@nasser-sw/fabric 7.0.1-beta5 → 7.0.1-beta7

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/fabric-test2.html CHANGED
@@ -54,6 +54,9 @@
54
54
  <button id="toggleDebugBtn">Toggle Debug</button>
55
55
  <button id="exportPngBtn">Export as PNG</button>
56
56
  <button id="exportSvgBtn">Export as SVG</button>
57
+ <button id="saveJsonBtn">Save JSON</button>
58
+ <button id="loadJsonBtn">Load JSON</button>
59
+ <input type="file" id="loadJsonFile" accept=".json" style="display: none;">
57
60
  </div>
58
61
 
59
62
  <div style="display: flex; gap: 20px;">
@@ -243,6 +246,94 @@
243
246
  });
244
247
  });
245
248
 
249
+ // Save JSON functionality
250
+ document.getElementById('saveJsonBtn').addEventListener('click', () => {
251
+ try {
252
+ // Get the canvas as JSON
253
+ const canvasJson = canvas.toJSON();
254
+
255
+ // Create a beautiful formatted JSON string
256
+ const jsonString = JSON.stringify(canvasJson, null, 2);
257
+
258
+ // Create a blob and download link
259
+ const blob = new Blob([jsonString], { type: 'application/json' });
260
+ const url = URL.createObjectURL(blob);
261
+
262
+ const link = document.createElement('a');
263
+ link.download = `fabric-canvas-${Date.now()}.json`;
264
+ link.href = url;
265
+
266
+ // Trigger download
267
+ document.body.appendChild(link);
268
+ link.click();
269
+ document.body.removeChild(link);
270
+
271
+ // Clean up
272
+ URL.revokeObjectURL(url);
273
+
274
+ console.log('Canvas saved as JSON:', canvasJson);
275
+ console.log('JSON string length:', jsonString.length);
276
+ } catch (error) {
277
+ console.error('Save JSON failed:', error);
278
+ alert('Save failed: ' + error.message);
279
+ }
280
+ });
281
+
282
+ // Load JSON functionality
283
+ document.getElementById('loadJsonBtn').addEventListener('click', () => {
284
+ document.getElementById('loadJsonFile').click();
285
+ });
286
+
287
+ document.getElementById('loadJsonFile').addEventListener('change', (e) => {
288
+ const file = e.target.files[0];
289
+ if (!file) return;
290
+
291
+ const reader = new FileReader();
292
+ reader.onload = function(e) {
293
+ try {
294
+ const jsonData = JSON.parse(e.target.result);
295
+
296
+ console.log('Loading JSON data:', jsonData);
297
+
298
+ // Clear existing canvas
299
+ canvas.clear();
300
+
301
+ // Load the JSON data into the canvas
302
+ canvas.loadFromJSON(jsonData, () => {
303
+ // This callback is called after loading is complete
304
+ canvas.renderAll();
305
+ console.log('Canvas loaded from JSON successfully');
306
+ console.log('Loaded objects:', canvas.getObjects());
307
+
308
+ // Log details about loaded lines
309
+ const lines = canvas.getObjects('line');
310
+ lines.forEach((line, index) => {
311
+ console.log(`Line ${index + 1}:`, {
312
+ type: line.type,
313
+ left: line.left,
314
+ top: line.top,
315
+ x1: line.x1,
316
+ y1: line.y1,
317
+ x2: line.x2,
318
+ y2: line.y2,
319
+ stroke: line.stroke,
320
+ strokeWidth: line.strokeWidth
321
+ });
322
+ });
323
+ });
324
+
325
+ // Clear the file input for next use
326
+ e.target.value = '';
327
+
328
+ } catch (error) {
329
+ console.error('Load JSON failed:', error);
330
+ alert('Load failed: ' + error.message);
331
+ }
332
+ };
333
+
334
+ reader.readAsText(file);
335
+ });
336
+
246
337
  // Add initial line for testing
