Skip to content

Commit

Permalink
Bump up to v3.0.0
Browse files Browse the repository at this point in the history
Wip
  • Loading branch information
klawr authored Jan 15, 2021
2 parents 046a750 + 5eda6d0 commit 01447ce
Show file tree
Hide file tree
Showing 135 changed files with 12,955 additions and 3,069 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.vscode
node_modules
docs/pages.json
1 change: 0 additions & 1 deletion .vscode/settings.json

This file was deleted.

21 changes: 13 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ So the API is minimal and easy to understand. The library is tiny, fast and rend
## Main features

* Fast and lightweight graphics command queue builder.
* Adressing HTML canvas 2D context as the default renderer.
* Addressing HTML canvas 2D context as the default renderer.
* Generating SVG output using an [addon library](https://github.com/goessner/g2-svg).
* Method chaining.
* Support of cartesian coordinates.
Expand Down Expand Up @@ -55,22 +55,27 @@ See the [API Reference for g2](docs/api/g2.core.md) for details.

Also see the [API Reference for g2.ext](docs/api/g2.ext.md) and the [API Reference for g2.mec](docs/api/g2.mec.md).

Also available under
- [https://goessner.github.io/g2/api/g2.core](https://goessner.github.io/g2/api/g2.core)
- [https://goessner.github.io/g2/api/g2.ext](https://goessner.github.io/g2/api/g2.ext)
- [https://goessner.github.io/g2/api/g2.mec](https://goessner.github.io/g2/api/g2.mec)


## Cheat Sheet
Check out the single page [Cheat Sheet](docs/api/sheet.pdf).

Also available under [https://goessner.github.io/g2/api/sheet.pdf](https://goessner.github.io/g2/api/sheet.pdf)

## GitCDN
Use the link [https://cdn.jsdelivr.net/gh/goessner/[email protected]/src/g2.js](https://cdn.jsdelivr.net/gh/goessner/[email protected]/src/g2.js)
for getting the current stable commit as a raw file.
Use the link [https://cdn.jsdelivr.net/gh/goessner/g2/dist/g2.js](https://cdn.jsdelivr.net/gh/goessner/g2/dist/g2.js) for getting the latest commit as a raw file.

In HTML use ...
```html
<script src="https://cdn.jsdelivr.net/gh/goessner/g2@v2.5/src/g2.js"></script>
<script src="https://cdn.jsdelivr.net/gh/goessner/g2/dist/g2.js"></script>
```

### Tests
Tests are found on the [Github Page](https://goessner.github.io/g2/tests.html)

## Cheat Sheet
Check out the single page [Cheat Sheet](docs/api/cheatsheet.pdf).


# License
g<sup>2</sup> is licensed under the terms of the MIT License.
214 changes: 214 additions & 0 deletions bin/canvasInteractor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
/**
* canvasInteractor.js (c) 2018 Stefan Goessner
* @file interaction manager for html `canvas`.
* @author Stefan Goessner
* @license MIT License
*/
/* jshint -W014 */
// Managing multiple canvases per static interactor as singleton ...
// .. using a single requestAnimationFrame loop !
const canvasInteractor = {
create() {
const o = Object.create(this.prototype);
o.constructor.apply(o,arguments);
return o;
},
// global static tickTimer properties
fps: '?',
fpsOrigin: 0,
frames: 0,
rafid: 0,
instances: [],
// global static timer methods
tick(time) {
canvasInteractor.fpsCount(time);
for (const instance of canvasInteractor.instances) {
instance.notify('tick',{t:time,dt:(time-instance.t)/1000,dirty:instance.dirty}); // notify listeners ..
instance.t = time;
instance.dirty = false;
}
canvasInteractor.rafid = requestAnimationFrame(canvasInteractor.tick); // request next animation frame ...
},
add(instance) {
canvasInteractor.instances.push(instance);
if (canvasInteractor.instances.length === 1) // first instance added ...
canvasInteractor.tick(canvasInteractor.fpsOrigin = performance.now());
},
remove(instance) {
canvasInteractor.instances.splice(canvasInteractor.instances.indexOf(instance),1);
if (canvasInteractor.instances.length === 0) // last instance removed ...
cancelAnimationFrame(canvasInteractor.rafid);
},
fpsCount(time) {
if (time - canvasInteractor.fpsOrigin > 1000) { // one second interval reached ...
const fps = ~~(canvasInteractor.frames*1000/(time - canvasInteractor.fpsOrigin) + 0.5); // ~~ as Math.floor()
if (fps !== canvasInteractor.fps)
for (const instance of canvasInteractor.instances)
instance.notify('fps',canvasInteractor.fps=fps);
canvasInteractor.fpsOrigin = time;
canvasInteractor.frames = 0;
}
canvasInteractor.frames++;
},

prototype: {
constructor(ctx, {x,y,scl,cartesian}) {
// canvas interaction properties
this.ctx = ctx;
this.view = {x:x||0,y:y||0,scl:scl||1,cartesian:cartesian||false};
this.evt = {
type: false,
basetype: false,
x: -2, y:-2,
xi: 0, yi:0,
dx: 0, dy: 0,
btn: 0,
xbtn: 0, ybtn: 0,
xusr: -2, yusr: -2,
dxusr: 0, dyusr: 0,
delta: 0,
inside: false,
hit: false, // something hit by pointer ...
dscl: 1, // for zooming ...
eps: 5 // some pixel tolerance ...
};
this.dirty = true;
// event handler registration
const canvas = ctx.canvas;
canvas.addEventListener("pointermove", this, false);
canvas.addEventListener("pointerdown", this, false);
canvas.addEventListener("pointerup", this, false);
canvas.addEventListener("pointerenter", this, false);
canvas.addEventListener("pointerleave", this, false);
canvas.addEventListener("wheel", this, false);
canvas.addEventListener("pointercancel", this, false);
},
deinit() {
const canvas = this.ctx.canvas;

canvas.removeEventListener("pointermove", this, false);
canvas.removeEventListener("pointerdown", this, false);
canvas.removeEventListener("pointerup", this, false);
canvas.removeEventListener("pointerenter", this, false);
canvas.removeEventListener("pointerleave", this, false);
canvas.removeEventListener("wheel", this, false);
canvas.removeEventListener("pointercancel", this, false);

this.endTimer();

delete this.signals;
delete this.evt;
delete this.ctx;

return this;
},
// canvas interaction interface
handleEvent(e) {
if (e.type in this && (e.isPrimary || e.type === 'wheel')) { // can I handle events of type e.type .. ?
const bbox = e.target.getBoundingClientRect && e.target.getBoundingClientRect() || {left:0, top:0},
x = e.clientX - Math.floor(bbox.left),
y = e.clientY - Math.floor(bbox.top),
btn = e.buttons !== undefined ? e.buttons : e.button || e.which;

this.evt.type = e.type;
this.evt.basetype = e.type; // obsolete now ... ?
this.evt.xi = this.evt.x; // interim coordinates ...
this.evt.yi = this.evt.y; // ... of previous event.
this.evt.dx = this.evt.dy = 0;
this.evt.x = x;
this.evt.y = this.view.cartesian ? this.ctx.canvas.height - y : y;
this.evt.xusr = (this.evt.x - this.view.x)/this.view.scl;
this.evt.yusr = (this.evt.y - this.view.y)/this.view.scl;
this.evt.dxusr = this.evt.dyusr = 0;
this.evt.dbtn = btn - this.evt.btn;
this.evt.btn = btn;
this.evt.delta = Math.max(-1,Math.min(1,e.deltaY||e.wheelDelta)) || 0;

if (this.isDefaultPreventer(e.type))
e.preventDefault();
this[e.type](); // handle specific event .. !
this.notify(this.evt.type,this.evt); // .. tell the world .. !
}
else
console.log(e)
},
pointermove() {
this.evt.dx = this.evt.x - this.evt.xi;
this.evt.dy = this.evt.y - this.evt.yi;
if (this.evt.btn === 1) { // pointerdown state ...
this.evt.dxusr = this.evt.dx/this.view.scl; // correct usr coordinates ...
this.evt.dyusr = this.evt.dy/this.view.scl;
this.evt.xusr -= this.evt.dxusr; // correct usr coordinates ...
this.evt.yusr -= this.evt.dyusr;
if (!this.evt.hit) { // let outer app perform panning ...
this.evt.type = 'pan';
}
else
this.evt.type = 'drag';
}
// view, geometry or graphics might be modified ...
this.dirty = true;
},
pointerdown() {
this.evt.xbtn = this.evt.x;
this.evt.ybtn = this.evt.y;
},
pointerup() {
this.evt.type = this.evt.x===this.evt.xbtn && this.evt.y===this.evt.ybtn ? 'click' : 'pointerup';
this.evt.xbtn = this.evt.x;
this.evt.ybtn = this.evt.y;
},
pointerleave() {
this.evt.inside = false;
},
pointerenter() {
this.evt.inside = true;
},
wheel() {
this.evt.dscl = this.evt.delta>0?8/10:10/8;
this.evt.eps /= this.evt.dscl;
this.dirty = true;
},
isDefaultPreventer(type) {
return ['pointermove','pointerdown','pointerup','wheel'].includes(type);
},
pntToUsr: function(p) {
let vw = this.view;
p.x = (p.x - vw.x)/vw.scl;
p.y = (p.y - vw.y)/vw.scl;
return p;
},
// tickTimer interface
startTimer() { // shouldn't there be a global startTimer method ?
canvasInteractor.add(this);
this.notify('timerStart',this); // notify potential listeners ..
return this;
},
endTimer() {
this.notify('timerEnd',this.t/1000); // notify potential listeners ..
canvasInteractor.remove(this);
return this;
},
// observable interface
notify(key,val) {
if (this.signals && this.signals[key])
for (let hdl of this.signals[key])
hdl(val);
return this;
},
on(key,handler) { // support array of keys as first argument.
if (Array.isArray(key))
for (let k of key)
this.on(k,handler);
else
((this.signals || (this.signals = {})) && this.signals[key] || (this.signals[key]=[])).push(handler);

return this;
},
remove(key,handler) {
const idx = (this.signals && this.signals[key]) ? this.signals[key].indexOf(handler) : -1;
if (idx >= 0)
this.signals[key].splice(idx,1);
}
}
};
35 changes: 35 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# CHANGELOG
## [2.6.0]() on May 2020

### `g2.core.js`
* additional support of `{p}` property as alternative to `{x,y}` properties for referencing shared points/vectors.
* unknown symbol name with `use` results in drawing unknown symbol instead of runtime error.
* `{ldoff}` as linedash offset style property for line dash animation added. `
* Implicite element selecting and dragging capability removed.
* Boolean `{draggable}` property added, for explicitly indicating draggable elements.
### `g2.ext.js`
* code cleanup.
* `label` element deprecated.
* `mark` element deprecated.
* `label` property for most element types introduced.
* Handle element `hdl` with default `{draggable:true}` property added.
* `nod, nodfix, nodflt, pol, gnd, vec, dim, adim, origin` elements moved/ported from `g2.mec.js`.
### `g2.io.js`
* works again.
### `g2.selector.js` / `canvasinteractor.js`
* `interactor.on('pan')`, `interactor.on('drag')` and `interactor.on('wheel')` handling is moved out of the library and is now in the responsibility of the application (s. `g2.drag.html`).
* `hdl` elements can be used elegantly to interactively modify geometry.

## [3.0.0]() on December 2020

### `g2.core.js`
* `g2.mixin` is replaced with `g2.mix`.

### `g2.ext.js`
* Symbols like `nod`, `origin` etc. are moved from `g2.mec` to `g2.ext`.
* Commands `vec`, `avec`, `dim`, `adim` are also moved.
* `label` is no command anymore, but a property on respective `g2` commands.
* `mark` is no command anymore, but a property on respective `g2` commands.

### `g2.chart.html.js`
* A new custom HTML element used for easy rendering of `g2.chart` commands.
Loading

0 comments on commit 01447ce

Please sign in to comment.