stage-js 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/stage.d.ts +32 -15
- package/dist/stage.js +196 -128
- package/dist/stage.js.map +1 -1
- package/dist/stage.umd.cjs +198 -130
- package/dist/stage.umd.cjs.map +1 -1
- package/package.json +13 -10
- package/src/core/component.ts +52 -10
- package/src/core/debug.ts +33 -0
- package/src/core/easing.ts +1 -1
- package/src/core/pin.ts +60 -10
- package/src/core/pointer.ts +6 -0
- package/src/core/root.ts +88 -114
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stage-js",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "2D HTML5 Rendering and Layout",
|
|
5
5
|
"homepage": "http://piqnt.com/stage.js/",
|
|
6
6
|
"author": "Ali Shakiba",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"mobile"
|
|
23
23
|
],
|
|
24
24
|
"engines": {
|
|
25
|
-
"node": ">=
|
|
25
|
+
"node": ">=24.0"
|
|
26
26
|
},
|
|
27
27
|
"type": "module",
|
|
28
28
|
"module": "./dist/stage.js",
|
|
@@ -55,7 +55,10 @@
|
|
|
55
55
|
"change": "changeset",
|
|
56
56
|
"version": "changeset version",
|
|
57
57
|
"publish": "changeset publish",
|
|
58
|
-
"typedoc": "typedoc --options typedoc.json && mv ./docs/pages/api/README.md ./docs/pages/api/index.md
|
|
58
|
+
"typedoc": "typedoc --options typedoc.json && mv ./docs/pages/api/README.md ./docs/pages/api/index.md",
|
|
59
|
+
"docs:dev": "vitepress dev docs",
|
|
60
|
+
"docs:build": "vitepress build docs",
|
|
61
|
+
"docs:preview": "vitepress preview docs"
|
|
59
62
|
},
|
|
60
63
|
"devDependencies": {
|
|
61
64
|
"@changesets/cli": "^2.27.11",
|
|
@@ -68,16 +71,16 @@
|
|
|
68
71
|
"expect.js": "^0.3.1",
|
|
69
72
|
"mocha": "^6.2.3",
|
|
70
73
|
"prettier": "^3.2.5",
|
|
71
|
-
"replace-in-files-cli": "^3.0.0",
|
|
72
74
|
"rollup-plugin-license": "^3.3.1",
|
|
73
75
|
"sandboxed-module": "^2.0.0",
|
|
74
76
|
"sinon": "^9.0.2",
|
|
75
|
-
"typedoc": "^0.
|
|
76
|
-
"typedoc-plugin-markdown": "^4.
|
|
77
|
+
"typedoc": "^0.28.18",
|
|
78
|
+
"typedoc-plugin-markdown": "^4.11.0",
|
|
77
79
|
"typescript": "^5.6.3",
|
|
78
|
-
"
|
|
79
|
-
"vite
|
|
80
|
-
"vite-plugin-pages": "^0.
|
|
81
|
-
"vite-plugin-typescript": "^1.0.4"
|
|
80
|
+
"unplugin-dts-bundle-generator": "^3.4.1",
|
|
81
|
+
"vite": "^6.4.1",
|
|
82
|
+
"vite-plugin-pages": "^0.33.3",
|
|
83
|
+
"vite-plugin-typescript": "^1.0.4",
|
|
84
|
+
"vitepress": "^2.0.0-alpha.16"
|
|
82
85
|
}
|
|
83
86
|
}
|
package/src/core/component.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import stats from "../common/stats";
|
|
2
|
-
import { Vec2Value } from "../common/matrix";
|
|
2
|
+
import { Matrix, Vec2Value } from "../common/matrix";
|
|
3
3
|
import { uid } from "../common/uid";
|
|
4
4
|
import { getDevicePixelRatio } from "../common/browser";
|
|
5
5
|
|
|
6
6
|
import { Pin, FitMode, SetPinType, SetPinKeys, GetPinKeys } from "./pin";
|
|
7
7
|
import { Transition, TransitionOptions } from "./transition";
|
|
8
|
+
import { renderAxis, renderPoint } from "./debug";
|
|
8
9
|
|
|
9
10
|
// todo: why there are two iids (other in pin)?
|
|
10
11
|
/** @internal */
|
|
@@ -130,6 +131,12 @@ export class Component {
|
|
|
130
131
|
/** @internal */ _mo_seqAlign: number;
|
|
131
132
|
/** @internal */ _mo_box: number;
|
|
132
133
|
|
|
134
|
+
/** @hidden Set to true to enable debug rendering */
|
|
135
|
+
_debug: boolean;
|
|
136
|
+
|
|
137
|
+
/** @internal */
|
|
138
|
+
_xf: Matrix;
|
|
139
|
+
|
|
133
140
|
constructor() {
|
|
134
141
|
stats.create++;
|
|
135
142
|
if (this instanceof Component) {
|
|
@@ -144,25 +151,30 @@ export class Component {
|
|
|
144
151
|
return this._pin.absoluteMatrix();
|
|
145
152
|
}
|
|
146
153
|
|
|
147
|
-
/** @hidden @deprecated */
|
|
154
|
+
/** @hidden @deprecated Use getLogicalPixelRatio */
|
|
148
155
|
getPixelRatio() {
|
|
149
156
|
// todo: remove this function
|
|
150
|
-
|
|
151
|
-
const pixelRatio = !m ? 1 : Math.max(Math.abs(m.a), Math.abs(m.b)) / getDevicePixelRatio();
|
|
152
|
-
return pixelRatio;
|
|
157
|
+
return this.getLogicalPixelRatio();
|
|
153
158
|
}
|
|
154
159
|
|
|
155
|
-
/**
|
|
160
|
+
/**
|
|
161
|
+
* @hidden
|
|
162
|
+
* Physical-pixel per unit of parent component.
|
|
163
|
+
* This is not accurate before first tick.
|
|
164
|
+
*/
|
|
156
165
|
getDevicePixelRatio() {
|
|
157
166
|
// todo: parent matrix is not available in the first call
|
|
158
167
|
const parentMatrix = this._parent?.matrix();
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
: Math.max(Math.abs(parentMatrix.a), Math.abs(parentMatrix.b));
|
|
168
|
+
if (!parentMatrix) return 1;
|
|
169
|
+
const pixelRatio = Math.max(Math.abs(parentMatrix.a), Math.abs(parentMatrix.b));
|
|
162
170
|
return pixelRatio;
|
|
163
171
|
}
|
|
164
172
|
|
|
165
|
-
/**
|
|
173
|
+
/**
|
|
174
|
+
* @hidden
|
|
175
|
+
* Logical-pixel per unit of parent component.
|
|
176
|
+
* This is not accurate before first tick.
|
|
177
|
+
*/
|
|
166
178
|
getLogicalPixelRatio() {
|
|
167
179
|
return this.getDevicePixelRatio() / getDevicePixelRatio();
|
|
168
180
|
}
|
|
@@ -656,6 +668,9 @@ export class Component {
|
|
|
656
668
|
stats.component++;
|
|
657
669
|
|
|
658
670
|
const m = this.matrix();
|
|
671
|
+
|
|
672
|
+
this.renderDebug(context, m);
|
|
673
|
+
|
|
659
674
|
context.setTransform(m.a, m.b, m.c, m.d, m.e, m.f);
|
|
660
675
|
|
|
661
676
|
// move this elsewhere!
|
|
@@ -1199,6 +1214,33 @@ export class Component {
|
|
|
1199
1214
|
this._spacing = space;
|
|
1200
1215
|
return this;
|
|
1201
1216
|
}
|
|
1217
|
+
|
|
1218
|
+
renderDebug(ctx: CanvasRenderingContext2D, xf: Matrix) {
|
|
1219
|
+
if (!this._debug) return;
|
|
1220
|
+
const ppu = this.getLogicalPixelRatio();
|
|
1221
|
+
|
|
1222
|
+
ctx.lineWidth = 1 / ppu;
|
|
1223
|
+
ctx.lineCap = "round";
|
|
1224
|
+
ctx.lineJoin = "round";
|
|
1225
|
+
|
|
1226
|
+
renderAxis(ctx, 1);
|
|
1227
|
+
|
|
1228
|
+
const pin = this._pin;
|
|
1229
|
+
if (pin._pivoted) {
|
|
1230
|
+
ctx.strokeStyle = "orange";
|
|
1231
|
+
renderPoint(ctx, pin._pivotX * pin._width, pin._pivotY * pin._height);
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
if (pin._aligned) {
|
|
1235
|
+
ctx.strokeStyle = "green";
|
|
1236
|
+
renderPoint(ctx, pin._alignX * pin._width, pin._alignY * pin._height);
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
if (pin._handled) {
|
|
1240
|
+
ctx.strokeStyle = "yellow";
|
|
1241
|
+
renderPoint(ctx, pin._handleX * pin._width, pin._handleY * pin._height);
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1202
1244
|
}
|
|
1203
1245
|
|
|
1204
1246
|
/** @hidden @deprecated Node is renamed to Component */
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export function renderAxis(this: unknown, ctx: CanvasRenderingContext2D, size: number) {
|
|
2
|
+
ctx.strokeStyle = "rgba(93, 173, 226)";
|
|
3
|
+
ctx.beginPath();
|
|
4
|
+
ctx.moveTo(0, 0);
|
|
5
|
+
ctx.lineTo(0, 0.8 * size);
|
|
6
|
+
ctx.lineTo(-0.2 * size, 0.8 * size);
|
|
7
|
+
ctx.lineTo(0, size);
|
|
8
|
+
ctx.lineTo(+0.2 * size, 0.8 * size);
|
|
9
|
+
ctx.lineTo(0, 0.8 * size);
|
|
10
|
+
ctx.stroke();
|
|
11
|
+
|
|
12
|
+
ctx.strokeStyle = "rgba(236, 112, 99)";
|
|
13
|
+
ctx.beginPath();
|
|
14
|
+
ctx.moveTo(0, 0);
|
|
15
|
+
ctx.lineTo(0.8 * size, 0);
|
|
16
|
+
ctx.lineTo(0.8 * size, -0.2 * size);
|
|
17
|
+
ctx.lineTo(size, 0);
|
|
18
|
+
ctx.lineTo(0.8 * size, +0.2 * size);
|
|
19
|
+
ctx.lineTo(0.8 * size, 0);
|
|
20
|
+
ctx.stroke();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function renderPoint(this: unknown, ctx: CanvasRenderingContext2D, px: number, py: number) {
|
|
24
|
+
ctx.beginPath();
|
|
25
|
+
ctx.beginPath();
|
|
26
|
+
ctx.moveTo(px - 0.2, py - 0.2);
|
|
27
|
+
ctx.lineTo(px + 0.2, py + 0.2);
|
|
28
|
+
ctx.stroke();
|
|
29
|
+
ctx.beginPath();
|
|
30
|
+
ctx.moveTo(px - 0.2, py + 0.2);
|
|
31
|
+
ctx.lineTo(px + 0.2, py - 0.2);
|
|
32
|
+
ctx.stroke();
|
|
33
|
+
}
|
package/src/core/easing.ts
CHANGED
|
@@ -78,7 +78,7 @@ const initEasing = (query: string, params?: number[]): EasingFunction => {
|
|
|
78
78
|
: 7.5625 * (t -= 2.625 / 2.75) * t + 0.984375;
|
|
79
79
|
|
|
80
80
|
/** @internal */ const poly =
|
|
81
|
-
(e: number): EasingFunction =>
|
|
81
|
+
(e: number = 3): EasingFunction =>
|
|
82
82
|
(t: number) =>
|
|
83
83
|
Math.pow(t, e);
|
|
84
84
|
|
package/src/core/pin.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Matrix
|
|
1
|
+
import { Matrix } from "../common/matrix";
|
|
2
2
|
import { uid } from "../common/uid";
|
|
3
3
|
|
|
4
4
|
import type { Component } from "./component";
|
|
@@ -35,6 +35,10 @@ export function isValidFitMode(value: string) {
|
|
|
35
35
|
|
|
36
36
|
/** @internal */ let iid = 0;
|
|
37
37
|
|
|
38
|
+
/** @internal */ export function getIID() {
|
|
39
|
+
return iid++;
|
|
40
|
+
}
|
|
41
|
+
|
|
38
42
|
export class Pin {
|
|
39
43
|
/** @internal */ uid = "pin:" + uid();
|
|
40
44
|
|
|
@@ -194,6 +198,7 @@ export class Pin {
|
|
|
194
198
|
abs.reset(this.relativeMatrix());
|
|
195
199
|
|
|
196
200
|
this._parent && abs.concat(this._parent._absoluteMatrix);
|
|
201
|
+
this._owner._xf && abs.concat(this._owner._xf);
|
|
197
202
|
|
|
198
203
|
this._ts_matrix = ++iid;
|
|
199
204
|
|
|
@@ -344,6 +349,51 @@ export class Pin {
|
|
|
344
349
|
}
|
|
345
350
|
}
|
|
346
351
|
|
|
352
|
+
/** @internal */
|
|
353
|
+
const fitted = {};
|
|
354
|
+
|
|
355
|
+
/** @internal */
|
|
356
|
+
export function fit(
|
|
357
|
+
this: unknown,
|
|
358
|
+
inWidth: number,
|
|
359
|
+
inHeight: number,
|
|
360
|
+
outWidth: number | null,
|
|
361
|
+
outHeight: number | null,
|
|
362
|
+
mode?: FitMode,
|
|
363
|
+
) {
|
|
364
|
+
if (mode === "contain") mode = "in-pad";
|
|
365
|
+
if (mode === "cover") mode = "out-crop";
|
|
366
|
+
|
|
367
|
+
let scaleX: number;
|
|
368
|
+
let scaleY: number;
|
|
369
|
+
|
|
370
|
+
let width: number;
|
|
371
|
+
let height: number;
|
|
372
|
+
|
|
373
|
+
if (typeof outWidth === "number") {
|
|
374
|
+
scaleX = outWidth / inWidth;
|
|
375
|
+
width = inWidth;
|
|
376
|
+
}
|
|
377
|
+
if (typeof outHeight === "number") {
|
|
378
|
+
scaleY = outHeight / inHeight;
|
|
379
|
+
height = inHeight;
|
|
380
|
+
}
|
|
381
|
+
if (typeof outWidth === "number" && typeof outHeight === "number" && typeof mode === "string") {
|
|
382
|
+
if (mode === "fill") {
|
|
383
|
+
} else if (mode === "out" || mode === "out-crop") {
|
|
384
|
+
scaleX = scaleY = Math.max(scaleX, scaleY);
|
|
385
|
+
} else if (mode === "in" || mode === "in-pad") {
|
|
386
|
+
scaleX = scaleY = Math.min(scaleX, scaleY);
|
|
387
|
+
}
|
|
388
|
+
if (mode === "out-crop" || mode === "in-pad") {
|
|
389
|
+
width = outWidth / scaleX;
|
|
390
|
+
height = outHeight / scaleY;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
return { scaleX, scaleY, width, height };
|
|
395
|
+
}
|
|
396
|
+
|
|
347
397
|
/** @internal */ const getters = {
|
|
348
398
|
alpha: function (pin: Pin) {
|
|
349
399
|
return pin._alpha;
|
|
@@ -652,11 +702,11 @@ export interface SetPinType {
|
|
|
652
702
|
|
|
653
703
|
rotation?: number;
|
|
654
704
|
|
|
655
|
-
/** Center of scale/skew/rotate */
|
|
705
|
+
/** Center of scale/skew/rotate, 0 is start, 1 is end */
|
|
656
706
|
pivot?: number;
|
|
657
|
-
/** Center of scale/skew/rotate */
|
|
707
|
+
/** Center of scale/skew/rotate, 0 is start, 1 is end */
|
|
658
708
|
pivotX?: number;
|
|
659
|
-
/** Center of scale/skew/rotate */
|
|
709
|
+
/** Center of scale/skew/rotate, 0 is start, 1 is end */
|
|
660
710
|
pivotY?: number;
|
|
661
711
|
|
|
662
712
|
/** Offset in parent coordination */
|
|
@@ -666,18 +716,18 @@ export interface SetPinType {
|
|
|
666
716
|
/** Offset in parent coordination */
|
|
667
717
|
offsetY?: number;
|
|
668
718
|
|
|
669
|
-
/** A point on parent where this component is offset from, 0 is
|
|
719
|
+
/** A point on parent where this component is offset from, 0 is start, 1 is end */
|
|
670
720
|
align?: number;
|
|
671
|
-
/** A point on parent where this component is offset from, 0 is
|
|
721
|
+
/** A point on parent where this component is offset from, 0 is start, 1 is end */
|
|
672
722
|
alignX?: number;
|
|
673
|
-
/** A point on parent where this component is offset from, 0 is
|
|
723
|
+
/** A point on parent where this component is offset from, 0 is start, 1 is end */
|
|
674
724
|
alignY?: number;
|
|
675
725
|
|
|
676
|
-
/** A point on this component which is offset from parent, 0 is
|
|
726
|
+
/** A point on this component which is offset from parent, 0 is start, 1 is end */
|
|
677
727
|
handle?: number;
|
|
678
|
-
/** A point on this component which is offset from parent, 0 is
|
|
728
|
+
/** A point on this component which is offset from parent, 0 is start, 1 is end */
|
|
679
729
|
handleX?: number;
|
|
680
|
-
/** A point on this component which is offset from parent, 0 is
|
|
730
|
+
/** A point on this component which is offset from parent, 0 is start, 1 is end */
|
|
681
731
|
handleY?: number;
|
|
682
732
|
|
|
683
733
|
/** @hidden @deprecated Use component.fit() */
|
package/src/core/pointer.ts
CHANGED
|
@@ -18,6 +18,12 @@ export const POINTER_START = "touchstart mousedown";
|
|
|
18
18
|
/** @hidden @deprecated */
|
|
19
19
|
export const POINTER_END = "touchend mouseup";
|
|
20
20
|
|
|
21
|
+
export interface PointerEvent {
|
|
22
|
+
x: number;
|
|
23
|
+
y: number;
|
|
24
|
+
raw: UIEvent;
|
|
25
|
+
}
|
|
26
|
+
|
|
21
27
|
class EventPoint {
|
|
22
28
|
x: number;
|
|
23
29
|
y: number;
|
package/src/core/root.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import stats from "../common/stats";
|
|
2
2
|
import { Matrix } from "../common/matrix";
|
|
3
3
|
|
|
4
|
+
import { renderAxis } from "./debug";
|
|
4
5
|
import { Component } from "./component";
|
|
5
6
|
import { Pointer } from "./pointer";
|
|
6
|
-
import { FitMode, isValidFitMode } from "./pin";
|
|
7
|
+
import { fit, FitMode, getIID, isValidFitMode } from "./pin";
|
|
7
8
|
|
|
8
9
|
/** @internal */ const ROOTS: Root[] = [];
|
|
9
10
|
|
|
@@ -59,11 +60,11 @@ export class Root extends Component {
|
|
|
59
60
|
dom: HTMLCanvasElement | null = null;
|
|
60
61
|
context: CanvasRenderingContext2D | null = null;
|
|
61
62
|
|
|
62
|
-
/** @internal */
|
|
63
|
-
/** @internal */
|
|
63
|
+
/** @internal */ clientWidth = -1;
|
|
64
|
+
/** @internal */ clientHeight = -1;
|
|
64
65
|
/** @internal */ pixelRatio = 1;
|
|
65
|
-
/** @internal */
|
|
66
|
-
/** @internal */
|
|
66
|
+
/** @internal */ canvasWidth = 0;
|
|
67
|
+
/** @internal */ canvasHeight = 0;
|
|
67
68
|
|
|
68
69
|
mounted = false;
|
|
69
70
|
paused = false;
|
|
@@ -76,7 +77,6 @@ export class Root extends Component {
|
|
|
76
77
|
|
|
77
78
|
/** @internal */ _viewport: Viewport;
|
|
78
79
|
/** @internal */ _viewbox: Viewbox;
|
|
79
|
-
/** @internal */ _camera: Matrix;
|
|
80
80
|
|
|
81
81
|
constructor() {
|
|
82
82
|
super();
|
|
@@ -168,6 +168,62 @@ export class Root extends Component {
|
|
|
168
168
|
/** @internal */ _lastFrameTime = 0;
|
|
169
169
|
/** @internal */ _mo_touch: number | null = null; // monitor touch
|
|
170
170
|
|
|
171
|
+
resizeCanvas() {
|
|
172
|
+
const newClientWidth = this.canvas.clientWidth;
|
|
173
|
+
const newClientHeight = this.canvas.clientHeight;
|
|
174
|
+
|
|
175
|
+
// canvas display size is not changed
|
|
176
|
+
if (this.clientWidth === newClientWidth && this.clientHeight === newClientHeight) return;
|
|
177
|
+
|
|
178
|
+
this.clientWidth = newClientWidth;
|
|
179
|
+
this.clientHeight = newClientHeight;
|
|
180
|
+
|
|
181
|
+
const notStyled =
|
|
182
|
+
this.canvas.clientWidth === this.canvas.width &&
|
|
183
|
+
this.canvas.clientHeight === this.canvas.height;
|
|
184
|
+
|
|
185
|
+
let pixelRatio: number;
|
|
186
|
+
|
|
187
|
+
if (notStyled) {
|
|
188
|
+
// If element is not styled, changing canvas rendering size will change its display size,
|
|
189
|
+
// which creates a loop of resizing. So we ignore pixel ratio and keep current rendering size.
|
|
190
|
+
pixelRatio = 1;
|
|
191
|
+
this.canvasWidth = this.canvas.width;
|
|
192
|
+
this.canvasHeight = this.canvas.height;
|
|
193
|
+
} else {
|
|
194
|
+
pixelRatio = this.pixelRatio;
|
|
195
|
+
this.canvasWidth = this.clientWidth * pixelRatio;
|
|
196
|
+
this.canvasHeight = this.clientHeight * pixelRatio;
|
|
197
|
+
|
|
198
|
+
if (this.canvas.width !== this.canvasWidth || this.canvas.height !== this.canvasHeight) {
|
|
199
|
+
// canvas rendering size is changed
|
|
200
|
+
this.canvas.width = this.canvasWidth;
|
|
201
|
+
this.canvas.height = this.canvasHeight;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
console.debug &&
|
|
206
|
+
console.debug(
|
|
207
|
+
"Resize: [" +
|
|
208
|
+
this.canvasWidth +
|
|
209
|
+
", " +
|
|
210
|
+
this.canvasHeight +
|
|
211
|
+
"] = " +
|
|
212
|
+
pixelRatio +
|
|
213
|
+
" x [" +
|
|
214
|
+
this.clientWidth +
|
|
215
|
+
", " +
|
|
216
|
+
this.clientHeight +
|
|
217
|
+
"]",
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
this.viewport({
|
|
221
|
+
width: this.canvasWidth,
|
|
222
|
+
height: this.canvasHeight,
|
|
223
|
+
ratio: pixelRatio,
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
|
|
171
227
|
/** @internal */
|
|
172
228
|
onFrame = (now: number) => {
|
|
173
229
|
this.frameRequested = false;
|
|
@@ -177,45 +233,7 @@ export class Root extends Component {
|
|
|
177
233
|
}
|
|
178
234
|
|
|
179
235
|
this.requestFrame();
|
|
180
|
-
|
|
181
|
-
const newPixelWidth = this.canvas.clientWidth;
|
|
182
|
-
const newPixelHeight = this.canvas.clientHeight;
|
|
183
|
-
|
|
184
|
-
if (this.pixelWidth !== newPixelWidth || this.pixelHeight !== newPixelHeight) {
|
|
185
|
-
// viewport pixel size is not the same as last time
|
|
186
|
-
this.pixelWidth = newPixelWidth;
|
|
187
|
-
this.pixelHeight = newPixelHeight;
|
|
188
|
-
|
|
189
|
-
this.drawingWidth = newPixelWidth * this.pixelRatio;
|
|
190
|
-
this.drawingHeight = newPixelHeight * this.pixelRatio;
|
|
191
|
-
|
|
192
|
-
if (this.canvas.width !== this.drawingWidth || this.canvas.height !== this.drawingHeight) {
|
|
193
|
-
// canvas size doesn't math
|
|
194
|
-
this.canvas.width = this.drawingWidth;
|
|
195
|
-
this.canvas.height = this.drawingHeight;
|
|
196
|
-
|
|
197
|
-
console.debug &&
|
|
198
|
-
console.debug(
|
|
199
|
-
"Resize: [" +
|
|
200
|
-
this.drawingWidth +
|
|
201
|
-
", " +
|
|
202
|
-
this.drawingHeight +
|
|
203
|
-
"] = " +
|
|
204
|
-
this.pixelRatio +
|
|
205
|
-
" x [" +
|
|
206
|
-
this.pixelWidth +
|
|
207
|
-
", " +
|
|
208
|
-
this.pixelHeight +
|
|
209
|
-
"]",
|
|
210
|
-
);
|
|
211
|
-
|
|
212
|
-
this.viewport({
|
|
213
|
-
width: this.drawingWidth,
|
|
214
|
-
height: this.drawingHeight,
|
|
215
|
-
ratio: this.pixelRatio,
|
|
216
|
-
});
|
|
217
|
-
}
|
|
218
|
-
}
|
|
236
|
+
this.resizeCanvas();
|
|
219
237
|
|
|
220
238
|
const last = this._lastFrameTime || now;
|
|
221
239
|
const elapsed = now - last;
|
|
@@ -234,12 +252,9 @@ export class Root extends Component {
|
|
|
234
252
|
this._mo_touch = this._ts_touch;
|
|
235
253
|
this.sleep = false;
|
|
236
254
|
|
|
237
|
-
if (this.
|
|
255
|
+
if (this.canvasWidth > 0 && this.canvasHeight > 0) {
|
|
238
256
|
this.context.setTransform(1, 0, 0, 1, 0, 0);
|
|
239
|
-
this.context.clearRect(0, 0, this.
|
|
240
|
-
if (this.debugDrawAxis > 0) {
|
|
241
|
-
this.renderDebug(this.context);
|
|
242
|
-
}
|
|
257
|
+
this.context.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
|
|
243
258
|
this.render(this.context);
|
|
244
259
|
}
|
|
245
260
|
} else if (tickRequest) {
|
|
@@ -253,40 +268,11 @@ export class Root extends Component {
|
|
|
253
268
|
stats.fps = elapsed ? 1000 / elapsed : 0;
|
|
254
269
|
};
|
|
255
270
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
const m = this.matrix();
|
|
262
|
-
context.setTransform(m.a, m.b, m.c, m.d, m.e, m.f);
|
|
263
|
-
const lineWidth = 3 / m.a;
|
|
264
|
-
|
|
265
|
-
context.beginPath();
|
|
266
|
-
context.moveTo(0, 0);
|
|
267
|
-
context.lineTo(0, 0.8 * size);
|
|
268
|
-
context.lineTo(-0.2 * size, 0.8 * size);
|
|
269
|
-
context.lineTo(0, size);
|
|
270
|
-
context.lineTo(+0.2 * size, 0.8 * size);
|
|
271
|
-
context.lineTo(0, 0.8 * size);
|
|
272
|
-
context.strokeStyle = "rgba(93, 173, 226)";
|
|
273
|
-
context.lineJoin = "round";
|
|
274
|
-
context.lineCap = "round";
|
|
275
|
-
context.lineWidth = lineWidth;
|
|
276
|
-
context.stroke();
|
|
277
|
-
|
|
278
|
-
context.beginPath();
|
|
279
|
-
context.moveTo(0, 0);
|
|
280
|
-
context.lineTo(0.8 * size, 0);
|
|
281
|
-
context.lineTo(0.8 * size, -0.2 * size);
|
|
282
|
-
context.lineTo(size, 0);
|
|
283
|
-
context.lineTo(0.8 * size, +0.2 * size);
|
|
284
|
-
context.lineTo(0.8 * size, 0);
|
|
285
|
-
context.strokeStyle = "rgba(236, 112, 99)";
|
|
286
|
-
context.lineJoin = "round";
|
|
287
|
-
context.lineCap = "round";
|
|
288
|
-
context.lineWidth = lineWidth;
|
|
289
|
-
context.stroke();
|
|
271
|
+
renderDebug(ctx: CanvasRenderingContext2D, m: Matrix) {
|
|
272
|
+
if (!this._debug) return;
|
|
273
|
+
ctx.setTransform(m.a, m.b, m.c, m.d, m.e, m.f);
|
|
274
|
+
ctx.lineWidth = 3 / m.a;
|
|
275
|
+
renderAxis(ctx, 10);
|
|
290
276
|
}
|
|
291
277
|
|
|
292
278
|
resume() {
|
|
@@ -362,7 +348,7 @@ export class Root extends Component {
|
|
|
362
348
|
height: height,
|
|
363
349
|
ratio: typeof ratio === "number" ? ratio : 1,
|
|
364
350
|
};
|
|
365
|
-
this.
|
|
351
|
+
this.rescale();
|
|
366
352
|
const data = Object.assign({}, this._viewport);
|
|
367
353
|
this.visit({
|
|
368
354
|
start: function (component) {
|
|
@@ -384,7 +370,6 @@ export class Root extends Component {
|
|
|
384
370
|
viewbox(width?: number, height?: number, mode?: FitMode): this;
|
|
385
371
|
viewbox(width?: number | Viewbox, height?: number, mode?: FitMode): this {
|
|
386
372
|
// TODO: static/fixed viewbox
|
|
387
|
-
// TODO: use css object-fit values
|
|
388
373
|
if (typeof width === "number" && typeof height === "number") {
|
|
389
374
|
this._viewbox = {
|
|
390
375
|
width,
|
|
@@ -402,9 +387,11 @@ export class Root extends Component {
|
|
|
402
387
|
return this;
|
|
403
388
|
}
|
|
404
389
|
|
|
390
|
+
/** @hidden */
|
|
405
391
|
camera(matrix: Matrix) {
|
|
406
|
-
this.
|
|
407
|
-
this.
|
|
392
|
+
this._xf = matrix.clone();
|
|
393
|
+
this._pin._ts_transform = getIID();
|
|
394
|
+
this.touch();
|
|
408
395
|
return this;
|
|
409
396
|
}
|
|
410
397
|
|
|
@@ -412,36 +399,23 @@ export class Root extends Component {
|
|
|
412
399
|
rescale() {
|
|
413
400
|
const viewbox = this._viewbox;
|
|
414
401
|
const viewport = this._viewport;
|
|
415
|
-
const camera = this._camera;
|
|
416
402
|
if (viewport && viewbox) {
|
|
417
|
-
const viewportWidth = viewport.width;
|
|
418
|
-
const viewportHeight = viewport.height;
|
|
419
403
|
const viewboxMode = isValidFitMode(viewbox.mode) ? viewbox.mode : "in-pad";
|
|
420
|
-
const
|
|
421
|
-
|
|
422
|
-
|
|
404
|
+
const fitted = fit(
|
|
405
|
+
viewbox.width,
|
|
406
|
+
viewbox.height,
|
|
407
|
+
viewport.width,
|
|
408
|
+
viewport.height,
|
|
409
|
+
viewboxMode,
|
|
410
|
+
);
|
|
423
411
|
this.pin({
|
|
424
|
-
width:
|
|
425
|
-
height:
|
|
412
|
+
width: fitted.width,
|
|
413
|
+
height: fitted.height,
|
|
414
|
+
scaleX: fitted.scaleX,
|
|
415
|
+
scaleY: fitted.scaleY,
|
|
416
|
+
offsetX: -(viewbox.x || 0) * fitted.scaleX,
|
|
417
|
+
offsetY: -(viewbox.y || 0) * fitted.scaleY,
|
|
426
418
|
});
|
|
427
|
-
this.fit(viewportWidth, viewportHeight, viewboxMode);
|
|
428
|
-
|
|
429
|
-
const viewboxX = viewbox.x || 0;
|
|
430
|
-
const viewboxY = viewbox.y || 0;
|
|
431
|
-
|
|
432
|
-
const cameraZoomX = camera?.a || 1;
|
|
433
|
-
const cameraZoomY = camera?.d || 1;
|
|
434
|
-
const cameraX = camera?.e || 0;
|
|
435
|
-
const cameraY = camera?.f || 0;
|
|
436
|
-
|
|
437
|
-
const scaleX = this.pin("scaleX");
|
|
438
|
-
const scaleY = this.pin("scaleY");
|
|
439
|
-
|
|
440
|
-
this.pin("scaleX", scaleX * cameraZoomX);
|
|
441
|
-
this.pin("scaleY", scaleY * cameraZoomY);
|
|
442
|
-
|
|
443
|
-
this.pin("offsetX", cameraX - viewboxX * scaleX * cameraZoomX);
|
|
444
|
-
this.pin("offsetY", cameraY - viewboxY * scaleY * cameraZoomY);
|
|
445
419
|
} else if (viewport) {
|
|
446
420
|
this.pin({
|
|
447
421
|
width: viewport.width,
|