247
338
  const initialLine = new fabric.Line([150, 150, 350, 250], {
248
339
  stroke: '#2196F3',
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@nasser-sw/fabric",
3
3
  "description": "Object model for HTML5 canvas, and SVG-to-canvas parser. Backed by jsdom and node-canvas.",
4
4
  "homepage": "http://fabricjs.com/",
5
- "version": "7.0.1-beta5",
5
+ "version": "7.0.1-beta7",
6
6
  "author": "Juriy Zaytsev <kangax@gmail.com>",
7
7
  "contributors": [
8
8
  {
@@ -12,6 +12,7 @@ import { CENTER, LEFT, TOP } from '../constants';
12
12
  import type { CSSRules } from '../parser/typedefs';
13
13
  import { Control } from '../controls/Control';
14
14
  import type { TPointerEvent, Transform } from '../EventTypeDefs';
15
+ import { multiplyTransformMatrices } from '../util/misc/matrix';
15
16
 
16
17
  const coordProps = ['x1', 'x2', 'y1', 'y2'] as const;
17
18
 
@@ -99,13 +100,11 @@ export class Line<
99
100
  }
100
101
 
101
102
  _p1PositionHandler() {
102
- const vpt = this.canvas?.viewportTransform || [1, 0, 0, 1, 0, 0];
103
- return new Point(this.x1, this.y1).transform(vpt);
103
+ return new Point(this.x1, this.y1).transform(this.getViewportTransform());
104
104
  }
105
105
 
106
106
  _p2PositionHandler() {
107
- const vpt = this.canvas?.viewportTransform || [1, 0, 0, 1, 0, 0];
108
- return new Point(this.x2, this.y2).transform(vpt);
107
+ return new Point(this.x2, this.y2).transform(this.getViewportTransform());
109
108
  }
110
109
 
111
110
  _renderEndpointControl(
@@ -176,11 +175,6 @@ export class Line<
176
175
 
177
176
  setCoords() {
178
177
  if (this._useEndpointCoords) {
179
- // Set the object's center to the geometric center of the line
180
- const center = this._findCenterFromElement();
181
- this.left = center.x;
182
- this.top = center.y;
183
-
184
178
  // Set width and height for hit detection and bounding box
185
179
  const effectiveStrokeWidth =
186
180
  this.hitStrokeWidth === 'auto'
@@ -189,6 +183,13 @@ export class Line<
189
183
  const hitPadding = Math.max(effectiveStrokeWidth / 2 + 5, 10);
190
184
  this.width = Math.abs(this.x2 - this.x1) + hitPadding * 2;
191
185
  this.height = Math.abs(this.y2 - this.y1) + hitPadding * 2;
186
+
187
+ // Only update left/top if they haven't been explicitly set (e.g., during loading)
188
+ if (this.left === 0 && this.top === 0) {
189
+ const center = this._findCenterFromElement();
190
+ this.left = center.x;
191
+ this.top = center.y;
192
+ }
192
193
  }
193
194
  super.setCoords();
194
195
  }
@@ -385,8 +386,6 @@ export class Line<
385
386
  _renderDirectly(ctx: CanvasRenderingContext2D) {
386
387
  if (!this.visible) return;
387
388
  ctx.save();
388
- const vpt = this.canvas?.viewportTransform || [1, 0, 0, 1, 0, 0];
389
- ctx.transform(vpt[0], vpt[1], vpt[2], vpt[3], vpt[4], vpt[5]);
390
389
  ctx.globalAlpha = this.opacity;
391
390
  ctx.strokeStyle = this.stroke?.toString() || '#000';
392
391
  ctx.lineWidth = this.strokeWidth;
@@ -421,6 +420,15 @@ export class Line<
421
420
  T extends Omit<Props & TClassProperties<this>, keyof SProps>,
422
421
  K extends keyof T = never
423
422
  >(propertiesToInclude: K[] = []): Pick<T, K> & SProps {
423
+ if (this._useEndpointCoords) {
424
+ return {
425
+ ...super.toObject(propertiesToInclude),
426
+ x1: this.x1,
427
+ y1: this.y1,
428
+ x2: this.x2,
429
+ y2: this.y2,
430
+ };
431
+ }
424
432
  return {
425
433
  ...super.toObject(propertiesToInclude),
426
434
  ...this.calcLinePoints(),