lispgram 0.10.0 → 0.10.3

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.
Files changed (3) hide show
  1. package/README.md +11 -5
  2. package/dist/index.js +331 -2
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -118,10 +118,11 @@ npm install lispgram
118
118
  <script type="module">
119
119
  import lispgram from "lispgram";
120
120
  lispgram.initialize({
121
- startOnLoad: true,
122
- showArrowGlyphs: true,
123
- clickToFocus: true
124
- });
121
+ startOnLoad: true,
122
+ showArrowGlyphs: true,
123
+ clickToFocus: true,
124
+ zoom: true
125
+ });
125
126
  </script>
126
127
  ```
127
128
 
@@ -226,6 +227,8 @@ import { render, renderElement, initialize, createDiagramSvg } from "lispgram/la
226
227
 
227
228
  `render(target, source, options?)` renders Lispgram or NCF into a DOM target. `renderElement(sourceElement, options?)` renders one source element. `initialize(options?)` auto-renders matching elements such as `<pre class="lispgram">`. `createDiagramSvg(doc, options?)` renders an already-normalized NCF document into an SVG element.
228
229
 
230
+ `options.zoom` is a boolean that controls the built-in Shift navigation tools. The default is `true`, which enables Shift + A + click zoom-to-target, cursor-centered Shift + wheel zoom, and Shift + drag panning. Shift + A + click fits containers to about 80% of the viewport. Ordinary nodes zoom until the node height is about 8% of the view height. Arrows zoom to their arrow glyph/label area at about 2% of the view height. Use `zoom: false`, or `data-lispgram-zoom="false"` on auto-rendered `<pre>` blocks, to disable all built-in zoom and panning behavior.
231
+
229
232
  ### Interaction entry point
230
233
 
231
234
  ```js
@@ -286,6 +289,8 @@ When `clickToFocus` is enabled, clicking a node, compound/container, or arrow fo
286
289
 
287
290
  Click hit-testing uses a transparent interaction layer above the rendered diagram. Ordinary nodes are given priority over arrows, arrows over container interiors, and deeper containers over their ancestors. This keeps large ancestor containers clickable without letting them steal clicks from nested containers such as `BuildSystem`, `ExternalDependencies`, or `GuileBinding`.
288
291
 
292
+ The examples use `zoom: true`, which is also the default. It enables Shift + A + click zoom-to-target, Shift-wheel cursor zoom, and Shift-drag panning. Containers fit to roughly 80% of the viewport; ordinary nodes fit to about 8% of the view height; arrows fit to the arrow glyph/label area at about 2% of the view height. Pass `zoom: false` to disable built-in zoom and pan behavior.
293
+
289
294
  ## Demo
290
295
 
291
296
  go to repo root directory
@@ -308,10 +313,11 @@ navigate to examples/basic.html in browser
308
313
  </pre>
309
314
  <script type="module">
310
315
  import lispgram from "https://unpkg.com/lispgram@latest/dist/index.js";
