@weasel-js/guides 1.15.0 → 1.15.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.
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { useState, useRef, useCallback, useEffect } from 'react';
2
- import { sceneBoxFrames, scenePoseFrame, useLatest, viewportWorldRect, tickedSegment, measuredSegmentCommands, AUTO_POSE_DESCRIPTOR, visualBoundsViaDescriptor, rectFromPlane, unionAABB, createTransformOp, asNodeId, sceneUnitScopes, screenToWorld, nodeGates, resolveStrokeWidth, resolveUnit, axisUnits, resolveScoped } from '@weasel-js/core';
3
- import { pointInPolygon, invert, mat3, applyToPoint, pxExtent, PATH_M, PATH_L, PATH_Z, pxExtentInFrame } from '@weasel-js/geom';
2
+ import { sceneBoxFrames, scenePoseFrame, useLatest, viewportWorldRect, viewWorldToScreen, tickedSegment, measuredSegmentCommands, AUTO_POSE_DESCRIPTOR, visualBoundsViaDescriptor, rectFromPlane, unionAABB, sceneMagnification, asNodeId, createTransformOp, sceneUnitScopes, screenToWorld, nodeGates, resolveStrokeWidth, resolveUnit, axisUnits, resolveScoped } from '@weasel-js/core';
3
+ import { pointInPolygon, invert, mat3, distance2, rectContainsPointHalfOpen, applyToPoint, pxExtent, PATH_M, PATH_L, PATH_Z, pxExtentInFrame } from '@weasel-js/geom';
4
4
 
5
5
  // src/grid/roundToCell.ts
