canvas-drawing-editor 2.2.0 → 2.3.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.
@@ -349,8 +349,8 @@ class $ extends HTMLElement {
349
349
  const y = this.objects.find((w) => w.id === c.objectId);
350
350
  if (y)
351
351
  for (const w of Object.keys(c.toProps)) {
352
- const T = c.fromProps[w] ?? 0, E = c.toProps[w] ?? 0;
353
- y[w] = T + (E - T) * f;
352
+ const k = c.fromProps[w] ?? 0, E = c.toProps[w] ?? 0;
353
+ y[w] = k + (E - k) * f;
354
354
  }
355
355
  (r = (o = c.config).onUpdate) == null || r.call(o, p), p >= 1 ? c.config.repeat === -1 || c.currentRepeat < c.config.repeat ? (c.currentRepeat++, c.startTime = t, c.config.yoyo && (c.isReversed = !c.isReversed), i = !0) : (c.isCompleted = !0, (a = (l = c.config).onComplete) == null || a.call(l), e.push(h)) : i = !0;
356
356
  }
@@ -404,13 +404,52 @@ class $ extends HTMLElement {
404
404
  }
405
405
  // 生命周期:属性变化
406
406
  attributeChangedCallback(t, i, e) {
407
- if (i !== e) {
408
- if (t === "initial-data" && e && this.canvas) {
409
- this.loadInitialData(), this.renderCanvas();
410
- return;
411
- }
412
- this.parseAttributes(), this.container && this.updateUI();
407
+ if (i === e) return;
408
+ if (t === "initial-data" && e && this.canvas) {
409
+ this.loadInitialData(), this.renderCanvas();
410
+ return;
411
+ }
412
+ if (t === "hotzone-data" && this.canvas) {
413
+ this.parseHotzoneData(), this.applyHotzoneData(), this.renderCanvas();
414
+ return;
413
415
  }
416
+ const s = [
417
+ "title",
418
+ "lang",
419
+ "theme-color",
420
+ "tool-config",
421
+ "enable-hotzone",
422
+ "show-pencil",
423
+ "show-rectangle",
424
+ "show-circle",
425
+ "show-text",
426
+ "show-image",
427
+ "show-zoom",
428
+ "show-download",
429
+ "show-export",
430
+ "show-import",
431
+ "show-color",
432
+ "show-clear",
433
+ "show-line",
434
+ "show-arrow",
435
+ "show-polygon",
436
+ "show-undo",
437
+ "show-redo",
438
+ "show-layers",
439
+ "show-group",
440
+ "show-align"
441
+ ];
442
+ if (this.parseAttributes(), this.container && s.includes(t)) {
443
+ const n = [...this.objects], o = this.scale, r = { ...this.panOffset }, l = new Set(this.selectedIds);
444
+ this.render(), this.setupEventListeners(), this.initCanvas(!1), this.objects = n, this.scale = o, this.panOffset = r, this.selectedIds = l, this.objects.forEach((a) => {
445
+ if (a.type === "IMAGE" && a.dataUrl) {
446
+ const h = new Image();
447
+ h.onload = () => {
448
+ a.imageElement = h, this.renderCanvas();
449
+ }, h.src = a.dataUrl;
450
+ }
451
+ }), this.updateZoomDisplay(), this.renderCanvas();
452
+ } else this.container && this.updateUI();
414
453
  }
415
454
  // 解析 HTML 属性
416
455
  parseAttributes() {
@@ -1774,6 +1813,23 @@ class $ extends HTMLElement {
1774
1813
  }
1775
1814
  }
1776
1815
  }
1816
+ // ========== 公开 API 方法 ==========
1817
+ // 导出画布数据为 JSON 对象
1818
+ exportJSON() {
1819
+ return {
1820
+ version: "1.0",
1821
+ objects: this.objects.map((t) => {
1822
+ const { imageElement: i, ...e } = t;
1823
+ return e;
1824
+ })
1825
+ };
1826
+ }
1827
+ // 导出画布为 PNG 图片
1828
+ exportPNG(t = "canvas-export.png") {
1829
+ if (!this.canvas) return;
1830
+ const i = document.createElement("a");
1831
+ i.download = t, i.href = this.canvas.toDataURL("image/png"), i.click();
1832
+ }
1777
1833
  // ========== Tween动画系统方法 ==========
1778
1834
  // 创建动画 (使用 tweenAnimate 避免与 HTMLElement.animate 冲突)
