modern-canvas 0.8.4 → 0.8.6

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/index.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  import { defineProperty, EventEmitter, getDeclarations, parseColor, property, RawWeakMap as RawWeakMap$1, isGradient, isColorFillObject, clearUndef, idGenerator, normalizeFill, isNone, normalizeBackground, normalizeForeground, normalizeOutline, normalizeShadow, normalizeShape, getDefaultStyle, normalizeText, normalizeTextContent } from 'modern-idoc';
2
2
  import { extend } from 'colord';
3
3
  import namesPlugin from 'colord/plugins/names';
4
- import { Path2D, Path2DSet, svgToDom, svgToPath2DSet, Matrix3 as Matrix3$1 } from 'modern-path2d';
5
- import { Text } from 'modern-text';
4
+ import { Path2D, Path2DSet, svgToDom, svgToPath2DSet, Matrix3 as Matrix3$1, BoundingBox } from 'modern-path2d';
5
+ import { Text, Character } from 'modern-text';
6
6
 
7
7
  const customNodes = /* @__PURE__ */ new Map();
8
8
  function customNode(name, defaultProperties) {
@@ -5120,21 +5120,26 @@ class GradientTexture extends Texture2D {
5120
5120
  if (!ctx) {
5121
5121
  throw new Error("Failed to parse linear gradient, get canvas context is null.");
5122
5122
  }
5123
- let { angle = 0, stops } = linearGradient;
5124
- angle -= Math.PI / 2;
5125
- const halfWidth = width / 2;
5126
- const halfHeight = height / 2;
5127
- const length = Math.sqrt(width * width + height * height) / 2;
5128
- const x0 = halfWidth + length * Math.cos(angle + Math.PI);
5129
- const y0 = halfHeight + length * Math.sin(angle + Math.PI);
5130
- const x1 = halfWidth + length * Math.cos(angle);
5131
- const y1 = halfHeight + length * Math.sin(angle);
5123
+ const { angle = 0, stops } = linearGradient;
5124
+ const w = width;
5125
+ const h = height;
5126
+ const cx = w / 2;
5127
+ const cy = h / 2;
5128
+ const canAng = angle * Math.PI / 180;
5129
+ const hypt = cy / Math.cos(canAng);
5130
+ const fromTopRight = cx - Math.sqrt(hypt * hypt - cy * cy);
5131
+ const diag = Math.sin(canAng) * fromTopRight;
5132
+ const len = hypt + diag;
5133
+ const x0 = cx + Math.cos(-Math.PI / 2 + canAng) * len;
5134
+ const y0 = cy + Math.sin(-Math.PI / 2 + canAng) * len;
5135
+ const x1 = cx + Math.cos(Math.PI / 2 + canAng) * len;
5136
+ const y1 = cy + Math.sin(Math.PI / 2 + canAng) * len;
5132
5137
  const gradient = ctx.createLinearGradient(x0, y0, x1, y1);
5133
5138
  stops.forEach((stop) => {
5134
5139
  gradient.addColorStop(stop.offset, stop.color);
5135
5140
  });
5136
5141
  ctx.fillStyle = gradient;
5137
- ctx.fillRect(0, 0, canvas.width, canvas.height);
5142
+ ctx.fillRect(0, 0, w, h);
5138
5143
  const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
5139
5144
  return {
5140
5145
  width: imageData.width,
@@ -9351,21 +9356,21 @@ ZoomBlurEffect = __decorateClass$t([
9351
9356
  customNode("ZoomBlurEffect")
9352
9357
  ], ZoomBlurEffect);
9353
9358
 
9354
- function getDrawOptions(fill, size) {
9359
+ function getDrawOptions(fill, box) {
9355
9360
  let disableWrapMode = false;
9356
- const { width, height } = size;
9357
- const uvTransform = new Transform2D().scale(1 / width, 1 / height);
9361
+ const { left = 0, top = 0, width, height } = box;
9362
+ const uvTransform = new Transform2D().translate(-left, -top).scale(1 / width, 1 / height);
9358
9363
  if (fill.cropRect) {
9359
9364
  const {
9360
- left = 0,
9361
- top = 0,
9365
+ left: left2 = 0,
9366
+ top: top2 = 0,
9362
9367
  right = 0,
9363
9368
  bottom = 0
9364
9369
  } = fill.cropRect;
9365
9370
  uvTransform.scale(
9366
- Math.abs(1 - (left + right)),
9367
- Math.abs(1 - (top + bottom))
9368
- ).translate(left, top);
9371
+ Math.abs(1 - (left2 + right)),
9372
+ Math.abs(1 - (top2 + bottom))
9373
+ ).translate(left2, top2);
9369
9374
  disableWrapMode = true;
9370
9375
  }
9371
9376
  if (fill.tile) {
@@ -9380,11 +9385,16 @@ function getDrawOptions(fill, size) {
9380
9385
  uvTransform.translate(-translateX / width, -translateY / height).scale(1 / scaleX, 1 / scaleY);
9381
9386
  disableWrapMode = true;
9382
9387
  } else if (fill.stretchRect) {
9383
- const { left = 0, top = 0, right = 0, bottom = 0 } = fill.stretchRect;
9388
+ const {
9389
+ left: left2 = 0,
9390
+ top: top2 = 0,
9391
+ right = 0,
9392
+ bottom = 0
9393
+ } = fill.stretchRect;
9384
9394
  uvTransform.scale(
9385
- Math.abs(1 - (-left + -right)),
9386
- Math.abs(1 - (-top + -bottom))
9387
- ).translate(-left, -top);
9395
+ Math.abs(1 - (-left2 + -right)),
9396
+ Math.abs(1 - (-top2 + -bottom))
9397
+ ).translate(-left2, -top2);
9388
9398
  disableWrapMode = true;
9389
9399
  }
9390
9400
  return { disableWrapMode, uvTransform };
@@ -9460,7 +9470,10 @@ class BaseElement2DFill extends CoreObject {
9460
9470
  const ctx = this.parent.context;
9461
9471
  const { uvTransform, disableWrapMode } = getDrawOptions(
9462
9472
  this,
9463
- this.parent.size
9473
+ {
9474
+ width: this.parent.size.width,
9475
+ height: this.parent.size.height
9476
+ }
9464
9477
  );
9465
9478
  ctx.uvTransform = uvTransform;
9466
9479
  ctx.fillStyle = this._texture ?? this.color;
@@ -9595,7 +9608,10 @@ class BaseElement2DOutline extends BaseElement2DFill {
9595
9608
  const ctx = this.parent.context;
9596
9609
  const { uvTransform, disableWrapMode } = getDrawOptions(
9597
9610
  this,
9598
- this.parent.size
9611
+ {
9612
+ width: this.parent.size.width,
9613
+ height: this.parent.size.height
9614
+ }
9599
9615
  );
9600
9616
  ctx.lineWidth = this.width || 1;
9601
9617
  ctx.uvTransform = uvTransform;
@@ -9819,7 +9835,7 @@ class BaseElement2DText extends CoreObject {
9819
9835
  }
9820
9836
  base = new Text();
9821
9837
  measureResult;
9822
- _textures = [];
9838
+ _textureMap = /* @__PURE__ */ new Map();
9823
9839
  setProperties(properties) {
9824
9840
  return super.setProperties(
9825
9841
  isNone(properties) ? void 0 : normalizeText(properties)
@@ -9829,30 +9845,72 @@ class BaseElement2DText extends CoreObject {
9829
9845
  super._updateProperty(key, value, oldValue, declaration);
9830
9846
  switch (key) {
9831
9847
  case "enabled":
9832
- case "content":
9833
9848
  case "effects":
9834
9849
  case "measureDom":
9835
9850
  case "fonts":
9836
9851
  this.parent.requestRedraw();
9837
9852
  break;
9838
9853
  case "fill":
9839
- this._updateTexture(0, value);
9840
- break;
9841
9854
  case "outline":
9842
- this._updateTexture(1, value);
9855
+ case "content":
9856
+ this._updateTextureMap();
9843
9857
  break;
9844
9858
  }
9845
9859
  }
9846
- async _updateTexture(index, fill) {
9847
- this._textures[index] = await this._loadTexture(fill);
9860
+ _update() {
9861
+ this.base.style = {
9862
+ justifyContent: "center",
9863
+ alignItems: "center",
9864
+ textAlign: "center",
9865
+ ...this.parent.style.toJSON()
9866
+ };
9867
+ this.base.update();
9868
+ }
9869
+ _updateTextureMap() {
9870
+ this._update();
9871
+ this._textureMap.clear();
9872
+ const pGlyphBoxs = [];
9873
+ this.base.paragraphs.forEach((p, pIndex) => {
9874
+ const fGlyphBoxs = [];
9875
+ p.fragments.forEach((f, fIndex) => {
9876
+ if (f.characters.length) {
9877
+ const fGlyphBox = BoundingBox.from(
9878
+ ...f.characters.map((c) => c.compatibleGlyphBox)
9879
+ );
9880
+ this._updateTexture(`${pIndex}.${fIndex}.fill`, f.fill, fGlyphBox);
9881
+ this._updateTexture(`${pIndex}.${fIndex}.outline`, f.outline, fGlyphBox);
9882
+ fGlyphBoxs.push(fGlyphBox);
9883
+ }
9884
+ });
9885
+ if (fGlyphBoxs.length) {
9886
+ const pGlyphBox = BoundingBox.from(...fGlyphBoxs);
9887
+ this._updateTexture(`${pIndex}.fill`, p.fill, pGlyphBox);
9888
+ this._updateTexture(`${pIndex}.outline`, p.outline, pGlyphBox);
9889
+ pGlyphBoxs.push(pGlyphBox);
9890
+ }
9891
+ });
9892
+ if (pGlyphBoxs.length) {
9893
+ const glyphBox = BoundingBox.from(...pGlyphBoxs);
9894
+ this._updateTexture("fill", this.fill, glyphBox);
9895
+ this._updateTexture("outline", this.outline, glyphBox);
9896
+ }
9848
9897
  this.parent.requestRedraw();
9849
9898
  }
9850
- async _loadTexture(fill) {
9899
+ async _updateTexture(key, fill, box) {
9900
+ if (fill && Object.keys(fill).length > 0) {
9901
+ this._textureMap.set(key, {
9902
+ texture: await this._loadTexture(fill, box),
9903
+ box
9904
+ });
9905
+ this.parent.requestRedraw();
9906
+ }
9907
+ }
9908
+ async _loadTexture(fill, box) {
9851
9909
  if (fill.linearGradient || fill.radialGradient) {
9852
9910
  return new GradientTexture(
9853
9911
  fill.linearGradient ?? fill.radialGradient,
9854
- this.parent.size.width,
9855
- this.parent.size.height
9912
+ box.width,
9913
+ box.height
9856
9914
  );
9857
9915
  } else if (!isNone(fill.image)) {
9858
9916
  this.parent.tree?.log(`load image ${fill.image}`);
@@ -9871,7 +9929,6 @@ class BaseElement2DText extends CoreObject {
9871
9929
  textAlign: "center",
9872
9930
  ...this.parent.style.toJSON()
9873
9931
  };
9874
- this.base.requestUpdate();
9875
9932
  return this.base.measure();
9876
9933
  }
9877
9934
  updateMeasure() {
@@ -9885,57 +9942,76 @@ class BaseElement2DText extends CoreObject {
9885
9942
  }
9886
9943
  _getVertTransform() {
9887
9944
  const parent = this.parent;
9888
- if (parent.style.scaleX > 0 && parent.style.scaleY > 0) {
9945
+ if (parent.scale.x > 0 && parent.scale.y > 0) {
9889
9946
  return void 0;
9890
9947
  }
9891
- const scale = parent.style.scaleX * parent.style.scaleY;
9948
+ const scale = parent.scale.x * parent.scale.y;
9892
9949
  const origin = parent.getTransformOrigin();
9893
9950
  return new Transform2D().translate(-origin.x, -origin.y).scale(scale > 0 ? 1 : -1, 1).translate(origin.x, origin.y);
9894
9951
  }
9895
9952
  draw() {
9896
9953
  const ctx = this.parent.context;
9897
- this.base.update();
9954
+ this._update();
9898
9955
  this.base.pathSets.forEach((pathSet) => {
9899
9956
  pathSet.paths.forEach((path) => {
9900
- if (path.style.stroke && !isNone(path.style.stroke)) {
9901
- if (typeof path.style.stroke === "object") {
9902
- const outline = path.style.stroke;
9903
- if (outline.enabled !== false && (this._textures[0] || outline.color) && (outline.width === void 0 || outline.width)) {
9904
- const { uvTransform, disableWrapMode } = getDrawOptions(outline, this.parent.size);
9957
+ const meta = path.getMeta();
9958
+ if (meta instanceof Character) {
9959
+ const fIndex = meta.parent.index;
9960
+ const pIndex = meta.parent.parent.index;
9961
+ if (path.style.fill && !isNone(path.style.fill)) {
9962
+ if (typeof path.style.fill === "object") {
9963
+ const fill = path.style.fill;
9964
+ const texture = this._textureMap.get(`${pIndex}.${fIndex}.fill`) ?? this._textureMap.get(`${pIndex}.fill`) ?? this._textureMap.get("fill");
9965
+ if (fill.enabled !== false && (texture || fill.color)) {
9966
+ const { uvTransform, disableWrapMode } = getDrawOptions(
9967
+ fill,
9968
+ texture?.box ?? {
9969
+ width: this.parent.size.width,
9970
+ height: this.parent.size.height
9971
+ }
9972
+ );
9973
+ ctx.addPath(path);
9974
+ ctx.style = { ...path.style };
9975
+ ctx.uvTransform = uvTransform;
9976
+ ctx.fillStyle = texture?.texture ?? fill.color;
9977
+ ctx.vertTransform = this._getVertTransform();
9978
+ ctx.fill({ disableWrapMode });
9979
+ }
9980
+ } else {
9905
9981
  ctx.addPath(path);
9906
9982
  ctx.style = { ...path.style };
9907
- ctx.lineWidth = outline.width || 1;
9908
- ctx.uvTransform = uvTransform;
9909
- ctx.strokeStyle = this._textures[0] ?? outline.color;
9910
- ctx.lineCap = outline.lineCap;
9911
- ctx.lineJoin = outline.lineJoin;
9912
9983
  ctx.vertTransform = this._getVertTransform();
9913
- ctx.stroke({ disableWrapMode });
9984
+ ctx.fill();
9914
9985
  }
9915
- } else {
9916
- ctx.addPath(path);
9917
- ctx.style = { ...path.style };
9918
- ctx.vertTransform = this._getVertTransform();
9919
- ctx.stroke();
9920
9986
  }
9921
- }
9922
- if (path.style.fill && !isNone(path.style.fill)) {
9923
- if (typeof path.style.fill === "object") {
9924
- const fill = path.style.fill;
9925
- if (fill.enabled !== false && (this._textures[1] || fill.color)) {
9926
- const { uvTransform, disableWrapMode } = getDrawOptions(fill, this.parent.size);
9987
+ if (path.style.stroke && !isNone(path.style.stroke)) {
9988
+ if (typeof path.style.stroke === "object") {
9989
+ const outline = path.style.stroke;
9990
+ const texture = this._textureMap.get(`${pIndex}.${fIndex}.outline`) ?? this._textureMap.get(`${pIndex}.outline`) ?? this._textureMap.get("outline");
9991
+ if (outline.enabled !== false && (texture || outline.color) && (outline.width === void 0 || outline.width)) {
9992
+ const { uvTransform, disableWrapMode } = getDrawOptions(
9993
+ outline,
9994
+ texture?.box ?? {
9995
+ width: this.parent.size.width,
9996
+ height: this.parent.size.height
9997
+ }
9998
+ );
9999
+ ctx.addPath(path);
10000
+ ctx.style = { ...path.style };
10001
+ ctx.lineWidth = outline.width || 1;
10002
+ ctx.uvTransform = uvTransform;
10003
+ ctx.strokeStyle = texture?.texture ?? outline.color;
10004
+ ctx.lineCap = outline.lineCap;
10005
+ ctx.lineJoin = outline.lineJoin;
10006
+ ctx.vertTransform = this._getVertTransform();
10007
+ ctx.stroke({ disableWrapMode });
10008
+ }
10009
+ } else {
9927
10010
  ctx.addPath(path);
9928
10011
  ctx.style = { ...path.style };
9929
- ctx.uvTransform = uvTransform;
9930
- ctx.fillStyle = this._textures[1] ?? fill.color;
9931
10012
  ctx.vertTransform = this._getVertTransform();
9932
- ctx.fill({ disableWrapMode });
10013
+ ctx.stroke();
9933
10014
  }
9934
- } else {
9935
- ctx.addPath(path);
9936
- ctx.style = { ...path.style };
9937
- ctx.vertTransform = this._getVertTransform();
9938
- ctx.fill();
9939
10015
  }
9940
10016
  }
9941
10017
  });
@@ -10069,16 +10145,22 @@ let BaseElement2D = class extends Node2D {
10069
10145
  }
10070
10146
  return this;
10071
10147
  }
10072
- _updateStyleProperty(key, value, _oldValue, _declaration) {
10148
+ _updateStyleProperty(key, value, oldValue, _declaration) {
10073
10149
  switch (key) {
10074
10150
  case "rotate":
10075
10151
  this.rotation = this.style.rotate * DEG_TO_RAD;
10076
10152
  break;
10077
10153
  case "scaleX":
10078
10154
  this.scale.x = this.style.scaleX;
10155
+ if (this.text.canDraw() && (value ^ oldValue) < 0) {
10156
+ this.requestRedraw();
10157
+ }
10079
10158
  break;
10080
10159
  case "scaleY":
10081
10160
  this.scale.y = this.style.scaleY;
10161
+ if (this.text.canDraw() && (value ^ oldValue) < 0) {
10162
+ this.requestRedraw();
10163
+ }
10082
10164
  break;
10083
10165
  case "skewX":
10084
10166
  this.skew.x = this.style.skewX;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "modern-canvas",
3
3
  "type": "module",
4
- "version": "0.8.4",
4
+ "version": "0.8.6",
5
5
  "packageManager": "pnpm@9.15.1",
6
6
  "description": "A JavaScript WebGL rendering engine.",
7
7
  "author": "wxm",
@@ -75,8 +75,8 @@
75
75
  "earcut": "^3.0.2",
76
76
  "modern-font": "^0.4.1",
77
77
  "modern-idoc": "^0.8.9",
78
- "modern-path2d": "^1.4.8",
79
- "modern-text": "^1.7.4"
78
+ "modern-path2d": "^1.4.9",
79
+ "modern-text": "^1.7.6"
80
80
  },
81
81
  "devDependencies": {
82
82
  "@antfu/eslint-config": "^5.2.1",