311
- lispgram.initialize({
316
+ lispgram.initialize({
312
317
  startOnLoad: true,
313
318
  showArrowGlyphs: true,
314
319
  clickToFocus: true,
320
+ zoom: true,
315
321
  arrowGlyphRadius: 5.75
316
322
  });
317
323
  </script>
package/dist/index.js CHANGED
@@ -4772,7 +4772,7 @@ function renderLispgramRoute(svg, route, options) {
4772
4772
  }
4773
4773
 
4774
4774
  function renderLispgramHitLayer(svg, result, options = {}) {
4775
- if (options.clickToFocus === false) return;
4775
+ if (options.clickToFocus === false && !zoomEnabled(options)) return;
4776
4776
  const layer = svgEl('g', { class: 'lispgram-hit-layer', 'aria-hidden': 'true' });
4777
4777
 
4778
4778
  // Container hit regions are separate from the visible paint order. They are
@@ -4888,6 +4888,330 @@ function routeTouchesFocus(route, focus) {
4888
4888
  return endpointTouches(route.fromEndpoint, focus.id, focus.type) || endpointTouches(route.toEndpoint, focus.id, focus.type);
4889
4889
  }
4890
4890
 
4891
+ function zoomEnabled(options = {}) {
4892
+ return options.zoom !== false;
4893
+ }
4894
+
4895
+ const lispgramZoomKeyState = new WeakMap();
4896
+
4897
+ function normalizeKeyboardKey(event) {
4898
+ return String(event?.key || event?.code || '').toLowerCase();
4899
+ }
4900
+
4901
+ function eventHasZoomClickKey(svg, event) {
4902
+ if (event?.aKey === true) return true;
4903
+ const key = normalizeKeyboardKey(event);
4904
+ if (key === 'a' || key === 'keya') return true;
4905
+ return !!lispgramZoomKeyState.get(svg)?.aDown;
4906
+ }
4907
+
4908
+ function isZoomClickEvent(svg, event) {
4909
+ return !!event?.shiftKey && eventHasZoomClickKey(svg, event);
4910
+ }
4911
+
4912
+ function parseViewBox(svg) {
4913
+ const raw = svg?.getAttribute?.('viewBox') || '';
4914
+ const nums = raw.trim().split(/[\s,]+/).map(Number).filter(Number.isFinite);
4915
+ if (nums.length >= 4) return { x: nums[0], y: nums[1], w: nums[2], h: nums[3] };
4916
+ return null;
4917
+ }
4918
+
4919
+ function writeViewBox(svg, vb) {
4920
+ if (!svg || !vb) return;
4921
+ svg.setAttribute('viewBox', `${vb.x} ${vb.y} ${vb.w} ${vb.h}`);
4922
+ }
4923
+
4924
+ function svgDisplayAspect(svg, fallbackViewBox) {
4925
+ const attrW = Number(svg?.getAttribute?.('width'));
4926
+ const attrH = Number(svg?.getAttribute?.('height'));
4927
+ if (Number.isFinite(attrW) && attrW > 0 && Number.isFinite(attrH) && attrH > 0) return attrW / attrH;
4928
+ const rect = typeof svg?.getBoundingClientRect === 'function' ? svg.getBoundingClientRect() : null;
4929
+ if (rect?.width > 0 && rect?.height > 0) return rect.width / rect.height;
4930
+ return fallbackViewBox?.w && fallbackViewBox?.h ? fallbackViewBox.w / fallbackViewBox.h : 1;
4931
+ }
4932
+
4933
+ function svgPointFromEvent(svg, event, fallbackViewBox) {
4934
+ const vb = parseViewBox(svg) || fallbackViewBox;
4935
+ if (!vb) return null;
4936
+ const rect = typeof svg?.getBoundingClientRect === 'function' ? svg.getBoundingClientRect() : null;
4937
+ if (rect?.width > 0 && rect?.height > 0 && Number.isFinite(event?.clientX) && Number.isFinite(event?.clientY)) {
4938
+ return {
4939
+ x: vb.x + ((event.clientX - rect.left) / rect.width) * vb.w,
4940
+ y: vb.y + ((event.clientY - rect.top) / rect.height) * vb.h
4941
+ };
4942
+ }
4943
+ return { x: vb.x + vb.w / 2, y: vb.y + vb.h / 2 };
4944
+ }
4945
+
4946
+ function zoomViewBoxAt(svg, pivot, factor, originalViewBox, options = {}) {
4947
+ const vb = parseViewBox(svg) || originalViewBox;
4948
+ if (!vb || !pivot || !Number.isFinite(factor) || factor <= 0) return null;
4949
+ const minScale = Number.isFinite(Number(options.zoomMinScale)) ? Number(options.zoomMinScale) : 0.08;
4950
+ const maxScale = Number.isFinite(Number(options.zoomMaxScale)) ? Number(options.zoomMaxScale) : 6;
4951
+ const base = originalViewBox || vb;
4952
+ let nextW = vb.w * factor;
4953
+ let nextH = vb.h * factor;
4954
+ nextW = Math.max(base.w * minScale, Math.min(base.w * maxScale, nextW));
4955
+ nextH = Math.max(base.h * minScale, Math.min(base.h * maxScale, nextH));
4956
+ const actualX = nextW / vb.w;
4957
+ const actualY = nextH / vb.h;
4958
+ const next = {
4959
+ x: pivot.x - (pivot.x - vb.x) * actualX,
4960
+ y: pivot.y - (pivot.y - vb.y) * actualY,
4961
+ w: nextW,
4962
+ h: nextH
4963
+ };
4964
+ writeViewBox(svg, next);
4965
+ return next;
4966
+ }
4967
+
4968
+ function viewBoxForBox(svg, box, originalViewBox, options = {}) {
4969
+ if (!box || !originalViewBox) return null;
4970
+ const ratioRaw = Number(options.zoomFitRatio ?? options.containerZoomFitRatio ?? 0.8);
4971
+ const fitRatio = Number.isFinite(ratioRaw) && ratioRaw > 0 && ratioRaw < 1 ? ratioRaw : 0.8;
4972
+ const aspect = svgDisplayAspect(svg, originalViewBox) || 1;
4973
+ const minW = Number(options.containerZoomMinWidth ?? 160);
4974
+ const minH = Number(options.containerZoomMinHeight ?? 120);
4975
+ let w = Math.max(box.w / fitRatio, (box.h / fitRatio) * aspect, minW);
4976
+ let h = w / aspect;
4977
+ if (h < Math.max(box.h / fitRatio, minH)) {
4978
+ h = Math.max(box.h / fitRatio, minH);
4979
+ w = h * aspect;
4980
+ }
4981
+ const maxW = originalViewBox.w * (Number(options.containerZoomMaxScale ?? 1.05) || 1.05);
4982
+ const maxH = originalViewBox.h * (Number(options.containerZoomMaxScale ?? 1.05) || 1.05);
4983
+ if (w > maxW || h > maxH) {
4984
+ const scale = Math.max(w / maxW, h / maxH);
4985
+ w /= scale;
4986
+ h /= scale;
4987
+ }
4988
+ return { x: box.cx - w / 2, y: box.cy - h / 2, w, h };
4989
+ }
4990
+
4991
+ function finiteBounds(points) {
4992
+ const pts = (points || []).filter((p) => p && Number.isFinite(p.x) && Number.isFinite(p.y));
4993
+ if (!pts.length) return null;
4994
+ let left = Infinity;
4995
+ let right = -Infinity;
4996
+ let top = Infinity;
4997
+ let bottom = -Infinity;
4998
+ for (const p of pts) {
4999
+ left = Math.min(left, p.x);
5000
+ right = Math.max(right, p.x);
5001
+ top = Math.min(top, p.y);
5002
+ bottom = Math.max(bottom, p.y);
5003
+ }
5004
+ return { left, right, top, bottom, w: right - left, h: bottom - top, cx: (left + right) / 2, cy: (top + bottom) / 2 };
5005
+ }
5006
+
5007
+ function routeZoomBounds(route, options = {}) {
5008
+ const mid = route?.anchors?.label || route?.anchors?.mid || pointAlongPolyline(route?.points || [], 0.5);
5009
+ const glyphRadius = Number.isFinite(Number(options.arrowGlyphRadius)) ? Number(options.arrowGlyphRadius) : 5;
5010
+ const glyphDiameter = Math.max(10, glyphRadius * 2);
5011
+ const routeBounds = finiteBounds(route?.points || []);
5012
+ if (!mid) return routeBounds;
5013
+ const desired = Math.max(glyphDiameter, Number(options.arrowZoomTargetSize || 0) || 0);
5014
+ const half = desired / 2;
5015
+ return {
5016
+ left: mid.x - half,
5017
+ right: mid.x + half,
5018
+ top: mid.y - half,
5019
+ bottom: mid.y + half,
5020
+ w: desired,
5021
+ h: desired,
5022
+ cx: mid.x,
5023
+ cy: mid.y,
5024
+ routeBounds
5025
+ };
5026
+ }
5027
+
5028
+ function viewBoxForSmallBounds(svg, bounds, originalViewBox, options = {}) {
5029
+ if (!bounds || !originalViewBox) return null;
5030
+ const aspect = svgDisplayAspect(svg, originalViewBox) || 1;
5031
+ const fractionRaw = Number(options.zoomTargetHeightFraction ?? options.smallZoomHeightFraction ?? 0.08);
5032
+ const fraction = Number.isFinite(fractionRaw) && fractionRaw > 0 && fractionRaw < 1 ? fractionRaw : 0.08;
5033
+ const minTargetH = Number.isFinite(Number(options.smallZoomMinTargetHeight)) ? Number(options.smallZoomMinTargetHeight) : 10;
5034
+ const targetH = Math.max(bounds.h || 0, minTargetH);
5035
+ let h = targetH / fraction;
5036
+ let w = h * aspect;
5037
+ const minW = Number(options.smallZoomMinWidth ?? 120);
5038
+ const minH = Number(options.smallZoomMinHeight ?? 90);
5039
+ if (w < minW) { w = minW; h = w / aspect; }
5040
+ if (h < minH) { h = minH; w = h * aspect; }
5041
+ return { x: bounds.cx - w / 2, y: bounds.cy - h / 2, w, h };
5042
+ }
5043
+
5044
+ function viewBoxForZoomTarget(svg, target, result, originalViewBox, options = {}) {
5045
+ if (!target || !originalViewBox) return null;
5046
+ if (target.type === 'node') {
5047
+ const box = result.boxes?.get?.(target.id);
5048
+ if (!box) return null;
5049
+ if (box.kind === 'container') return viewBoxForBox(svg, box, originalViewBox, options);
5050
+ return viewBoxForSmallBounds(svg, box, originalViewBox, options);
5051
+ }
5052
+ if (target.type === 'edge') {
5053
+ const route = result.routes?.get?.(target.id);
5054
+ const edgeOptions = {
5055
+ ...options,
5056
+ zoomTargetHeightFraction: options.arrowZoomHeightFraction ?? options.edgeZoomHeightFraction ?? 0.02,
5057
+ smallZoomMinTargetHeight: options.arrowZoomMinTargetHeight ?? options.edgeZoomMinTargetHeight ?? 10
5058
+ };
5059
+ return viewBoxForSmallBounds(svg, routeZoomBounds(route, edgeOptions), originalViewBox, edgeOptions);
5060
+ }
5061
+ return null;
5062
+ }
5063
+
5064
+ function enableLispgramZoom(svg, result, options = {}) {
5065
+ if (!svg || !result || !zoomEnabled(options)) return;
5066
+ const originalViewBox = parseViewBox(svg) || result.viewBox || null;
5067
+ if (!originalViewBox) return;
5068
+ let currentViewBox = { ...originalViewBox };
5069
+ const animationMs = Number.isFinite(Number(options.zoomAnimationMs)) ? Number(options.zoomAnimationMs) : 160;
5070
+
5071
+ function setViewBox(vb) {
5072
+ if (!vb) return null;
5073
+ currentViewBox = { ...vb };
5074
+ if (svg.style && animationMs > 0) svg.style.transition = `viewBox ${animationMs}ms ease`;
5075
+ writeViewBox(svg, currentViewBox);
5076
+ return currentViewBox;
5077
+ }
5078
+
5079
+ function zoomToTarget(target) {
5080
+ return setViewBox(viewBoxForZoomTarget(svg, target, result, originalViewBox, options));
5081
+ }
5082
+
5083
+ function zoomToBox(id) {
5084
+ return zoomToTarget({ type: 'node', id });
5085
+ }
5086
+
5087
+ function zoomToEdge(id) {
5088
+ return zoomToTarget({ type: 'edge', id });
5089
+ }
5090
+
5091
+ function reset() {
5092
+ return setViewBox(originalViewBox);
5093
+ }
5094
+
5095
+ let suppressNextShiftClick = false;
5096
+ const keyState = { aDown: false };
5097
+ lispgramZoomKeyState.set(svg, keyState);
5098
+
5099
+ function updateZoomKeyState(event, value) {
5100
+ const key = normalizeKeyboardKey(event);
5101
+ if (key === 'a' || key === 'keya') keyState.aDown = value;
5102
+ }
5103
+
5104
+ const keyTargets = [];
5105
+ const ownerDocument = svg.ownerDocument || (typeof document !== 'undefined' ? document : null);
5106
+ if (ownerDocument?.defaultView?.addEventListener) keyTargets.push(ownerDocument.defaultView);
5107
+ if (ownerDocument?.addEventListener) keyTargets.push(ownerDocument);
5108
+ for (const target of keyTargets) {
5109
+ target.addEventListener('keydown', (event) => updateZoomKeyState(event, true));
5110
+ target.addEventListener('keyup', (event) => updateZoomKeyState(event, false));
5111
+ target.addEventListener('blur', () => { keyState.aDown = false; });
5112
+ }
5113
+
5114
+ if (typeof svg.addEventListener === 'function') {
5115
+ svg.addEventListener('wheel', (event) => {
5116
+ if (!event?.shiftKey) return;
5117
+ if (typeof event.preventDefault === 'function') event.preventDefault();
5118
+ const scale = Number.isFinite(Number(options.zoomWheelScale)) ? Number(options.zoomWheelScale) : 1.05;
5119
+ const delta = Number(event.deltaY || 0);
5120
+ const factor = delta < 0 ? 1 / scale : scale;
5121
+ const pivot = svgPointFromEvent(svg, event, currentViewBox);
5122
+ currentViewBox = zoomViewBoxAt(svg, pivot, factor, originalViewBox, options) || currentViewBox;
5123
+ }, { passive: false });
5124
+
5125
+ let dragState = null;
5126
+ const dragThreshold = Number.isFinite(Number(options.zoomDragThreshold)) ? Number(options.zoomDragThreshold) : 3;
5127
+
5128
+ function updateDrag(event) {
5129
+ if (!dragState) return;
5130
+ const rect = typeof svg.getBoundingClientRect === 'function' ? svg.getBoundingClientRect() : null;
5131
+ if (!rect?.width || !rect?.height) return;
5132
+ const dx = Number(event.clientX) - dragState.startClientX;
5133
+ const dy = Number(event.clientY) - dragState.startClientY;
5134
+ if (!dragState.moved && Math.hypot(dx, dy) >= dragThreshold) dragState.moved = true;
5135
+ if (typeof event.preventDefault === 'function') event.preventDefault();
5136
+ const next = {
5137
+ x: dragState.startViewBox.x - dx / rect.width * dragState.startViewBox.w,
5138
+ y: dragState.startViewBox.y - dy / rect.height * dragState.startViewBox.h,
5139
+ w: dragState.startViewBox.w,
5140
+ h: dragState.startViewBox.h
5141
+ };
5142
+ currentViewBox = next;
5143
+ writeViewBox(svg, currentViewBox);
5144
+ }
5145
+
5146
+ function endDrag(event) {
5147
+ if (!dragState) return;
5148
+ if (dragState.moved) {
5149
+ suppressNextShiftClick = true;
5150
+ if (typeof event?.preventDefault === 'function') event.preventDefault();
5151
+ }
5152
+ if (dragState.pointerId != null && typeof svg.releasePointerCapture === 'function') {
5153
+ try { svg.releasePointerCapture(dragState.pointerId); } catch {}
5154
+ }
5155
+ dragState = null;
5156
+ if (svg.style) svg.style.cursor = '';
5157
+ setTimeout(() => { suppressNextShiftClick = false; }, 0);
5158
+ }
5159
+
5160
+ if (typeof svg.addEventListener === 'function') {
5161
+ svg.addEventListener('pointerdown', (event) => {
5162
+ if (!event?.shiftKey) return;
5163
+ if (isZoomClickEvent(svg, event)) return;
5164
+ if (event.button != null && event.button !== 0) return;
5165
+ const start = parseViewBox(svg) || currentViewBox;
5166
+ if (!start) return;
5167
+ dragState = {
5168
+ pointerId: event.pointerId,
5169
+ startClientX: Number(event.clientX),
5170
+ startClientY: Number(event.clientY),
5171
+ startViewBox: { ...start },
5172
+ moved: false
5173
+ };
5174
+ if (typeof svg.setPointerCapture === 'function' && event.pointerId != null) {
5175
+ try { svg.setPointerCapture(event.pointerId); } catch {}
5176
+ }
5177
+ if (svg.style) svg.style.cursor = 'grabbing';
5178
+ if (typeof event.preventDefault === 'function') event.preventDefault();
5179
+ }, { passive: false });
5180
+ svg.addEventListener('pointermove', updateDrag, { passive: false });
5181
+ svg.addEventListener('pointerup', endDrag, { passive: false });
5182
+ svg.addEventListener('pointercancel', endDrag, { passive: false });
5183
+ }
5184
+ }
5185
+
5186
+ {
5187
+ const hitboxes = [];
5188
+ walkSvgElements(svg, (node) => {
5189
+ if (typeof node.getAttribute !== 'function') return;
5190
+ const cls = node.getAttribute('class');
5191
+ if (cls === 'lispgram-compound-hitbox' || cls === 'lispgram-node-hitbox') {
5192
+ const id = node.getAttribute('data-node-id');
5193
+ if (result.boxes?.has?.(id)) hitboxes.push([node, { type: 'node', id }]);
5194
+ } else if (cls === 'lispgram-edge-hitbox') {
5195
+ const id = node.getAttribute('data-edge-id');
5196
+ if (result.routes?.has?.(id)) hitboxes.push([node, { type: 'edge', id }]);
5197
+ }
5198
+ });
5199
+ for (const [el, target] of hitboxes) {
5200
+ if (typeof el.addEventListener !== 'function') continue;
5201
+ el.addEventListener('click', (event) => {
5202
+ if (!isZoomClickEvent(svg, event)) return;
5203
+ if (suppressNextShiftClick) return;
5204
+ if (typeof event.preventDefault === 'function') event.preventDefault();
5205
+ if (typeof event.stopPropagation === 'function') event.stopPropagation();
5206
+ if (typeof event.stopImmediatePropagation === 'function') event.stopImmediatePropagation();
5207
+ zoomToTarget(target);
5208
+ });
5209
+ }
5210
+ }
5211
+
5212
+ svg.__lispgramZoom = { enabled: true, originalViewBox, get viewBox() { return currentViewBox; }, reset, zoomToBox, zoomToEdge, zoomToTarget };
5213
+ }
5214
+
4891
5215
  function enableLispgramClickFocus(svg, result, options = {}) {
4892
5216
  if (!svg || !result || options.clickToFocus === false) return;
4893
5217
  const dimOpacity = Number.isFinite(Number(options.focusDimOpacity)) ? Number(options.focusDimOpacity) : 0.12;
@@ -4960,6 +5284,7 @@ function enableLispgramClickFocus(svg, result, options = {}) {
4960
5284
  if (typeof el.addEventListener !== 'function') continue;
4961
5285
  if (el.style) el.style.cursor = 'pointer';
4962
5286
  el.addEventListener('click', (event) => {
5287
+ if (zoomEnabled(options) && event?.shiftKey && result.boxes?.has?.(id)) return;
4963
5288
  stop(event);
4964
5289
  const next = { type: 'node', id };
4965
5290
  applyFocus(sameFocus(currentFocus, next) ? null : next);
@@ -4972,6 +5297,7 @@ function enableLispgramClickFocus(svg, result, options = {}) {
4972
5297
  if (typeof el.addEventListener !== 'function') continue;
4973
5298
  if (el.style) el.style.cursor = 'pointer';
4974
5299
  el.addEventListener('click', (event) => {
5300
+ if (zoomEnabled(options) && event?.shiftKey && result.routes?.has?.(id)) return;
4975
5301
  stop(event);
4976
5302
  const next = { type: 'edge', id };
4977
5303
  applyFocus(sameFocus(currentFocus, next) ? null : next);
@@ -4999,6 +5325,7 @@ function createLispgramConstraintSvg(result, options = {}) {
4999
5325
  for (const route of result.routes.values()) renderLispgramRoute(svg, route, options);
5000
5326
  renderLispgramHitLayer(svg, result, options);
5001
5327
  enableLispgramClickFocus(svg, result, options);
5328
+ enableLispgramZoom(svg, result, options);
5002
5329
  return svg;
5003
5330
  }
5004
5331
 
@@ -5207,6 +5534,7 @@ function elementRenderOptions(sourceElement, options = {}) {
5207
5534
  ...options,
5208
5535
  showArrowGlyphs: parseBooleanOption(data.lispgramArrowGlyphs, options.showArrowGlyphs ?? false),
5209
5536
  clickToFocus: parseBooleanOption(data.lispgramClickFocus, options.clickToFocus ?? true),
5537
+ zoom: parseBooleanOption(data.lispgramZoom, options.zoom ?? true),
5210
5538
  arrowGlyphRadius: parseNumericOption(data.lispgramArrowGlyphRadius, options.arrowGlyphRadius),
5211
5539
  diagramId: data.lispgramDiagram || data.diagramId || options.diagramId || options.name || options.id || sourceElement?.id || undefined
5212
5540
  };
@@ -5277,6 +5605,7 @@ function initialize(options = {}) {
5277
5605
  showNCF = false,
5278
5606
  showArrowGlyphs = false,
5279
5607
  clickToFocus = true,
5608
+ zoom = true,
5280
5609
  arrowGlyphRadius = 5.75,
5281
5610
  height,
5282
5611
  width,
@@ -5288,7 +5617,7 @@ function initialize(options = {}) {
5288
5617
  for (const element of elements) {
5289
5618
  if (element.dataset.lispgramMounted === 'true') continue;
5290
5619
  try {
5291
- renderElement(element, { showNCF, showArrowGlyphs, clickToFocus, arrowGlyphRadius, height, width, diagramId });
5620
+ renderElement(element, { showNCF, showArrowGlyphs, clickToFocus, zoom, arrowGlyphRadius, height, width, diagramId });
5292
5621
  element.dataset.lispgramMounted = 'true';
5293
5622
  } catch {
5294
5623
  element.dataset.lispgramMounted = 'error';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lispgram",
3
- "version": "0.10.0",
3
+ "version": "0.10.3",
4
4
  "description": "A small public Lispgram surface compiler, constraint-layout SVG renderer, and interaction API.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",