js-draw 1.11.2 → 1.12.0

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.
@@ -57,6 +57,7 @@ const version_1 = __importDefault(require("./version"));
57
57
  const editorImageToSVG_1 = require("./image/export/editorImageToSVG");
58
58
  const ReactiveValue_1 = require("./util/ReactiveValue");
59
59
  const listenForKeyboardEventsFrom_1 = __importDefault(require("./util/listenForKeyboardEventsFrom"));
60
+ const mitLicenseAttribution_1 = __importDefault(require("./util/mitLicenseAttribution"));
60
61
  /**
61
62
  * The main entrypoint for the full editor.
62
63
  *
@@ -1202,9 +1203,19 @@ class Editor {
1202
1203
  text: [
1203
1204
  `This image editor is powered by js-draw v${version_1.default.number}.`,
1204
1205
  '',
1205
- 'js-draw uses several libraries at runtime. Particularly noteworthy are:',
1206
+ 'At runtime, js-draw uses',
1206
1207
  ' - The Coloris color picker: https://github.com/mdbassit/Coloris',
1207
- ' - The bezier.js Bézier curve library: https://github.com/Pomax/bezierjs'
1208
+ ' - The bezier.js Bézier curve library: https://github.com/Pomax/bezierjs',
1209
+ '',
1210
+ 'Both are licensed under the MIT license:',
1211
+ '',
1212
+ '',
1213
+ '== Coloris ==',
1214
+ (0, mitLicenseAttribution_1.default)('2021 Mohammed Bassit'),
1215
+ '',
1216
+ '',
1217
+ '== Bezier.js ==',
1218
+ (0, mitLicenseAttribution_1.default)('2023 Mike "Pomax" Kamermans'),
1208
1219
  ].join('\n'),
1209
1220
  minimized: true,
1210
1221
  });
@@ -15,6 +15,7 @@ export declare class StrokeSmoother {
15
15
  private onCurveAdded;
16
16
  private isFirstSegment;
17
17
  private buffer;
18
+ private centerOfMass;
18
19
  private lastPoint;
19
20
  private lastExitingVec;
20
21
  private currentCurve;
@@ -15,6 +15,7 @@ class StrokeSmoother {
15
15
  this.maxFitAllowed = maxFitAllowed;
16
16
  this.onCurveAdded = onCurveAdded;
17
17
  this.isFirstSegment = true;
18
+ this.centerOfMass = null;
18
19
  this.lastExitingVec = null;
19
20
  this.currentCurve = null;
20
21
  this.lastPoint = this.startPoint;
@@ -60,6 +61,7 @@ class StrokeSmoother {
60
61
  this.buffer[this.buffer.length - 2], lastPoint,
61
62
  ];
62
63
  this.currentCurve = null;
64
+ this.centerOfMass = null;
63
65
  this.isFirstSegment = false;
64
66
  }
65
67
  // Returns [upper curve, connector, lower curve]
@@ -107,10 +109,20 @@ class StrokeSmoother {
107
109
  if (shouldSnapToInitial) {
108
110
  return;
109
111
  }
112
+ if (!this.centerOfMass) {
113
+ this.centerOfMass = newPoint.pos;
114
+ }
115
+ else {
116
+ this.centerOfMass = this.centerOfMass
117
+ .times(this.buffer.length)
118
+ .plus(newPoint.pos).times(1 / (this.buffer.length + 1));
119
+ }
120
+ const toCenterOfMass = this.centerOfMass.minus(newPoint.pos);
110
121
  const deltaTimeSeconds = deltaTime / 1000;
111
122
  const velocity = newPoint.pos.minus(this.lastPoint.pos).times(1 / deltaTimeSeconds);
112
123
  // TODO: Do we need momentum smoothing? (this.momentum.lerp(velocity, 0.9);)
113
- this.momentum = velocity;
124
+ const k = 1;
125
+ this.momentum = velocity.plus(toCenterOfMass.times(k));
114
126
  }
115
127
  const lastPoint = this.lastPoint ?? newPoint;
116
128
  this.lastPoint = newPoint;
@@ -147,7 +159,7 @@ class StrokeSmoother {
147
159
  }
148
160
  let exitingVec = this.computeExitingVec();
149
161
  // Find the intersection between the entering vector and the exiting vector
150
- const maxRelativeLength = 2.4;
162
+ const maxRelativeLength = 1.6;
151
163
  const segmentStart = this.buffer[0];
152
164
  const segmentEnd = newPoint.pos;
153
165
  const startEndDist = segmentEnd.minus(segmentStart).magnitude();
@@ -168,11 +180,17 @@ class StrokeSmoother {
168
180
  if (intersection) {
169
181
  controlPoint = intersection.point;
170
182
  }
171
- // No intersection or the intersection is one of the end points?
172
- if (!controlPoint || segmentStart.eq(controlPoint) || segmentEnd.eq(controlPoint)) {
173
- // Position the control point closer to the first -- the connecting
174
- // segment will be roughly a line.
175
- controlPoint = segmentStart.plus(enteringVec.times(startEndDist / 4));
183
+ // No intersection?
184
+ if (!controlPoint) {
185
+ // Estimate the control point position based on the entering tangent line
186
+ controlPoint = segmentStart
187
+ .lerp(segmentEnd, 0.5)
188
+ .lerp(segmentStart.plus(enteringVec.times(startEndDist)), 0.25);
189
+ }
190
+ // Equal to an endpoint?
191
+ if (segmentStart.eq(controlPoint) || segmentEnd.eq(controlPoint)) {
192
+ // Position the control point between the two end points
193
+ controlPoint = segmentStart.lerp(segmentEnd, 0.5);
176
194
  }
177
195
  console.assert(!segmentStart.eq(controlPoint, 1e-11), 'Start and control points are equal!');
178
196
  console.assert(!controlPoint.eq(segmentEnd, 1e-11), 'Control and end points are equal!');
@@ -0,0 +1,2 @@
1
+ declare const mitLicenseAttribution: (copyright: string) => string;
2
+ export default mitLicenseAttribution;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const mitLicenseAttribution = (copyright) => {
4
+ const removeSingleLineBreaks = (text) => text.replace(/([^\n])[\n]([^\n])/g, '$1 $2');
5
+ return removeSingleLineBreaks(`
6
+ MIT License
7
+
8
+ Copyright (c) ${copyright}
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.`);
27
+ };
28
+ exports.default = mitLicenseAttribution;
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.default = {
4
- number: '1.11.2',
4
+ number: '1.12.0',
5
5
  };
@@ -28,6 +28,7 @@ import version from './version.mjs';
28
28
  import { editorImageToSVGSync, editorImageToSVGAsync } from './image/export/editorImageToSVG.mjs';
29
29
  import { MutableReactiveValue } from './util/ReactiveValue.mjs';
30
30
  import listenForKeyboardEventsFrom from './util/listenForKeyboardEventsFrom.mjs';
31
+ import mitLicenseAttribution from './util/mitLicenseAttribution.mjs';
31
32
  /**
32
33
  * The main entrypoint for the full editor.
33
34
  *
@@ -1173,9 +1174,19 @@ export class Editor {
1173
1174
  text: [
1174
1175
  `This image editor is powered by js-draw v${version.number}.`,
1175
1176
  '',
1176
- 'js-draw uses several libraries at runtime. Particularly noteworthy are:',
1177
+ 'At runtime, js-draw uses',
1177
1178
  ' - The Coloris color picker: https://github.com/mdbassit/Coloris',
1178
- ' - The bezier.js Bézier curve library: https://github.com/Pomax/bezierjs'
1179
+ ' - The bezier.js Bézier curve library: https://github.com/Pomax/bezierjs',
1180
+ '',
1181
+ 'Both are licensed under the MIT license:',
1182
+ '',
1183
+ '',
1184
+ '== Coloris ==',
1185
+ mitLicenseAttribution('2021 Mohammed Bassit'),
1186
+ '',
1187
+ '',
1188
+ '== Bezier.js ==',
1189
+ mitLicenseAttribution('2023 Mike "Pomax" Kamermans'),
1179
1190
  ].join('\n'),
1180
1191
  minimized: true,
1181
1192
  });
@@ -15,6 +15,7 @@ export declare class StrokeSmoother {
15
15
  private onCurveAdded;
16
16
  private isFirstSegment;
17
17
  private buffer;
18
+ private centerOfMass;
18
19
  private lastPoint;
19
20
  private lastExitingVec;
20
21
  private currentCurve;
@@ -12,6 +12,7 @@ export class StrokeSmoother {
12
12
  this.maxFitAllowed = maxFitAllowed;
13
13
  this.onCurveAdded = onCurveAdded;
14
14
  this.isFirstSegment = true;
15
+ this.centerOfMass = null;
15
16
  this.lastExitingVec = null;
16
17
  this.currentCurve = null;
17
18
  this.lastPoint = this.startPoint;
@@ -57,6 +58,7 @@ export class StrokeSmoother {
57
58
  this.buffer[this.buffer.length - 2], lastPoint,
58
59
  ];
59
60
  this.currentCurve = null;
61
+ this.centerOfMass = null;
60
62
  this.isFirstSegment = false;
61
63
  }
62
64
  // Returns [upper curve, connector, lower curve]
@@ -104,10 +106,20 @@ export class StrokeSmoother {
104
106
  if (shouldSnapToInitial) {
105
107
  return;
106
108
  }
109
+ if (!this.centerOfMass) {
110
+ this.centerOfMass = newPoint.pos;
111
+ }
112
+ else {
113
+ this.centerOfMass = this.centerOfMass
114
+ .times(this.buffer.length)
115
+ .plus(newPoint.pos).times(1 / (this.buffer.length + 1));
116
+ }
117
+ const toCenterOfMass = this.centerOfMass.minus(newPoint.pos);
107
118
  const deltaTimeSeconds = deltaTime / 1000;
108
119
  const velocity = newPoint.pos.minus(this.lastPoint.pos).times(1 / deltaTimeSeconds);
109
120
  // TODO: Do we need momentum smoothing? (this.momentum.lerp(velocity, 0.9);)
110
- this.momentum = velocity;
121
+ const k = 1;
122
+ this.momentum = velocity.plus(toCenterOfMass.times(k));
111
123
  }
112
124
  const lastPoint = this.lastPoint ?? newPoint;
113
125
  this.lastPoint = newPoint;
@@ -144,7 +156,7 @@ export class StrokeSmoother {
144
156
  }
145
157
  let exitingVec = this.computeExitingVec();
146
158
  // Find the intersection between the entering vector and the exiting vector
147
- const maxRelativeLength = 2.4;
159
+ const maxRelativeLength = 1.6;
148
160
  const segmentStart = this.buffer[0];
149
161
  const segmentEnd = newPoint.pos;
150
162
  const startEndDist = segmentEnd.minus(segmentStart).magnitude();
@@ -165,11 +177,17 @@ export class StrokeSmoother {
165
177
  if (intersection) {
166
178
  controlPoint = intersection.point;
167
179
  }
168
- // No intersection or the intersection is one of the end points?
169
- if (!controlPoint || segmentStart.eq(controlPoint) || segmentEnd.eq(controlPoint)) {
170
- // Position the control point closer to the first -- the connecting
171
- // segment will be roughly a line.
172
- controlPoint = segmentStart.plus(enteringVec.times(startEndDist / 4));
180
+ // No intersection?
181
+ if (!controlPoint) {
182
+ // Estimate the control point position based on the entering tangent line
183
+ controlPoint = segmentStart
184
+ .lerp(segmentEnd, 0.5)
185
+ .lerp(segmentStart.plus(enteringVec.times(startEndDist)), 0.25);
186
+ }
187
+ // Equal to an endpoint?
188
+ if (segmentStart.eq(controlPoint) || segmentEnd.eq(controlPoint)) {
189
+ // Position the control point between the two end points
190
+ controlPoint = segmentStart.lerp(segmentEnd, 0.5);
173
191
  }
174
192
  console.assert(!segmentStart.eq(controlPoint, 1e-11), 'Start and control points are equal!');
175
193
  console.assert(!controlPoint.eq(segmentEnd, 1e-11), 'Control and end points are equal!');
@@ -0,0 +1,2 @@
1
+ declare const mitLicenseAttribution: (copyright: string) => string;
2
+ export default mitLicenseAttribution;
@@ -0,0 +1,26 @@
1
+ const mitLicenseAttribution = (copyright) => {
2
+ const removeSingleLineBreaks = (text) => text.replace(/([^\n])[\n]([^\n])/g, '$1 $2');
3
+ return removeSingleLineBreaks(`
4
+ MIT License
5
+
6
+ Copyright (c) ${copyright}
7
+
8
+ Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ of this software and associated documentation files (the "Software"), to deal
10
+ in the Software without restriction, including without limitation the rights
11
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ copies of the Software, and to permit persons to whom the Software is
13
+ furnished to do so, subject to the following conditions:
14
+
15
+ The above copyright notice and this permission notice shall be included in all
16
+ copies or substantial portions of the Software.
17
+
18
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
+ SOFTWARE.`);
25
+ };
26
+ export default mitLicenseAttribution;
@@ -1,3 +1,3 @@
1
1
  export default {
2
- number: '1.11.2',
2
+ number: '1.12.0',
3
3
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "js-draw",
3
- "version": "1.11.2",
3
+ "version": "1.12.0",
4
4
  "description": "Draw pictures using a pen, touchscreen, or mouse! JS-draw is a drawing library for JavaScript and TypeScript. ",
5
5
  "types": "./dist/mjs/lib.d.ts",
6
6
  "main": "./dist/cjs/lib.js",
@@ -86,5 +86,5 @@
86
86
  "freehand",
87
87
  "svg"
88
88
  ],
89
- "gitHead": "e1d593def957ec85633ff89166f9af25ae03f862"
89
+ "gitHead": "c179c5b3ebca482dfb156527ec6631c8f5159033"
90
90
  }