js-draw 0.7.1 → 0.7.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.
@@ -177,6 +177,7 @@ export default class SVGLoader {
177
177
  else if (child.nodeType === Node.ELEMENT_NODE) {
178
178
  const subElem = child;
179
179
  if (subElem.tagName.toLowerCase() === 'tspan') {
180
+ // FIXME: tspan's (x, y) components are absolute, not relative to the parent.
180
181
  contentList.push(this.makeText(subElem));
181
182
  }
182
183
  else {
@@ -83,11 +83,14 @@ export default class SVGRenderer extends AbstractRenderer {
83
83
  }
84
84
  this.lastPathString.push(path.toString());
85
85
  }
86
- // Apply [elemTransform] to [elem].
87
- transformFrom(elemTransform, elem, inCanvasSpace = false) {
86
+ // Apply [elemTransform] to [elem]. Uses both a `matrix` and `.x`, `.y` properties if `setXY` is true.
87
+ // Otherwise, just uses a `matrix`.
88
+ transformFrom(elemTransform, elem, inCanvasSpace = false, setXY = true) {
88
89
  let transform = !inCanvasSpace ? this.getCanvasToScreenTransform().rightMul(elemTransform) : elemTransform;
89
90
  const translation = transform.transformVec2(Vec2.zero);
90
- transform = transform.rightMul(Mat33.translation(translation.times(-1)));
91
+ if (setXY) {
92
+ transform = transform.rightMul(Mat33.translation(translation.times(-1)));
93
+ }
91
94
  if (!transform.eq(Mat33.identity)) {
92
95
  elem.style.transform = `matrix(
93
96
  ${transform.a1}, ${transform.b1},
@@ -98,8 +101,10 @@ export default class SVGRenderer extends AbstractRenderer {
98
101
  else {
99
102
  elem.style.transform = '';
100
103
  }
101
- elem.setAttribute('x', `${toRoundedString(translation.x)}`);
102
- elem.setAttribute('y', `${toRoundedString(translation.y)}`);
104
+ if (setXY) {
105
+ elem.setAttribute('x', `${toRoundedString(translation.x)}`);
106
+ elem.setAttribute('y', `${toRoundedString(translation.y)}`);
107
+ }
103
108
  }
104
109
  drawText(text, transform, style) {
105
110
  var _a;
@@ -120,7 +125,10 @@ export default class SVGRenderer extends AbstractRenderer {
120
125
  if (!this.textContainer) {
121
126
  const container = document.createElementNS(svgNameSpace, 'text');
122
127
  container.appendChild(document.createTextNode(text));
123
- this.transformFrom(transform, container, true);
128
+ // Don't set .x/.y properties (just use .style.transform).
129
+ // Child nodes aren't translated by .x/.y properties, but are by .style.transform.
130
+ const setXY = false;
131
+ this.transformFrom(transform, container, true, setXY);
124
132
  applyTextStyles(container, style);
125
133
  this.elem.appendChild(container);
126
134
  (_a = this.objectElems) === null || _a === void 0 ? void 0 : _a.push(container);
@@ -133,8 +141,12 @@ export default class SVGRenderer extends AbstractRenderer {
133
141
  const elem = document.createElementNS(svgNameSpace, 'tspan');
134
142
  elem.appendChild(document.createTextNode(text));
135
143
  this.textContainer.appendChild(elem);
144
+ // Make .x/.y relative to the parent.
136
145
  transform = this.textContainerTransform.inverse().rightMul(transform);
137
- this.transformFrom(transform, elem, true);
146
+ // .style.transform does nothing to tspan elements. As such, we need to set x/y:
147
+ const translation = transform.transformVec2(Vec2.zero);
148
+ elem.setAttribute('x', `${toRoundedString(translation.x)}`);
149
+ elem.setAttribute('y', `${toRoundedString(translation.y)}`);
138
150
  applyTextStyles(elem, style);
139
151
  }
140
152
  }
@@ -119,7 +119,7 @@ export default class TextTool extends BaseTool {
119
119
  this.textInputElem = document.createElement('textarea');
120
120
  this.textInputElem.value = initialText;
121
121
  this.textInputElem.style.display = 'inline-block';
122
- this.textTargetPosition = textCanvasPos;
122
+ this.textTargetPosition = this.editor.viewport.roundPoint(textCanvasPos);
123
123
  this.textRotation = -this.editor.viewport.getRotationAngle();
124
124
  this.textScale = Vec2.of(1, 1).times(this.editor.viewport.getSizeOfPixelOnCanvas());
125
125
  this.updateTextInput();
@@ -172,6 +172,8 @@ export default class TextTool extends BaseTool {
172
172
  const testRegion = Rect2.fromCorners(canvasPos.minus(halfTestRegionSize), canvasPos.plus(halfTestRegionSize));
173
173
  const targetNodes = this.editor.image.getElementsIntersectingRegion(testRegion);
174
174
  const targetTextNodes = targetNodes.filter(node => node instanceof TextComponent);
175
+ // End any TextNodes we're currently editing.
176
+ this.flushInput();
175
177
  if (targetTextNodes.length > 0) {
176
178
  const targetNode = targetTextNodes[targetTextNodes.length - 1];
177
179
  this.setTextStyle(targetNode.getTextStyle());
@@ -227,7 +229,7 @@ export default class TextTool extends BaseTool {
227
229
  }
228
230
  setTextStyle(style) {
229
231
  // Copy the style — we may change parts of it.
230
- this.textStyle = Object.assign({}, style);
232
+ this.textStyle = Object.assign(Object.assign({}, style), { renderingStyle: Object.assign({}, style.renderingStyle) });
231
233
  this.dispatchUpdateEvent();
232
234
  }
233
235
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "js-draw",
3
- "version": "0.7.1",
3
+ "version": "0.7.2",
4
4
  "description": "Draw pictures using a pen, touchscreen, or mouse! JS-draw is a drawing library for JavaScript and TypeScript. ",
5
5
  "main": "./dist/src/lib.d.ts",
6
6
  "types": "./dist/src/lib.js",
package/src/SVGLoader.ts CHANGED
@@ -218,6 +218,7 @@ export default class SVGLoader implements ImageLoader {
218
218
  } else if (child.nodeType === Node.ELEMENT_NODE) {
219
219
  const subElem = child as SVGElement;
220
220
  if (subElem.tagName.toLowerCase() === 'tspan') {
221
+ // FIXME: tspan's (x, y) components are absolute, not relative to the parent.
221
222
  contentList.push(this.makeText(subElem as SVGTSpanElement));
222
223
  } else {
223
224
  throw new Error(`Unrecognized text child element: ${subElem}`);
@@ -99,11 +99,15 @@ export default class SVGRenderer extends AbstractRenderer {
99
99
  this.lastPathString.push(path.toString());
100
100
  }
101
101
 
102
- // Apply [elemTransform] to [elem].
103
- private transformFrom(elemTransform: Mat33, elem: SVGElement, inCanvasSpace: boolean = false) {
102
+ // Apply [elemTransform] to [elem]. Uses both a `matrix` and `.x`, `.y` properties if `setXY` is true.
103
+ // Otherwise, just uses a `matrix`.
104
+ private transformFrom(elemTransform: Mat33, elem: SVGElement, inCanvasSpace: boolean = false, setXY: boolean = true) {
104
105
  let transform = !inCanvasSpace ? this.getCanvasToScreenTransform().rightMul(elemTransform) : elemTransform;
105
106
  const translation = transform.transformVec2(Vec2.zero);
106
- transform = transform.rightMul(Mat33.translation(translation.times(-1)));
107
+
108
+ if (setXY) {
109
+ transform = transform.rightMul(Mat33.translation(translation.times(-1)));
110
+ }
107
111
 
108
112
  if (!transform.eq(Mat33.identity)) {
109
113
  elem.style.transform = `matrix(
@@ -115,8 +119,10 @@ export default class SVGRenderer extends AbstractRenderer {
115
119
  elem.style.transform = '';
116
120
  }
117
121
 
118
- elem.setAttribute('x', `${toRoundedString(translation.x)}`);
119
- elem.setAttribute('y', `${toRoundedString(translation.y)}`);
122
+ if (setXY) {
123
+ elem.setAttribute('x', `${toRoundedString(translation.x)}`);
124
+ elem.setAttribute('y', `${toRoundedString(translation.y)}`);
125
+ }
120
126
  }
121
127
 
122
128
  private textContainer: SVGTextElement|null = null;
@@ -140,7 +146,11 @@ export default class SVGRenderer extends AbstractRenderer {
140
146
  if (!this.textContainer) {
141
147
  const container = document.createElementNS(svgNameSpace, 'text');
142
148
  container.appendChild(document.createTextNode(text));
143
- this.transformFrom(transform, container, true);
149
+
150
+ // Don't set .x/.y properties (just use .style.transform).
151
+ // Child nodes aren't translated by .x/.y properties, but are by .style.transform.
152
+ const setXY = false;
153
+ this.transformFrom(transform, container, true, setXY);
144
154
  applyTextStyles(container, style);
145
155
 
146
156
  this.elem.appendChild(container);
@@ -154,8 +164,14 @@ export default class SVGRenderer extends AbstractRenderer {
154
164
  elem.appendChild(document.createTextNode(text));
155
165
  this.textContainer.appendChild(elem);
156
166
 
167
+ // Make .x/.y relative to the parent.
157
168
  transform = this.textContainerTransform!.inverse().rightMul(transform);
158
- this.transformFrom(transform, elem, true);
169
+
170
+ // .style.transform does nothing to tspan elements. As such, we need to set x/y:
171
+ const translation = transform.transformVec2(Vec2.zero);
172
+ elem.setAttribute('x', `${toRoundedString(translation.x)}`);
173
+ elem.setAttribute('y', `${toRoundedString(translation.y)}`);
174
+
159
175
  applyTextStyles(elem, style);
160
176
  }
161
177
  }
@@ -148,7 +148,7 @@ export default class TextTool extends BaseTool {
148
148
  this.textInputElem = document.createElement('textarea');
149
149
  this.textInputElem.value = initialText;
150
150
  this.textInputElem.style.display = 'inline-block';
151
- this.textTargetPosition = textCanvasPos;
151
+ this.textTargetPosition = this.editor.viewport.roundPoint(textCanvasPos);
152
152
  this.textRotation = -this.editor.viewport.getRotationAngle();
153
153
  this.textScale = Vec2.of(1, 1).times(this.editor.viewport.getSizeOfPixelOnCanvas());
154
154
  this.updateTextInput();
@@ -210,6 +210,9 @@ export default class TextTool extends BaseTool {
210
210
  const targetNodes = this.editor.image.getElementsIntersectingRegion(testRegion);
211
211
  const targetTextNodes = targetNodes.filter(node => node instanceof TextComponent) as TextComponent[];
212
212
 
213
+ // End any TextNodes we're currently editing.
214
+ this.flushInput();
215
+
213
216
  if (targetTextNodes.length > 0) {
214
217
  const targetNode = targetTextNodes[targetTextNodes.length - 1];
215
218
  this.setTextStyle(targetNode.getTextStyle());
@@ -290,7 +293,7 @@ export default class TextTool extends BaseTool {
290
293
 
291
294
  private setTextStyle(style: TextStyle) {
292
295
  // Copy the style — we may change parts of it.
293
- this.textStyle = {...style};
296
+ this.textStyle = { ...style, renderingStyle: { ...style.renderingStyle } };
294
297
  this.dispatchUpdateEvent();
295
298
  }
296
299
  }