6
6
  function roundToCell(value, cellSize) {
@@ -592,26 +592,27 @@ function createGuidesLayer(opts) {
592
592
  const guides = opts.getGuides();
593
593
  const gaps = opts.getGaps?.() ?? [];
594
594
  if (guides.length === 0 && gaps.length === 0) return [];
595
- const sx = (x) => (x - view.x) * view.scale.x;
596
- const sy = (y) => (y - view.y) * view.scale.y;
597
595
  const out = [];
598
596
  for (const g of guides) {
599
597
  const span2 = spanned ? g.span : void 0;
600
598
  if (g.axis === "x") {
601
- const x = sx(g.offset);
599
+ const lo3 = viewWorldToScreen(view, { x: g.offset, y: span2?.min ?? 0 });
600
+ const x = lo3.x;
602
601
  if (x < -lineWidth || x > dims.width + lineWidth) continue;
603
- const path = span2 ? tickedSegment(x, sy(span2.min), x, sy(span2.max), ticks) : tickedSegment(x, 0, x, dims.height, 0);
602
+ const path = span2 ? tickedSegment(x, lo3.y, x, viewWorldToScreen(view, { x: g.offset, y: span2.max }).y, ticks) : tickedSegment(x, 0, x, dims.height, 0);
604
603
  out.push({ kind: "path", path, stroke });
605
604
  } else {
606
- const y = sy(g.offset);
605
+ const lo3 = viewWorldToScreen(view, { x: span2?.min ?? 0, y: g.offset });
606
+ const y = lo3.y;
607
607
  if (y < -lineWidth || y > dims.height + lineWidth) continue;
608
- const path = span2 ? tickedSegment(sx(span2.min), y, sx(span2.max), y, ticks) : tickedSegment(0, y, dims.width, y, 0);
608
+ const path = span2 ? tickedSegment(lo3.x, y, viewWorldToScreen(view, { x: span2.max, y: g.offset }).x, y, ticks) : tickedSegment(0, y, dims.width, y, 0);
609
609
  out.push({ kind: "path", path, stroke });
610
610
  }
611
611
  }
612
612
  for (const g of gaps) {
613
- const [x0, y0, x1, y1] = g.axis === "x" ? [sx(g.min), sy(g.at), sx(g.max), sy(g.at)] : [sx(g.at), sy(g.min), sx(g.at), sy(g.max)];
614
- out.push(...measuredSegmentCommands(x0, y0, x1, y1, ticks, gapStroke, format?.(g.max - g.min) ?? null, gapColor));
613
+ const a = viewWorldToScreen(view, g.axis === "x" ? { x: g.min, y: g.at } : { x: g.at, y: g.min });
614
+ const b = viewWorldToScreen(view, g.axis === "x" ? { x: g.max, y: g.at } : { x: g.at, y: g.max });
615
+ out.push(...measuredSegmentCommands(a.x, a.y, b.x, b.y, ticks, gapStroke, format?.(g.max - g.min) ?? null, gapColor));
615
616
  }
616
617
  return out;
617
618
  }
@@ -942,8 +943,6 @@ function extentAcross(q, p, axis, delta) {
942
943
  const lo3 = c === "x" ? landed.x : landed.y;
943
944
  return [lo3, lo3 + (c === "x" ? landed.width : landed.height)];
944
945
  }
945
-
946
- // src/sources/spacing.ts
947
946
  var TRANSLATE = [
948
947
  { axis: "x", edge: "both", rate: { x: 1, y: 0 } },
949
948
  { axis: "y", edge: "both", rate: { x: 0, y: 1 } }
@@ -952,9 +951,9 @@ function movingSides(q) {
952
951
  return q.sides ? q.sides.map((s) => ({ axis: s.axis, edge: s.side, rate: s.rate })) : TRANSLATE;
953
952
  }
954
953
  var measureAll = (boxes) => ({ boxes, x: measureGapSpans(boxes, "x"), y: measureGapSpans(boxes, "y") });
955
- function gapMark(g, color) {
954
+ function gapMark(g, color, magnification) {
956
955
  const ends = g.axis === "x" ? { from: { x: g.min, y: g.at }, to: { x: g.max, y: g.at } } : { from: { x: g.at, y: g.min }, to: { x: g.at, y: g.max } };
957
- return { kind: "gap", ...ends, value: g.max - g.min, ...color === void 0 ? {} : { color } };
956
+ return { kind: "gap", ...ends, value: (g.max - g.min) / magnification, ...color === void 0 ? {} : { color } };
958
957
  }
959
958
  function spacingSnapSource(opts = {}) {
960
959
  const fromScene = cachedPerScene(measureAll, opts.filter);
@@ -971,6 +970,7 @@ function spacingSnapSource(opts = {}) {
971
970
  const reach = q.reachWorld(q.reachPx);
972
971
  const refs = { x: referenceGaps(box, measured.x), y: referenceGaps(box, measured.y) };
973
972
  const seen = /* @__PURE__ */ new Set();
973
+ const magnification = q.scene && q.ids?.length ? sceneMagnification(q.scene, q.ids.map(asNodeId)) : 1;
974
974
  for (const { axis, edge, rate } of movingSides(q)) {
975
975
  const speed = Math.hypot(rate.x, rate.y);
976
976
  for (const o of spacingOffers(box, axis, edge, measured.boxes, refs[axis])) {
@@ -982,7 +982,7 @@ function spacingSnapSource(opts = {}) {
982
982
  locus: sideLine(probe.at, rate, o.delta),
983
983
  mark: (delta) => {
984
984
  const landed = landedBox(q, delta) ?? box;
985
- return equalGaps(landed, axis, o.size, measured.boxes, refs[axis]).map((g) => gapMark(g, opts.color));
985
+ return equalGaps(landed, axis, o.size, measured.boxes, refs[axis]).map((g) => gapMark(g, opts.color, magnification));
986
986
  }
987
987
  };
988
988
  }
@@ -1033,10 +1033,13 @@ function measureAxis(from, to, axis, out) {
1033
1033
  }
1034
1034
 
1035
1035
  // src/spacingHints/distanceReadout.ts
1036
- function marksOf(r, color) {
1036
+ function marksOf(r, color, magnification) {
1037
1037
  const c = color === void 0 ? {} : { color };
1038
1038
  return [
1039
- ...r.gaps.map((g) => g.axis === "x" ? { kind: "distance", from: { x: g.min, y: g.at }, to: { x: g.max, y: g.at }, value: g.max - g.min, ...c } : { kind: "distance", from: { x: g.at, y: g.min }, to: { x: g.at, y: g.max }, value: g.max - g.min, ...c }),
1039
+ ...r.gaps.map((g) => {
1040
+ const value = (g.max - g.min) / magnification;
1041
+ return g.axis === "x" ? { kind: "distance", from: { x: g.min, y: g.at }, to: { x: g.max, y: g.at }, value, ...c } : { kind: "distance", from: { x: g.at, y: g.min }, to: { x: g.at, y: g.max }, value, ...c };
1042
+ }),
1040
1043
  ...r.leaders.flatMap((l) => {
1041
1044
  if (l.span === void 0) return [];
1042
1045
  return [l.axis === "x" ? { kind: "line", from: { x: l.offset, y: l.span.min }, to: { x: l.offset, y: l.span.max }, ...c } : { kind: "line", from: { x: l.span.min, y: l.offset }, to: { x: l.span.max, y: l.offset }, ...c }];
@@ -1061,10 +1064,10 @@ function distanceReadout(opts = {}) {
1061
1064
  const modifier = opts.modifier ?? "alt";
1062
1065
  let shown = EMPTY;
1063
1066
  let store = null;
1064
- const show = (next) => {
1067
+ const show = (next, magnification = 1) => {
1065
1068
  if (next === shown || next.gaps.length === 0 && shown.gaps.length === 0) return;
1066
1069
  shown = next;
1067
- store?.set(marksOf(next, opts.color));
1070
+ store?.set(marksOf(next, opts.color, magnification));
1068
1071
  };
1069
1072
  const action = {
1070
1073
  id: `${id}.measure`,
@@ -1084,7 +1087,8 @@ function distanceReadout(opts = {}) {
1084
1087
  const hit = nodeAtPoint(p.world, subtreeOf(scene, ids));
1085
1088
  const from = worldUnionOf(scene, ids, { poseDescriptor });
1086
1089
  const [to] = hit === null ? [] : worldBoundsOf(scene, [hit], { poseDescriptor });
1087
- show(from === null || to === void 0 ? EMPTY : measureDistances(from, to));
1090
+ if (from === null || to === void 0) show(EMPTY);
1091
+ else show(measureDistances(from, to), sceneMagnification(scene, [...ids, hit]));
1088
1092
  }
1089
1093
  }
1090
1094
  };
@@ -1132,19 +1136,12 @@ function createSpacingHintsPreset(opts = {}) {
1132
1136
  if (opts.readout !== false) contributions.push(distanceReadout({ ...opts.readout, ...color }));
1133
1137
  return { id, snapSources, contributions };
1134
1138
  }
1135
-
1136
- // src/layout/snaps.ts
1137
- function dist2(a, b) {
1138
- const dx = a.x - b.x;
1139
- const dy = a.y - b.y;
1140
- return dx * dx + dy * dy;
1141
- }
1142
1139
  function nearestOf(targets, pointer) {
1143
1140
  if (targets.length === 0) return null;
1144
1141
  let best = targets[0];
1145
- let bestD = dist2(best.origin, pointer);
1142
+ let bestD = distance2(best.origin, pointer);
1146
1143
  for (let i = 1; i < targets.length; i++) {
1147
- const d = dist2(targets[i].origin, pointer);
1144
+ const d = distance2(targets[i].origin, pointer);
1148
1145
  if (d < bestD) {
1149
1146
  bestD = d;
1150
1147
  best = targets[i];
@@ -1164,18 +1161,15 @@ function nearestWithin(opts) {
1164
1161
  pickTarget(targets, pointer) {
1165
1162
  const got = nearestOf(targets, pointer);
1166
1163
  if (got === null) return null;
1167
- return dist2(got.origin, pointer) <= tol2 ? got : null;
1164
+ return distance2(got.origin, pointer) <= tol2 ? got : null;
1168
1165
  }
1169
1166
  };
1170
1167
  }
1171
- function rectContains(r, p) {
1172
- return p.x >= r.x && p.x < r.x + r.width && p.y >= r.y && p.y < r.y + r.height;
1173
- }
1174
1168
  function containedThenNearest() {
1175
1169
  return {
1176
1170
  pickTarget(targets, pointer) {
1177
1171
  for (const t of targets) {
1178
- if (t.hitBounds && rectContains(t.hitBounds, pointer)) return t;
1172
+ if (t.hitBounds && rectContainsPointHalfOpen(t.hitBounds, pointer.x, pointer.y)) return t;
1179
1173
  }
1180
1174
  return nearestOf(targets, pointer);
1181
1175
  }
@@ -1188,8 +1182,8 @@ function cellAt() {
1188
1182
  return {
1189
1183
  pickTarget(targets, pointer) {
1190
1184
  for (const t of targets) {
1191
- if (t.hitBounds && rectContains(t.hitBounds, pointer)) return t;
1192
- if (isCellMeta(t.meta) && rectContains(t.meta.cellRect, pointer)) return t;
1185
+ if (t.hitBounds && rectContainsPointHalfOpen(t.hitBounds, pointer.x, pointer.y)) return t;
1186
+ if (isCellMeta(t.meta) && rectContainsPointHalfOpen(t.meta.cellRect, pointer.x, pointer.y)) return t;
1193
1187
  }
1194
1188
  return nearestOf(targets, pointer);
1195
1189
  }