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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stage-js",
3
- "version": "1.0.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": ">=18.0"
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 && ./node_modules/.bin/replace-in-files ./docs/pages/api/* --string '.md' --replacement ''"
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.26.11",
76
- "typedoc-plugin-markdown": "^4.2.10",
77
+ "typedoc": "^0.28.18",
78
+ "typedoc-plugin-markdown": "^4.11.0",
77
79
  "typescript": "^5.6.3",
78
- "vite": "^5.4.11",
79
- "vite-plugin-dts-bundle-generator": "^2.0.5",
80
- "vite-plugin-pages": "^0.32.3",
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
  }
@@ -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
- const m = this._parent?.matrix();
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
- /** @hidden This is not accurate before first tick */
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
- const pixelRatio = !parentMatrix
160
- ? 1
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
- /** @hidden This is not accurate before first tick */
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
+ }
@@ -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, Vec2Value } from "../common/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 top/left, 1 is bottom/right */
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 top/left, 1 is bottom/right */
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 top/left, 1 is bottom/right */
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 top/left, 1 is bottom/right */
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 top/left, 1 is bottom/right */
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 top/left, 1 is bottom/right */
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() */
@@ -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 */ pixelWidth = -1;
63
- /** @internal */ pixelHeight = -1;
63
+ /** @internal */ clientWidth = -1;
64
+ /** @internal */ clientHeight = -1;
64
65
  /** @internal */ pixelRatio = 1;
65
- /** @internal */ drawingWidth = 0;
66
- /** @internal */ drawingHeight = 0;
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.drawingWidth > 0 && this.drawingHeight > 0) {
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.drawingWidth, this.drawingHeight);
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
- /** @hidden */
257
- debugDrawAxis = 0;
258
-
259
- private renderDebug(context: CanvasRenderingContext2D): void {
260
- const size = typeof this.debugDrawAxis === "number" ? this.debugDrawAxis : 10;
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.viewbox();
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._camera = matrix;
407
- this.rescale();
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 viewboxWidth = viewbox.width;
421
- const viewboxHeight = viewbox.height;
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: viewboxWidth,
425
- height: viewboxHeight,
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,