canvu-react 0.3.6 → 0.3.8

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/dist/index.js CHANGED
@@ -365,7 +365,7 @@ function attachViewportInput(options) {
365
365
  if (e.ctrlKey || e.metaKey) {
366
366
  e.preventDefault();
367
367
  const dy = wheelDeltaYPixels(e);
368
- const normDy = dy < 20 ? dy * 12 : dy;
368
+ const normDy = Math.abs(dy) < 20 ? dy * 12 : dy;
369
369
  const factor = Math.exp(-normDy * wheelZoomSensitivity);
370
370
  const rect = element.getBoundingClientRect();
371
371
  camera.setZoom(camera.zoom * factor, {
@@ -610,89 +610,6 @@ function createCustomShapeItem(id, bounds, content) {
610
610
  };
611
611
  }
612
612
 
613
- // src/scene/freehand-path.ts
614
- function dedupeFreehandPoints(points, minDist) {
615
- if (points.length <= 2) {
616
- return points.map((p) => ({ ...p }));
617
- }
618
- const minSq = minDist * minDist;
619
- const first = points[0];
620
- if (!first) return [];
621
- const out = [{ ...first }];
622
- for (let i = 1; i < points.length - 1; i++) {
623
- const p = points[i];
624
- const last = out[out.length - 1];
625
- if (!p || !last) continue;
626
- const dx = p.x - last.x;
627
- const dy = p.y - last.y;
628
- if (dx * dx + dy * dy >= minSq) {
629
- out.push({ ...p });
630
- }
631
- }
632
- const end = points[points.length - 1];
633
- const lastKept = out[out.length - 1];
634
- if (!end || !lastKept) return out;
635
- if ((end.x - lastKept.x) ** 2 + (end.y - lastKept.y) ** 2 > 1e-12) {
636
- out.push({ ...end });
637
- }
638
- return out;
639
- }
640
- function smoothFreehandPointsToPathD(points) {
641
- const n = points.length;
642
- if (n === 0) return "";
643
- if (n === 1) {
644
- const p = points[0];
645
- if (!p) return "";
646
- return `M ${p.x} ${p.y}`;
647
- }
648
- if (n === 2) {
649
- const a = points[0];
650
- const b = points[1];
651
- if (!a || !b) return "";
652
- return `M ${a.x} ${a.y} L ${b.x} ${b.y}`;
653
- }
654
- const p0 = points[0];
655
- if (!p0) return "";
656
- let d = `M ${p0.x} ${p0.y}`;
657
- let i = 1;
658
- for (; i < n - 2; i++) {
659
- const pi = points[i];
660
- const pi1 = points[i + 1];
661
- if (!pi || !pi1) continue;
662
- const xc = (pi.x + pi1.x) / 2;
663
- const yc = (pi.y + pi1.y) / 2;
664
- d += ` Q ${pi.x} ${pi.y} ${xc} ${yc}`;
665
- }
666
- const pLast = points[i];
667
- const pEnd = points[i + 1];
668
- if (!pLast || !pEnd) return d;
669
- d += ` Q ${pLast.x} ${pLast.y} ${pEnd.x} ${pEnd.y}`;
670
- return d;
671
- }
672
- function outlineStrokeToClosedPathD(outline) {
673
- const len = outline.length;
674
- if (len === 0) return "";
675
- const first = outline[0];
676
- if (!first) return "";
677
- if (len < 3) {
678
- let d2 = `M ${first[0]} ${first[1]}`;
679
- for (let i = 1; i < len; i++) {
680
- const pt = outline[i];
681
- if (!pt) continue;
682
- d2 += ` L ${pt[0]} ${pt[1]}`;
683
- }
684
- return `${d2} Z`;
685
- }
686
- let d = `M ${first[0]} ${first[1]} Q`;
687
- for (let i = 0; i < len; i++) {
688
- const p0 = outline[i];
689
- const p1 = outline[(i + 1) % len];
690
- if (!p0 || !p1) continue;
691
- d += ` ${p0[0]} ${p0[1]} ${(p0[0] + p1[0]) / 2} ${(p0[1] + p1[1]) / 2}`;
692
- }
693
- return `${d} Z`;
694
- }
695
-
696
613
  // src/scene/text-svg.ts
697
614
  function escapeSvgTextContent(s) {
698
615
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
@@ -813,7 +730,7 @@ var DEFAULT_STROKE_STYLE = {
813
730
  strokeWidth: 2
814
731
  };
815
732
  var TOOL_FREEHAND_DEFAULTS = {
816
- draw: { strokeWidth: 3 },
733
+ draw: { strokeWidth: 10 },
817
734
  pencil: { strokeWidth: 3 },
818
735
  brush: { strokeWidth: 10 },
819
736
  marker: { stroke: "#fde047", strokeWidth: 16, strokeOpacity: 0.5 }
@@ -830,18 +747,18 @@ function perfectFreehandOptions(toolKind, style, strokeComplete, pressureAware =
830
747
  ...base,
831
748
  size: Math.max(2, sw * 1.05),
832
749
  thinning: 0.42,
833
- smoothing: 0.56,
834
- streamline: 0.18,
835
- simulatePressure: false
750
+ smoothing: 0.78,
751
+ streamline: 0.62,
752
+ simulatePressure: true
836
753
  };
837
754
  }
838
755
  return {
839
756
  ...base,
840
757
  size: Math.max(2, sw * 1.18),
841
758
  thinning: 0.12,
842
- smoothing: 0.72,
843
- streamline: 0.42,
844
- simulatePressure: false
759
+ smoothing: 0.85,
760
+ streamline: 0.78,
761
+ simulatePressure: true
845
762
  };
846
763
  }
847
764
  if (toolKind === "brush") {
@@ -859,7 +776,7 @@ function perfectFreehandOptions(toolKind, style, strokeComplete, pressureAware =
859
776
  thinning: 0.08,
860
777
  smoothing: 0.88,
861
778
  streamline: 0.84,
862
- simulatePressure: false
779
+ simulatePressure: true
863
780
  };
864
781
  }
865
782
  function resolveStrokeStyle(item) {
@@ -929,70 +846,41 @@ function computeFreehandSvgPayload(pathPointsLocal, style, toolKind, strokeCompl
929
846
  if (pathPointsLocal.length === 1) {
930
847
  const p = pathPointsLocal[0];
931
848
  if (!p) return null;
932
- const r = Math.max(0.5, style.strokeWidth / 2);
933
- return {
934
- kind: "circle",
935
- cx: p.x,
936
- cy: p.y,
937
- r,
938
- fill: style.stroke,
939
- fillOpacity: style.strokeOpacity
940
- };
941
- }
942
- const minDist = Math.min(0.25, Math.max(0.02, style.strokeWidth * 0.02));
943
- const pts = dedupeFreehandPoints(pathPointsLocal, minDist);
944
- if (pts.length === 0) return null;
945
- if (pts.length === 1) {
946
- const p = pts[0];
947
- if (!p) return null;
948
- const r = Math.max(0.5, style.strokeWidth / 2);
949
849
  return {
950
850
  kind: "circle",
951
851
  cx: p.x,
952
852
  cy: p.y,
953
- r,
853
+ r: Math.max(0.5, style.strokeWidth / 2),
954
854
  fill: style.stroke,
955
855
  fillOpacity: style.strokeOpacity
956
856
  };
957
857
  }
958
- const hasPressure = toolKind === "draw" && pts.some((p) => p.pressure != null && Number.isFinite(p.pressure));
959
- if (toolKind === "draw" && !hasPressure) {
960
- const d2 = smoothFreehandPointsToPathD(pts);
961
- return {
962
- kind: "strokePath",
963
- d: d2,
964
- stroke: style.stroke,
965
- strokeWidth: style.strokeWidth,
966
- strokeOpacity: style.strokeOpacity
967
- };
968
- }
969
- const input = hasPressure ? pts.map(
858
+ const hasPressure = pathPointsLocal.some(
859
+ (p) => p.pressure != null && Number.isFinite(p.pressure)
860
+ );
861
+ const input = hasPressure ? pathPointsLocal.map(
970
862
  (p) => [p.x, p.y, Math.min(1, Math.max(0, p.pressure ?? 0.5))]
971
- ) : pts.map((p) => [p.x, p.y]);
972
- const opts = perfectFreehandOptions(toolKind, style, strokeComplete, hasPressure);
973
- let outline = [];
974
- try {
975
- const raw = getStroke(input, opts);
976
- outline = raw.map(([x, y]) => [x, y]);
977
- } catch {
978
- outline = [];
979
- }
980
- if (outline.length >= 3) {
981
- const d2 = outlineStrokeToClosedPathD(outline);
982
- return {
983
- kind: "fillPath",
984
- d: d2,
985
- fill: style.stroke,
986
- fillOpacity: style.strokeOpacity
987
- };
863
+ ) : pathPointsLocal.map((p) => [p.x, p.y]);
864
+ const stroke = getStroke(
865
+ input,
866
+ perfectFreehandOptions(toolKind, style, strokeComplete, hasPressure)
867
+ );
868
+ if (stroke.length < 3) return null;
869
+ const first = stroke[0];
870
+ if (!first) return null;
871
+ let d = `M ${first[0]} ${first[1]} Q`;
872
+ for (let i = 0; i < stroke.length; i++) {
873
+ const a = stroke[i];
874
+ const b = stroke[(i + 1) % stroke.length];
875
+ if (!a || !b) continue;
876
+ d += ` ${a[0]} ${a[1]} ${(a[0] + b[0]) / 2} ${(a[1] + b[1]) / 2}`;
988
877
  }
989
- const d = smoothFreehandPointsToPathD(pts);
878
+ d += " Z";
990
879
  return {
991
- kind: "strokePath",
880
+ kind: "fillPath",
992
881
  d,
993
- stroke: style.stroke,
994
- strokeWidth: style.strokeWidth,
995
- strokeOpacity: style.strokeOpacity
882
+ fill: style.stroke,
883
+ fillOpacity: style.strokeOpacity
996
884
  };
997
885
  }
998
886
  function freehandPayloadToSvgString(payload) {