1779
1835
  tweenAnimate(t, i, e = {}) {
@@ -2258,7 +2314,7 @@ class $ extends HTMLElement {
2258
2314
  // 绘制单个对象
2259
2315
  drawObject(t, i) {
2260
2316
  if (i.visible !== !1) {
2261
- if (t.save(), i.rotation || i.skewX || i.skewY) {
2317
+ if (t.save(), i.opacity !== void 0 && i.opacity !== 1 && (t.globalAlpha = i.opacity), i.rotation || i.skewX || i.skewY) {
2262
2318
  const e = this.getObjectBounds(i), s = e.x + e.width / 2, n = e.y + e.height / 2;
2263
2319
  t.translate(s, n), i.rotation && t.rotate(i.rotation), (i.skewX || i.skewY) && t.transform(1, i.skewY || 0, i.skewX || 0, 1, 0, 0), t.translate(-s, -n);
2264
2320
  }
@@ -2470,8 +2526,8 @@ class $ extends HTMLElement {
2470
2526
  if (t.skewX || t.skewY) {
2471
2527
  const p = t.skewX || 0, f = t.skewY || 0, y = 1 - p * f;
2472
2528
  if (Math.abs(y) > 1e-3) {
2473
- const w = (c - p * d) / y, T = (d - f * c) / y;
2474
- c = w, d = T;
2529
+ const w = (c - p * d) / y, k = (d - f * c) / y;
2530
+ c = w, d = k;
2475
2531
  }
2476
2532
  }
2477
2533
  l = n + c, a = o + d;
@@ -3257,8 +3313,8 @@ class $ extends HTMLElement {
3257
3313
  g.addEventListener("click", (m) => {
3258
3314
  const b = m.currentTarget, v = b.dataset.lineStyle;
3259
3315
  this.lineStyle = v, this.shadow.querySelectorAll(".line-style-btn").forEach((x) => x.classList.remove("active")), b.classList.add("active");
3260
- const k = this.getSelectedObjects();
3261
- k.length > 0 && (this.saveHistory(), k.forEach((x) => {
3316
+ const T = this.getSelectedObjects();
3317
+ T.length > 0 && (this.saveHistory(), T.forEach((x) => {
3262
3318
  (x.type === "LINE" || x.type === "ARROW" || x.type === "RECTANGLE" || x.type === "CIRCLE" || x.type === "POLYGON" || x.type === "TRIANGLE" || x.type === "STAR" || x.type === "HEART" || x.type === "DIAMOND") && (x.lineStyle = v);
3263
3319
  }), this.renderCanvas(), this.dispatchChangeEvent());
3264
3320
  });
@@ -3288,11 +3344,11 @@ class $ extends HTMLElement {
3288
3344
  const g = (m) => {
3289
3345
  const b = m.target.value;
3290
3346
  if (this.color = b, this.selectedId) {
3291
- const v = this.objects.find((k) => k.id === this.selectedId);
3347
+ const v = this.objects.find((T) => T.id === this.selectedId);
3292
3348
  v && (this.saveHistory(), v.color = b, this.renderCanvas(), this.dispatchChangeEvent());
3293
3349
  } else this.selectedIds.size > 0 && (this.saveHistory(), this.selectedIds.forEach((v) => {
3294
- const k = this.objects.find((x) => x.id === v);
3295
- k && (k.color = b);
3350
+ const T = this.objects.find((x) => x.id === v);
3351
+ T && (T.color = b);
3296
3352
  }), this.renderCanvas(), this.dispatchChangeEvent());
3297
3353
  };
3298
3354
  y.addEventListener("input", g), y.addEventListener("change", g);
@@ -3300,8 +3356,8 @@ class $ extends HTMLElement {
3300
3356
  this.shadow.querySelectorAll(".image-input").forEach((g) => {
3301
3357
  g.addEventListener("change", (m) => this.handleImageUpload(m));
3302
3358
  });
3303
- const w = this.shadow.querySelector(".zoom-in-btn"), T = this.shadow.querySelector(".zoom-out-btn"), E = this.shadow.querySelector(".zoom-text");
3304
- w && w.addEventListener("click", () => this.zoomIn()), T && T.addEventListener("click", () => this.zoomOut()), E && E.addEventListener("click", () => this.resetZoom());
3359
+ const w = this.shadow.querySelector(".zoom-in-btn"), k = this.shadow.querySelector(".zoom-out-btn"), E = this.shadow.querySelector(".zoom-text");
3360
+ w && w.addEventListener("click", () => this.zoomIn()), k && k.addEventListener("click", () => this.zoomOut()), E && E.addEventListener("click", () => this.resetZoom());
3305
3361
  const P = this.shadow.querySelector(".save-json-btn"), O = this.shadow.querySelector(".load-json-input"), R = this.shadow.querySelector(".export-png-btn");
3306
3362
  P && P.addEventListener("click", () => this.saveJson()), O && O.addEventListener("change", (g) => this.loadJson(g)), R && R.addEventListener("click", () => this.exportPng());
3307
3363
  const L = this.shadow.querySelector(".clear-canvas-btn"), z = this.shadow.querySelector(".clear-confirm-popup"), A = this.shadow.querySelector(".clear-confirm-yes"), D = this.shadow.querySelector(".clear-confirm-no");
@@ -3395,6 +3451,7 @@ class $ extends HTMLElement {
3395
3451
  width: 100%;
3396
3452
  height: 100%;
3397
3453
  background: #f1f5f9;
3454
+ position: relative;
3398
3455
  }
3399
3456
 
3400
3457
  /* 工具栏 */