cytoscape-canvas-underlay 1.2.3 → 1.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.
- package/README.md +15 -7
- package/package.json +1 -1
- package/src/DrawingOverlay.js +33 -43
- package/src/index.js +1 -2
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ A [Cytoscape.js](https://js.cytoscape.org) plugin for rendering image/PDF backgr
|
|
|
8
8
|
- **Pan clamping** — hard boundary or iOS-style rubber-band with spring-back
|
|
9
9
|
- **Minimap** — DOM-based crisp image rendering, two viewport styles (`dim` / `rect`), auto-hide, full customization
|
|
10
10
|
- **Adaptive PDF quality** — low-quality render during interaction, high-quality on idle
|
|
11
|
-
- **Rich navigation** — `fit`, `fitAll`, `
|
|
11
|
+
- **Rich navigation** — `fit`, `fitAll`, `panToRegion`, coordinate conversion
|
|
12
12
|
- **Layer visibility** — independently show/hide drawing background and graph layer
|
|
13
13
|
- **CSS filters** — invert, brightness, contrast, saturate, grayscale (invert applied first so brightness/contrast work correctly on inverted images)
|
|
14
14
|
- **Rotation** — rotate main or additional drawings (0, 90, 180, 270 degrees)
|
|
@@ -147,13 +147,14 @@ api.off('zoom'); // remove all zoom handlers
|
|
|
147
147
|
### Navigation
|
|
148
148
|
|
|
149
149
|
```js
|
|
150
|
-
api.fit(); // fit main drawing
|
|
150
|
+
api.fit(); // fit main drawing (instant)
|
|
151
|
+
api.fit({ animate: true }); // fit with animation (300ms)
|
|
152
|
+
api.fit({ padding: 50 }); // fit with 50px padding
|
|
153
|
+
api.fit({ animate: true, duration: 500, easing: 'ease-out' });
|
|
151
154
|
api.fitToDrawing('trace-1'); // fit specific drawing
|
|
152
155
|
api.fitAll(); // fit all drawings
|
|
153
156
|
api.panTo(500, 300); // center on world coordinate
|
|
154
157
|
api.panTo(500, 300, 2.0); // center + set zoom
|
|
155
|
-
api.panToElement('node-id'); // center on cytoscape element
|
|
156
|
-
api.panToElement(cy.$('#node-id')); // also accepts element reference
|
|
157
158
|
api.panToRegion(100, 100, 400, 300); // fit a world-coordinate region
|
|
158
159
|
```
|
|
159
160
|
|
|
@@ -255,7 +256,7 @@ const inside = api.isPointInDrawing(world.x, world.y);
|
|
|
255
256
|
| Option | Type | Default | Description |
|
|
256
257
|
|--------|------|---------|-------------|
|
|
257
258
|
| `fitOnLoad` | `boolean` | `true` | Auto-fit drawing to viewport on load |
|
|
258
|
-
| `fitPadding` | `number` | `
|
|
259
|
+
| `fitPadding` | `number` | `0` | Default padding for fit operations (px) |
|
|
259
260
|
|
|
260
261
|
### Pan Clamping
|
|
261
262
|
|
|
@@ -368,11 +369,10 @@ These still work but the `on()`/`off()` event emitter is preferred.
|
|
|
368
369
|
|
|
369
370
|
| Method | Description |
|
|
370
371
|
|--------|-------------|
|
|
371
|
-
| `fit(
|
|
372
|
+
| `fit(opts?)` | Fit main drawing to viewport. Options: `{ animate, padding, duration, easing }` |
|
|
372
373
|
| `fitToDrawing(id, padding?)` | Fit a specific additional drawing to viewport |
|
|
373
374
|
| `fitAll(padding?)` | Fit all drawings (main + additional) to viewport |
|
|
374
375
|
| `panTo(x, y, zoom?)` | Center viewport on world coordinate, optionally set zoom |
|
|
375
|
-
| `panToElement(eleOrId, padding?)` | Fit a cytoscape element in viewport (accepts ID string or element) |
|
|
376
376
|
| `panToRegion(x, y, w, h, padding?)` | Fit a world-coordinate region in viewport |
|
|
377
377
|
|
|
378
378
|
### Visibility
|
|
@@ -440,6 +440,14 @@ These still work but the `on()`/`off()` event emitter is preferred.
|
|
|
440
440
|
|
|
441
441
|
## Changelog
|
|
442
442
|
|
|
443
|
+
### 1.3.0
|
|
444
|
+
|
|
445
|
+
- **Breaking**: `fit()` now accepts an options object instead of a padding number: `fit({ animate, padding, duration, easing })`. Calling `fit()` with no arguments still works (uses defaults).
|
|
446
|
+
- **Breaking**: Removed `panToElement()` — use application-level implementation for element navigation with custom zoom/animation logic.
|
|
447
|
+
- **Changed**: Default `fitPadding` changed from `50` to `0`.
|
|
448
|
+
- **Added**: `fit()` now supports `animate` option with configurable `duration` (default 300ms) and `easing` (default `ease-in-out-cubic`).
|
|
449
|
+
- **Added**: `fit()` now calls `cy.resize()` before calculating dimensions.
|
|
450
|
+
|
|
443
451
|
### 1.2.3
|
|
444
452
|
|
|
445
453
|
- **Fix**: `_springBackIfNeeded` now respects `panClamp: false`. Previously, setting `panClamp: false` at runtime disabled hard clamping but the soft spring-back animation on mouse release still fired, snapping the viewport back to drawing bounds. This made it impossible to programmatically disable pan clamping (e.g., during `panToElement` animations).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cytoscape-canvas-underlay",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Cytoscape.js plugin for rendering image/PDF canvas underlay behind graph nodes with synchronized zoom and pan",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"module": "src/index.js",
|
package/src/DrawingOverlay.js
CHANGED
|
@@ -24,7 +24,7 @@ const DEFAULTS = {
|
|
|
24
24
|
// ── Layout ──
|
|
25
25
|
zIndex: 0, // Canvas z-index within overlay container
|
|
26
26
|
fitOnLoad: true, // Auto-fit drawing to viewport on load
|
|
27
|
-
fitPadding:
|
|
27
|
+
fitPadding: 0, // Padding (px) for fit operations
|
|
28
28
|
|
|
29
29
|
// ── Pan Clamping ──
|
|
30
30
|
panClamp: false, // Prevent panning too far from drawing bounds
|
|
@@ -295,6 +295,15 @@ export class DrawingOverlay {
|
|
|
295
295
|
this._enforceLimits();
|
|
296
296
|
this._draw();
|
|
297
297
|
if (this._minimap) this._minimap.render();
|
|
298
|
+
|
|
299
|
+
// Schedule high-quality PDF re-render at current zoom level
|
|
300
|
+
const hasPdf = this._main.isPdf || [...this._drawings.values()].some(d => d.isPdf && d.visible);
|
|
301
|
+
if (hasPdf) {
|
|
302
|
+
if (this._qualityTimer) clearTimeout(this._qualityTimer);
|
|
303
|
+
this._qualityTimer = setTimeout(() => {
|
|
304
|
+
this._reRenderAllPdfs().then(() => this._draw());
|
|
305
|
+
}, this.opts.qualityDelay);
|
|
306
|
+
}
|
|
298
307
|
};
|
|
299
308
|
this._onResize = () => {
|
|
300
309
|
this._setupCanvas();
|
|
@@ -712,22 +721,31 @@ export class DrawingOverlay {
|
|
|
712
721
|
═══════════════════════════════════════ */
|
|
713
722
|
|
|
714
723
|
/** Fit the main drawing to viewport. */
|
|
715
|
-
fit(
|
|
724
|
+
fit({
|
|
725
|
+
animate = false,
|
|
726
|
+
padding = this.opts.fitPadding,
|
|
727
|
+
duration = 300,
|
|
728
|
+
easing = 'ease-in-out-cubic',
|
|
729
|
+
} = {}) {
|
|
716
730
|
if (!this._main.w || !this._main.h) return;
|
|
717
|
-
const
|
|
718
|
-
const container = this.cy.container().getBoundingClientRect();
|
|
719
|
-
const scaleX = (container.width - pad * 2) / this._main.w;
|
|
720
|
-
const scaleY = (container.height - pad * 2) / this._main.h;
|
|
721
|
-
const zoom = Math.max(this.cy.minZoom(), Math.min(this.cy.maxZoom(),Math.min(scaleX, scaleY)));
|
|
731
|
+
const cy = this.cy;
|
|
722
732
|
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
733
|
+
cy.resize();
|
|
734
|
+
|
|
735
|
+
const container = cy.container().getBoundingClientRect();
|
|
736
|
+
const cw = container.width - padding * 2;
|
|
737
|
+
const ch = container.height - padding * 2;
|
|
738
|
+
if (cw <= 0 || ch <= 0) return;
|
|
739
|
+
|
|
740
|
+
const scale = Math.min(cw / this._main.w, ch / this._main.h);
|
|
741
|
+
const panX = Math.round(padding + (cw - this._main.w * scale) / 2);
|
|
742
|
+
const panY = Math.round(padding + (ch - this._main.h * scale) / 2);
|
|
743
|
+
|
|
744
|
+
if (animate) {
|
|
745
|
+
cy.animate({ zoom: scale, pan: { x: panX, y: panY }, duration, easing });
|
|
746
|
+
} else {
|
|
747
|
+
cy.viewport({ zoom: scale, pan: { x: panX, y: panY } });
|
|
748
|
+
}
|
|
731
749
|
}
|
|
732
750
|
|
|
733
751
|
/** Fit a specific additional drawing to viewport. */
|
|
@@ -793,34 +811,6 @@ export class DrawingOverlay {
|
|
|
793
811
|
});
|
|
794
812
|
}
|
|
795
813
|
|
|
796
|
-
/** Pan to center a cytoscape element in viewport. */
|
|
797
|
-
panToElement(eleOrId, padding) {
|
|
798
|
-
const cy = this.cy;
|
|
799
|
-
const ele = typeof eleOrId === 'string' ? cy.getElementById(eleOrId) : eleOrId;
|
|
800
|
-
if (!ele || ele.empty?.()) return;
|
|
801
|
-
|
|
802
|
-
const bb = ele.boundingBox();
|
|
803
|
-
const pad = padding ?? this.opts.fitPadding;
|
|
804
|
-
const container = cy.container().getBoundingClientRect();
|
|
805
|
-
|
|
806
|
-
// Calculate zoom to fit element
|
|
807
|
-
const scaleX = (container.width - pad * 2) / bb.w;
|
|
808
|
-
const scaleY = (container.height - pad * 2) / bb.h;
|
|
809
|
-
const zoom = Math.max(this.cy.minZoom(), Math.min(this.cy.maxZoom(),Math.min(scaleX, scaleY)));
|
|
810
|
-
|
|
811
|
-
const cx = (bb.x1 + bb.x2) / 2;
|
|
812
|
-
const cy_ = (bb.y1 + bb.y2) / 2;
|
|
813
|
-
|
|
814
|
-
this.cy.zoom({
|
|
815
|
-
level: zoom,
|
|
816
|
-
renderedPosition: { x: container.width / 2, y: container.height / 2 },
|
|
817
|
-
});
|
|
818
|
-
this.cy.pan({
|
|
819
|
-
x: container.width / 2 - cx * zoom,
|
|
820
|
-
y: container.height / 2 - cy_ * zoom,
|
|
821
|
-
});
|
|
822
|
-
}
|
|
823
|
-
|
|
824
814
|
/** Pan to a specific region of the drawing. */
|
|
825
815
|
panToRegion(x, y, w, h, padding) {
|
|
826
816
|
const pad = padding ?? this.opts.fitPadding;
|
package/src/index.js
CHANGED
|
@@ -38,11 +38,10 @@ function register(cytoscape) {
|
|
|
38
38
|
getRotation() { return overlay.getRotation(); },
|
|
39
39
|
|
|
40
40
|
// ── Navigation ──
|
|
41
|
-
fit(
|
|
41
|
+
fit(opts) { overlay.fit(opts); },
|
|
42
42
|
fitToDrawing(id, padding) { overlay.fitToDrawing(id, padding); },
|
|
43
43
|
fitAll(padding) { overlay.fitAll(padding); },
|
|
44
44
|
panTo(x, y, zoom) { overlay.panTo(x, y, zoom); },
|
|
45
|
-
panToElement(eleOrId, padding) { overlay.panToElement(eleOrId, padding); },
|
|
46
45
|
panToRegion(x, y, w, h, padding) { overlay.panToRegion(x, y, w, h, padding); },
|
|
47
46
|
|
|
48
47
|
// ── Visibility ──
|