@nmmty/lazycanvas 0.3.4 → 0.3.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.
@@ -1,4 +1,4 @@
1
- import { ScaleType, IBaseLayer, IBaseLayerProps, AnyCentring } from "../../types";
1
+ import { ScaleType, IBaseLayer, IBaseLayerProps, AnyCentring, AnyGlobalCompositeOperation } from "../../types";
2
2
  import { LayerType } from "../../types/enum";
3
3
  export declare class BaseLayer<T extends IBaseLayerProps> {
4
4
  id: string;
@@ -74,6 +74,11 @@ export declare class BaseLayer<T extends IBaseLayerProps> {
74
74
  * @param zIndex {number} - The `zIndex` of the layer
75
75
  */
76
76
  setZIndex(zIndex: number): this;
77
+ /**
78
+ * @description Sets global composite operation of the layer.
79
+ * @param operation {AnyGlobalCompositeOperation} - The `operation` of the layer
80
+ */
81
+ setGlobalCompositeOperation(operation: AnyGlobalCompositeOperation): this;
77
82
  /**
78
83
  * @returns {IBaseLayer}
79
84
  */
@@ -141,6 +141,14 @@ class BaseLayer {
141
141
  this.zIndex = zIndex;
142
142
  return this;
143
143
  }
144
+ /**
145
+ * @description Sets global composite operation of the layer.
146
+ * @param operation {AnyGlobalCompositeOperation} - The `operation` of the layer
147
+ */
148
+ setGlobalCompositeOperation(operation) {
149
+ this.props.globalComposite = operation;
150
+ return this;
151
+ }
144
152
  /**
145
153
  * @returns {IBaseLayer}
146
154
  */
@@ -65,6 +65,16 @@ export declare class TextLayer extends BaseLayer<ITextLayerProps> {
65
65
  * @param filled {boolean} - The `filled` of the layer.
66
66
  */
67
67
  setFilled(filled: boolean): this;
68
+ /**
69
+ * @description Sets the spacing between the words.
70
+ * @param wordSpacing {number} - The `wordSpacing` of the text layer.
71
+ */
72
+ setWordSpacing(wordSpacing: number): this;
73
+ /**
74
+ * @description Sets the letter spacing.
75
+ * @param letterSpacing {number} - The `letterSpacing` of the text layer.
76
+ */
77
+ setLetterSpacing(letterSpacing: number): this;
68
78
  measureText(ctx: SKRSContext2D, canvas: Canvas): {
69
79
  width: number;
70
80
  height: number;
@@ -29,6 +29,8 @@ class TextLayer extends BaseLayer_1.BaseLayer {
29
29
  height: 0,
30
30
  };
31
31
  this.props.centring = enum_1.Centring.Center;
32
+ this.props.wordSpacing = 0;
33
+ this.props.letterSpacing = 0;
32
34
  }
33
35
  /**
34
36
  * @description Sets the text of the text layer.
@@ -155,6 +157,22 @@ class TextLayer extends BaseLayer_1.BaseLayer {
155
157
  this.props.filled = filled;
156
158
  return this;
157
159
  }
160
+ /**
161
+ * @description Sets the spacing between the words.
162
+ * @param wordSpacing {number} - The `wordSpacing` of the text layer.
163
+ */
164
+ setWordSpacing(wordSpacing) {
165
+ this.props.wordSpacing = wordSpacing;
166
+ return this;
167
+ }
168
+ /**
169
+ * @description Sets the letter spacing.
170
+ * @param letterSpacing {number} - The `letterSpacing` of the text layer.
171
+ */
172
+ setLetterSpacing(letterSpacing) {
173
+ this.props.letterSpacing = letterSpacing;
174
+ return this;
175
+ }
158
176
  measureText(ctx, canvas) {
159
177
  const w = (0, utils_1.parseToNormal)(this.props.size?.width, ctx, canvas);
160
178
  const h = (0, utils_1.parseToNormal)(this.props.size?.height, ctx, canvas, { width: w, height: 0 }, { vertical: true });
@@ -184,6 +202,8 @@ class TextLayer extends BaseLayer_1.BaseLayer {
184
202
  (0, utils_1.opacity)(ctx, this.props.opacity);
185
203
  (0, utils_1.filters)(ctx, this.props.filter);
186
204
  ctx.textAlign = this.props.align;
205
+ ctx.letterSpacing = `${this.props.letterSpacing}px`;
206
+ ctx.wordSpacing = `${this.props.wordSpacing}px`;
187
207
  if (this.props.baseline)
188
208
  ctx.textBaseline = this.props.baseline;
189
209
  if (this.props.direction)
@@ -7,9 +7,9 @@ export declare class LayersManager implements ILayersManager {
7
7
  constructor(debug?: boolean);
8
8
  /**
9
9
  * Add a layer to the map
10
- * @param layers {AnyLayer[] | Group[]} - The `layer` or `group` to add to the map
10
+ * @param layers {AnyLayer[]} - The `layer` or `group` to add to the map
11
11
  */
12
- add(...layers: AnyLayer[] | Group[]): this;
12
+ add(...layers: AnyLayer[]): this;
13
13
  /**
14
14
  * Remove a layer from the map
15
15
  * @param ids {string[]} - The `id` of the layer or group to remove
@@ -22,8 +22,9 @@ export declare class LayersManager implements ILayersManager {
22
22
  /**
23
23
  * Get a layer from the map
24
24
  * @param id {string} - The `id` of the layer or group to get
25
+ * @param cross {boolean} - Whether to search in groups or not
25
26
  */
26
- get(id: string): AnyLayer | Group | undefined;
27
+ get(id: string, cross?: boolean): AnyLayer | undefined;
27
28
  /**
28
29
  * Check if a layer exists in the map
29
30
  * @param id {string} - The `id` of the layer or group to check
@@ -36,7 +37,7 @@ export declare class LayersManager implements ILayersManager {
36
37
  /**
37
38
  * Get the values of the map
38
39
  */
39
- values(): IterableIterator<AnyLayer | Group>;
40
+ values(): IterableIterator<AnyLayer>;
40
41
  /**
41
42
  * Get the keys of the map
42
43
  */
@@ -44,12 +45,12 @@ export declare class LayersManager implements ILayersManager {
44
45
  /**
45
46
  * Get the entries of the map
46
47
  */
47
- entries(): IterableIterator<[string, AnyLayer | Group]>;
48
+ entries(): IterableIterator<[string, AnyLayer]>;
48
49
  /**
49
50
  * For each layer in the map
50
51
  * @param callbackfn {Function} - The `callback` function to execute
51
52
  */
52
- forEach(callbackfn: (value: AnyLayer | Group, key: string, map: Map<string, AnyLayer | Group>) => void): this;
53
+ forEach(callbackfn: (value: AnyLayer, key: string, map: Map<string, AnyLayer>) => void): this;
53
54
  /**
54
55
  * Convert the map to a JSON object
55
56
  */
@@ -62,11 +63,12 @@ export declare class LayersManager implements ILayersManager {
62
63
  /**
63
64
  * Convert the map to an array
64
65
  */
65
- toArray(): Array<AnyLayer | Group>;
66
+ toArray(): Array<AnyLayer>;
66
67
  /**
67
68
  * Convert an array to the map
68
- * @param array {Array<AnyLayer | Group>} - The `array` to convert
69
+ * @param array {Array<AnyLayer>} - The `array` to convert
69
70
  */
70
- fromArray(array: Array<AnyLayer | Group>): this;
71
+ fromArray(array: Array<AnyLayer>): this;
71
72
  sort(): void;
73
+ private crossSearch;
72
74
  }
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.LayersManager = void 0;
4
+ const Group_1 = require("../components/Group");
4
5
  const LazyUtil_1 = require("../../utils/LazyUtil");
5
6
  class LayersManager {
6
7
  map;
@@ -11,7 +12,7 @@ class LayersManager {
11
12
  }
12
13
  /**
13
14
  * Add a layer to the map
14
- * @param layers {AnyLayer[] | Group[]} - The `layer` or `group` to add to the map
15
+ * @param layers {AnyLayer[]} - The `layer` or `group` to add to the map
15
16
  */
16
17
  add(...layers) {
17
18
  if (this.debug)
@@ -48,9 +49,13 @@ class LayersManager {
48
49
  /**
49
50
  * Get a layer from the map
50
51
  * @param id {string} - The `id` of the layer or group to get
52
+ * @param cross {boolean} - Whether to search in groups or not
51
53
  */
52
- get(id) {
53
- return this.map.get(id);
54
+ get(id, cross = false) {
55
+ if (cross)
56
+ return this.crossSearch(id);
57
+ else
58
+ return this.map.get(id);
54
59
  }
55
60
  /**
56
61
  * Check if a layer exists in the map
@@ -113,7 +118,7 @@ class LayersManager {
113
118
  }
114
119
  /**
115
120
  * Convert an array to the map
116
- * @param array {Array<AnyLayer | Group>} - The `array` to convert
121
+ * @param array {Array<AnyLayer>} - The `array` to convert
117
122
  */
118
123
  fromArray(array) {
119
124
  this.map = new Map(array.map(l => [l.id, l]));
@@ -122,5 +127,17 @@ class LayersManager {
122
127
  sort() {
123
128
  this.fromArray(this.toArray().sort((a, b) => a.zIndex - b.zIndex));
124
129
  }
130
+ crossSearch(id) {
131
+ for (const layer of this.map.values()) {
132
+ if (layer.id === id)
133
+ return layer;
134
+ if (layer instanceof Group_1.Group) {
135
+ const result = layer.components.find(l => l.id === id);
136
+ if (result)
137
+ return result;
138
+ }
139
+ }
140
+ return undefined;
141
+ }
125
142
  }
126
143
  exports.LayersManager = LayersManager;
@@ -23,11 +23,19 @@ class RenderManager {
23
23
  if (layer instanceof Group_1.Group) {
24
24
  for (const subLayer of layer.components) {
25
25
  if (subLayer.visible) {
26
+ if (!subLayer.props.globalComposite)
27
+ this.lazyCanvas.ctx.globalCompositeOperation = 'source-over';
28
+ else
29
+ this.lazyCanvas.ctx.globalCompositeOperation = subLayer.props.globalComposite;
26
30
  await subLayer.draw(this.lazyCanvas.ctx, this.lazyCanvas.canvas, this.lazyCanvas.layers, this.debug);
27
31
  }
28
32
  }
29
33
  }
30
34
  else {
35
+ if (!layer.props.globalComposite)
36
+ this.lazyCanvas.ctx.globalCompositeOperation = 'source-over';
37
+ else
38
+ this.lazyCanvas.ctx.globalCompositeOperation = layer.props.globalComposite;
31
39
  await layer.draw(this.lazyCanvas.ctx, this.lazyCanvas.canvas, this.lazyCanvas.layers, this.debug);
32
40
  }
33
41
  this.lazyCanvas.ctx.shadowColor = 'transparent';
@@ -1,4 +1,4 @@
1
- import { ColorType, ScaleType, AnyCentring } from "../";
1
+ import { ColorType, ScaleType, AnyCentring, AnyGlobalCompositeOperation } from "../";
2
2
  import { LayerType } from "../enum";
3
3
 
4
4
  export interface IBaseLayer {
@@ -32,6 +32,7 @@ export interface IBaseLayerProps {
32
32
  offsetY: number;
33
33
  };
34
34
  transform: Transform;
35
+ globalComposite: AnyGlobalCompositeOperation;
35
36
  }
36
37
 
37
38
  export interface Transform {
@@ -23,4 +23,6 @@ export interface ITextLayerProps extends IBaseLayerProps {
23
23
  align: AnyTextAlign;
24
24
  baseline: AnyTextBaseline;
25
25
  direction: AnyTextDirection;
26
+ letterSpacing: number;
27
+ wordSpacing: number;
26
28
  }
@@ -100,3 +100,31 @@ export declare enum LinkType {
100
100
  X = "x",
101
101
  Y = "y"
102
102
  }
103
+ export declare enum GlobalCompositeOperation {
104
+ SourceOver = "source-over",
105
+ SourceIn = "source-in",
106
+ SourceOut = "source-out",
107
+ SourceAtop = "source-atop",
108
+ DestinationOver = "destination-over",
109
+ DestinationIn = "destination-in",
110
+ DestinationOut = "destination-out",
111
+ DestinationAtop = "destination-atop",
112
+ Lighter = "lighter",
113
+ Copy = "copy",
114
+ Xor = "xor",
115
+ Multiply = "multiply",
116
+ Screen = "screen",
117
+ Overlay = "overlay",
118
+ Darken = "darken",
119
+ Lighten = "lighten",
120
+ ColorDodge = "color-dodge",
121
+ ColorBurn = "color-burn",
122
+ HardLight = "hard-light",
123
+ SoftLight = "soft-light",
124
+ Difference = "difference",
125
+ Exclusion = "exclusion",
126
+ Hue = "hue",
127
+ Saturation = "saturation",
128
+ Color = "color",
129
+ Luminosity = "luminosity"
130
+ }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.LinkType = exports.PatternType = exports.Centring = exports.SaveFormat = exports.Export = exports.LineJoin = exports.LineCap = exports.TextDirection = exports.TextBaseline = exports.TextAlign = exports.FontWeight = exports.GradientType = exports.LayerScaleType = exports.LayerType = void 0;
3
+ exports.GlobalCompositeOperation = exports.LinkType = exports.PatternType = exports.Centring = exports.SaveFormat = exports.Export = exports.LineJoin = exports.LineCap = exports.TextDirection = exports.TextBaseline = exports.TextAlign = exports.FontWeight = exports.GradientType = exports.LayerScaleType = exports.LayerType = void 0;
4
4
  var LayerType;
5
5
  (function (LayerType) {
6
6
  LayerType["Base"] = "base";
@@ -117,3 +117,32 @@ var LinkType;
117
117
  LinkType["X"] = "x";
118
118
  LinkType["Y"] = "y";
119
119
  })(LinkType || (exports.LinkType = LinkType = {}));
120
+ var GlobalCompositeOperation;
121
+ (function (GlobalCompositeOperation) {
122
+ GlobalCompositeOperation["SourceOver"] = "source-over";
123
+ GlobalCompositeOperation["SourceIn"] = "source-in";
124
+ GlobalCompositeOperation["SourceOut"] = "source-out";
125
+ GlobalCompositeOperation["SourceAtop"] = "source-atop";
126
+ GlobalCompositeOperation["DestinationOver"] = "destination-over";
127
+ GlobalCompositeOperation["DestinationIn"] = "destination-in";
128
+ GlobalCompositeOperation["DestinationOut"] = "destination-out";
129
+ GlobalCompositeOperation["DestinationAtop"] = "destination-atop";
130
+ GlobalCompositeOperation["Lighter"] = "lighter";
131
+ GlobalCompositeOperation["Copy"] = "copy";
132
+ GlobalCompositeOperation["Xor"] = "xor";
133
+ GlobalCompositeOperation["Multiply"] = "multiply";
134
+ GlobalCompositeOperation["Screen"] = "screen";
135
+ GlobalCompositeOperation["Overlay"] = "overlay";
136
+ GlobalCompositeOperation["Darken"] = "darken";
137
+ GlobalCompositeOperation["Lighten"] = "lighten";
138
+ GlobalCompositeOperation["ColorDodge"] = "color-dodge";
139
+ GlobalCompositeOperation["ColorBurn"] = "color-burn";
140
+ GlobalCompositeOperation["HardLight"] = "hard-light";
141
+ GlobalCompositeOperation["SoftLight"] = "soft-light";
142
+ GlobalCompositeOperation["Difference"] = "difference";
143
+ GlobalCompositeOperation["Exclusion"] = "exclusion";
144
+ GlobalCompositeOperation["Hue"] = "hue";
145
+ GlobalCompositeOperation["Saturation"] = "saturation";
146
+ GlobalCompositeOperation["Color"] = "color";
147
+ GlobalCompositeOperation["Luminosity"] = "luminosity";
148
+ })(GlobalCompositeOperation || (exports.GlobalCompositeOperation = GlobalCompositeOperation = {}));
@@ -20,7 +20,8 @@ import {
20
20
  Centring,
21
21
  PatternType,
22
22
  SaveFormat,
23
- LinkType
23
+ LinkType,
24
+ GlobalCompositeOperation
24
25
  } from "./enum";
25
26
 
26
27
  export type ScaleType = string | number | 'vw' | 'vh' | 'vmin' | 'vmax' | Link;
@@ -53,6 +54,8 @@ export type AnySaveFormat = SaveFormat | 'png' | 'jpeg' | 'jpg' | 'svg';
53
54
 
54
55
  export type AnyLinkType = LinkType | 'width' | 'height' | 'x' | 'y';
55
56
 
57
+ export type AnyGlobalCompositeOperation = GlobalCompositeOperation | 'source-over' | 'source-in' | 'source-out' | 'source-atop' | 'destination-over' | 'destination-in' | 'destination-out' | 'destination-atop' | 'lighter' | 'copy' | 'xor' | 'multiply' | 'screen' | 'overlay' | 'darken' | 'lighten' | 'color-dodge' | 'color-burn' | 'hard-light' | 'soft-light' | 'difference' | 'exclusion' | 'hue' | 'saturation' | 'color' | 'luminosity';
58
+
56
59
  export type Point = {
57
60
  x: ScaleType;
58
61
  y: ScaleType;
@@ -35,6 +35,7 @@ const Group_1 = require("../structures/components/Group");
35
35
  const LineLayer_1 = require("../structures/components/LineLayer");
36
36
  const BezierLayer_1 = require("../structures/components/BezierLayer");
37
37
  const QuadraticLayer_1 = require("../structures/components/QuadraticLayer");
38
+ const TextLayer_1 = require("../structures/components/TextLayer");
38
39
  function generateID(type) {
39
40
  return `${type}-${Math.random().toString(36).substr(2, 9)}`;
40
41
  }
@@ -149,7 +150,7 @@ function parseToNormal(v, ctx, canvas, layer = { width: 0, height: 0 }, options
149
150
  let match = v.match(linkReg);
150
151
  if (!manager)
151
152
  return 0;
152
- let anyLayer = manager.get(match[2]);
153
+ let anyLayer = manager.get(match[2], true);
153
154
  const parcer = parser(ctx, canvas, manager);
154
155
  switch (match[1]) {
155
156
  case 'link-w':
@@ -157,6 +158,9 @@ function parseToNormal(v, ctx, canvas, layer = { width: 0, height: 0 }, options
157
158
  if (anyLayer instanceof LineLayer_1.LineLayer || anyLayer instanceof BezierLayer_1.BezierLayer || anyLayer instanceof QuadraticLayer_1.QuadraticLayer) {
158
159
  return anyLayer.getBoundingBox(ctx, canvas, manager).width + (parseInt(match[3]) || 0);
159
160
  }
161
+ else if (anyLayer instanceof TextLayer_1.TextLayer) {
162
+ return anyLayer.measureText(ctx, canvas).width + (parseInt(match[3]) || 0);
163
+ }
160
164
  else {
161
165
  return (parcer.parse(anyLayer.props.size.width) || 0) + (parseInt(match[3]) || 0);
162
166
  }
@@ -170,6 +174,9 @@ function parseToNormal(v, ctx, canvas, layer = { width: 0, height: 0 }, options
170
174
  if (anyLayer instanceof LineLayer_1.LineLayer || anyLayer instanceof BezierLayer_1.BezierLayer || anyLayer instanceof QuadraticLayer_1.QuadraticLayer) {
171
175
  return anyLayer.getBoundingBox(ctx, canvas, manager).height + (parseInt(match[3]) || 0);
172
176
  }
177
+ else if (anyLayer instanceof TextLayer_1.TextLayer) {
178
+ return anyLayer.measureText(ctx, canvas).height + (parseInt(match[3]) || 0);
179
+ }
173
180
  else {
174
181
  return (parcer.parse(anyLayer.props.size.height, LazyUtil_1.defaultArg.wh(parcer.parse(anyLayer.props.size.width)), LazyUtil_1.defaultArg.vl(true)) || 0) + (parseInt(match[3]) || 0);
175
182
  }
@@ -200,7 +207,7 @@ function parseToNormal(v, ctx, canvas, layer = { width: 0, height: 0 }, options
200
207
  else if (v instanceof Link_1.Link) {
201
208
  if (!manager)
202
209
  return 0;
203
- let anyLayer = manager.get(v.source);
210
+ let anyLayer = manager.get(v.source, true);
204
211
  const parcer = parser(ctx, canvas, manager);
205
212
  switch (v.type) {
206
213
  case enum_1.LinkType.Width:
@@ -209,6 +216,9 @@ function parseToNormal(v, ctx, canvas, layer = { width: 0, height: 0 }, options
209
216
  if (anyLayer instanceof LineLayer_1.LineLayer || anyLayer instanceof BezierLayer_1.BezierLayer || anyLayer instanceof QuadraticLayer_1.QuadraticLayer) {
210
217
  return anyLayer.getBoundingBox(ctx, canvas, manager).width + (parcer.parse(v.additionalSpacing, LazyUtil_1.defaultArg.wh(layer.width, layer.height), LazyUtil_1.defaultArg.vl(options.vertical, options.layer)) || 0);
211
218
  }
219
+ else if (anyLayer instanceof TextLayer_1.TextLayer) {
220
+ return anyLayer.measureText(ctx, canvas).width + (parcer.parse(v.additionalSpacing, LazyUtil_1.defaultArg.wh(layer.width, layer.height), LazyUtil_1.defaultArg.vl(options.vertical, options.layer)) || 0);
221
+ }
212
222
  else {
213
223
  return (parcer.parse(anyLayer.props.size.width) || 0) + (parcer.parse(v.additionalSpacing, LazyUtil_1.defaultArg.wh(layer.width, layer.height), LazyUtil_1.defaultArg.vl(options.vertical, options.layer)) || 0);
214
224
  }
@@ -223,6 +233,9 @@ function parseToNormal(v, ctx, canvas, layer = { width: 0, height: 0 }, options
223
233
  if (anyLayer instanceof LineLayer_1.LineLayer || anyLayer instanceof BezierLayer_1.BezierLayer || anyLayer instanceof QuadraticLayer_1.QuadraticLayer) {
224
234
  return anyLayer.getBoundingBox(ctx, canvas, manager).height + (parcer.parse(v.additionalSpacing, LazyUtil_1.defaultArg.wh(layer.width, layer.height), LazyUtil_1.defaultArg.vl(options.vertical, options.layer)) || 0);
225
235
  }
236
+ else if (anyLayer instanceof TextLayer_1.TextLayer) {
237
+ return anyLayer.measureText(ctx, canvas).height + (parcer.parse(v.additionalSpacing, LazyUtil_1.defaultArg.wh(layer.width, layer.height), LazyUtil_1.defaultArg.vl(options.vertical, options.layer)) || 0);
238
+ }
226
239
  else {
227
240
  return (parcer.parse(anyLayer.props.size.height, LazyUtil_1.defaultArg.wh(parcer.parse(anyLayer.props.size.width)), LazyUtil_1.defaultArg.vl(true)) || 0) + (parcer.parse(v.additionalSpacing, LazyUtil_1.defaultArg.wh(layer.width, layer.height), LazyUtil_1.defaultArg.vl(options.vertical, options.layer)) || 0);
228
241
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nmmty/lazycanvas",
3
- "version": "0.3.4",
3
+ "version": "0.3.6",
4
4
  "description": "A simple way to interact with @napi-rs/canvas in an advanced way!",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",