@ngroznykh/papirus 0.9.11 → 0.9.13
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/core/DiagramRenderer.d.ts +9 -11
- package/dist/core/DiagramRenderer.d.ts.map +1 -1
- package/dist/core/DiagramSurface.d.ts +0 -2
- package/dist/core/DiagramSurface.d.ts.map +1 -1
- package/dist/core/InteractionManager.d.ts +5 -0
- package/dist/core/InteractionManager.d.ts.map +1 -1
- package/dist/core/NavigationManager.d.ts.map +1 -1
- package/dist/core/overlays/GridOverlay.d.ts.map +1 -1
- package/dist/core/overlays/MiniMap.d.ts +8 -0
- package/dist/core/overlays/MiniMap.d.ts.map +1 -1
- package/dist/core/overlays/RulersOverlay.d.ts +4 -0
- package/dist/core/overlays/RulersOverlay.d.ts.map +1 -1
- package/dist/elements/Edge.d.ts.map +1 -1
- package/dist/elements/Group.d.ts.map +1 -1
- package/dist/elements/TextLabel.d.ts.map +1 -1
- package/dist/elements/composite/CText.d.ts.map +1 -1
- package/dist/elements/edge/EdgeLabelRenderer.d.ts.map +1 -1
- package/dist/papirus.js +334 -130
- package/dist/papirus.js.map +1 -1
- package/dist/utils/adaptiveGridStep.d.ts +10 -0
- package/dist/utils/adaptiveGridStep.d.ts.map +1 -0
- package/dist/utils/pathViewport.d.ts +12 -0
- package/dist/utils/pathViewport.d.ts.map +1 -0
- package/dist/utils/screenText.d.ts +4 -0
- package/dist/utils/screenText.d.ts.map +1 -0
- package/package.json +1 -1
package/dist/papirus.js
CHANGED
|
@@ -1689,13 +1689,11 @@ var NavigationManager = class extends EventEmitter {
|
|
|
1689
1689
|
x: event.screenX,
|
|
1690
1690
|
y: event.screenY
|
|
1691
1691
|
};
|
|
1692
|
-
this.renderer.beginLowResPan();
|
|
1693
1692
|
this.emit("panStart");
|
|
1694
1693
|
}
|
|
1695
1694
|
endPan() {
|
|
1696
1695
|
this.isPanning = false;
|
|
1697
1696
|
this.panStart = null;
|
|
1698
|
-
this.renderer.endLowResPan();
|
|
1699
1697
|
this.emit("panEnd");
|
|
1700
1698
|
}
|
|
1701
1699
|
};
|
|
@@ -3222,6 +3220,20 @@ function measureTextLines(ctx, lines) {
|
|
|
3222
3220
|
for (const line of lines) maxWidth = Math.max(maxWidth, ctx.measureText(line).width);
|
|
3223
3221
|
return maxWidth;
|
|
3224
3222
|
}
|
|
3223
|
+
function readScale(ctx) {
|
|
3224
|
+
if (typeof ctx.getTransform !== "function") return null;
|
|
3225
|
+
const m = ctx.getTransform();
|
|
3226
|
+
if (m === null || typeof m.a !== "number") return null;
|
|
3227
|
+
return {
|
|
3228
|
+
a: m.a,
|
|
3229
|
+
b: typeof m.b === "number" ? m.b : 0
|
|
3230
|
+
};
|
|
3231
|
+
}
|
|
3232
|
+
function isScreenFontReadable(ctx, fontSize) {
|
|
3233
|
+
const m = readScale(ctx);
|
|
3234
|
+
if (m === null) return true;
|
|
3235
|
+
return fontSize * Math.hypot(m.a, m.b) >= 7;
|
|
3236
|
+
}
|
|
3225
3237
|
//#endregion
|
|
3226
3238
|
//#region src/elements/TextLabel.ts
|
|
3227
3239
|
var DEFAULT_INSET = 8;
|
|
@@ -3479,10 +3491,10 @@ var TextLabel = class {
|
|
|
3479
3491
|
default: startY = innerBounds.y + (innerBounds.height - totalHeight) / 2 + lineHeight / 2;
|
|
3480
3492
|
}
|
|
3481
3493
|
ctx.fillStyle = this._style.color ?? "#000000";
|
|
3494
|
+
if (!isScreenFontReadable(ctx, this._style.fontSize ?? 14)) return;
|
|
3482
3495
|
for (let i = 0; i < this._lines.length; i++) {
|
|
3483
|
-
const line = this._lines[i];
|
|
3484
3496
|
const y = startY + i * lineHeight;
|
|
3485
|
-
ctx.fillText(
|
|
3497
|
+
ctx.fillText(this._lines[i], x, y);
|
|
3486
3498
|
}
|
|
3487
3499
|
}
|
|
3488
3500
|
/**
|
|
@@ -6413,6 +6425,7 @@ function drawLegacyArrowHead(ctx, from, to) {
|
|
|
6413
6425
|
function renderEdgeLabel(ctx, options) {
|
|
6414
6426
|
const { label, path, background } = options;
|
|
6415
6427
|
if (!label || path.length < 2) return;
|
|
6428
|
+
if (!isScreenFontReadable(ctx, label.style.fontSize ?? 14)) return;
|
|
6416
6429
|
const labelCenter = getEdgeLabelPosition(options);
|
|
6417
6430
|
if (!labelCenter) return;
|
|
6418
6431
|
const rotation = getEdgeLabelRotation(options);
|
|
@@ -7062,7 +7075,7 @@ var Edge = class extends Element {
|
|
|
7062
7075
|
}
|
|
7063
7076
|
return pts;
|
|
7064
7077
|
};
|
|
7065
|
-
if (!(this._label !== void 0 && this._labelLineGap)) {
|
|
7078
|
+
if (!(this._label !== void 0 && this._labelLineGap && isScreenFontReadable(ctx, this._label.style.fontSize ?? 14))) {
|
|
7066
7079
|
const start = path[0];
|
|
7067
7080
|
const startNext = path[1];
|
|
7068
7081
|
const startAngle = Math.atan2(startNext.y - start.y, startNext.x - start.x);
|
|
@@ -7549,6 +7562,7 @@ var InteractionManager = class {
|
|
|
7549
7562
|
this.handledScrollbarMouseDown = false;
|
|
7550
7563
|
this.overlayDragSession = null;
|
|
7551
7564
|
this.handledOverlayMouseDown = false;
|
|
7565
|
+
this.editHoverSuspendedForPan = false;
|
|
7552
7566
|
this.renderer = options.renderer;
|
|
7553
7567
|
this.navigationOnly = options.navigationOnly ?? false;
|
|
7554
7568
|
this.inputHandler = new InputHandler({
|
|
@@ -7732,7 +7746,7 @@ var InteractionManager = class {
|
|
|
7732
7746
|
setupEvents() {
|
|
7733
7747
|
this.overlayCleanup = this.renderer.addOverlayRenderer((ctx) => {
|
|
7734
7748
|
this.selectionManager.renderSelectionRect(ctx);
|
|
7735
|
-
if (!this.navigationOnly) {
|
|
7749
|
+
if (!this.navigationOnly && !this.navigationManager.panning) {
|
|
7736
7750
|
this.dragManager.renderAlignmentGuides(ctx);
|
|
7737
7751
|
this.connectionManager.renderPreview(ctx);
|
|
7738
7752
|
this.connectionManager.renderHoverAnchors(ctx);
|
|
@@ -7903,7 +7917,7 @@ var InteractionManager = class {
|
|
|
7903
7917
|
if (event.button === 0) {
|
|
7904
7918
|
if (this.navigationOnly) {
|
|
7905
7919
|
this.selectionManager.clearSelection();
|
|
7906
|
-
this.
|
|
7920
|
+
this.beginBackgroundPan(event);
|
|
7907
7921
|
return;
|
|
7908
7922
|
}
|
|
7909
7923
|
if (hitElement === void 0) {
|
|
@@ -7912,11 +7926,14 @@ var InteractionManager = class {
|
|
|
7912
7926
|
return;
|
|
7913
7927
|
}
|
|
7914
7928
|
this.selectionManager.clearSelection();
|
|
7915
|
-
this.
|
|
7929
|
+
this.beginBackgroundPan(event);
|
|
7916
7930
|
return;
|
|
7917
7931
|
}
|
|
7918
7932
|
}
|
|
7919
|
-
if (this.navigationManager.handleMouseDown(event))
|
|
7933
|
+
if (this.navigationManager.handleMouseDown(event)) {
|
|
7934
|
+
this.suspendEditHover();
|
|
7935
|
+
return;
|
|
7936
|
+
}
|
|
7920
7937
|
if (this.navigationOnly) return;
|
|
7921
7938
|
if (this.dragManager.handleMouseDown(event)) return;
|
|
7922
7939
|
}
|
|
@@ -7930,7 +7947,11 @@ var InteractionManager = class {
|
|
|
7930
7947
|
this.renderer.setScrollbarActiveAxis(null);
|
|
7931
7948
|
this.scrollbarDragState = null;
|
|
7932
7949
|
}
|
|
7933
|
-
if (this.navigationManager.panning) this.
|
|
7950
|
+
if (this.navigationManager.panning) this.finishBackgroundPan(event);
|
|
7951
|
+
}
|
|
7952
|
+
if (this.navigationManager.panning) {
|
|
7953
|
+
this.navigationManager.handleMouseMove(event);
|
|
7954
|
+
return;
|
|
7934
7955
|
}
|
|
7935
7956
|
const overScrollbar = this.renderer.updateScrollbarHover(event.screenX, event.screenY);
|
|
7936
7957
|
const overOverlayPointerSink = this.renderer.blocksDiagramPointerAtScreen(event.screenX, event.screenY);
|
|
@@ -7992,7 +8013,7 @@ var InteractionManager = class {
|
|
|
7992
8013
|
this.selectionManager.endSelectionRect();
|
|
7993
8014
|
return;
|
|
7994
8015
|
}
|
|
7995
|
-
this.
|
|
8016
|
+
this.finishBackgroundPan(event);
|
|
7996
8017
|
}
|
|
7997
8018
|
handleClick(event) {
|
|
7998
8019
|
if (this.handledOverlayMouseDown) {
|
|
@@ -8096,6 +8117,24 @@ var InteractionManager = class {
|
|
|
8096
8117
|
}
|
|
8097
8118
|
return closestEdge;
|
|
8098
8119
|
}
|
|
8120
|
+
suspendEditHover() {
|
|
8121
|
+
if (this.navigationOnly || this.editHoverSuspendedForPan) return;
|
|
8122
|
+
this.connectionManager.disableHover();
|
|
8123
|
+
this.editHoverSuspendedForPan = true;
|
|
8124
|
+
}
|
|
8125
|
+
resumeEditHover() {
|
|
8126
|
+
if (!this.editHoverSuspendedForPan) return;
|
|
8127
|
+
this.connectionManager.enableHover();
|
|
8128
|
+
this.editHoverSuspendedForPan = false;
|
|
8129
|
+
}
|
|
8130
|
+
beginBackgroundPan(event) {
|
|
8131
|
+
this.suspendEditHover();
|
|
8132
|
+
this.navigationManager.startPan(event);
|
|
8133
|
+
}
|
|
8134
|
+
finishBackgroundPan(event) {
|
|
8135
|
+
this.navigationManager.handleMouseUp(event);
|
|
8136
|
+
this.resumeEditHover();
|
|
8137
|
+
}
|
|
8099
8138
|
handleWheel(event) {
|
|
8100
8139
|
if (this.renderer.blocksDiagramPointerAtScreen(event.screenX, event.screenY)) return;
|
|
8101
8140
|
this.navigationManager.handleWheel(event);
|
|
@@ -8134,6 +8173,7 @@ var InteractionManager = class {
|
|
|
8134
8173
|
}
|
|
8135
8174
|
handleKeyUp(event) {
|
|
8136
8175
|
this.navigationManager.handleKeyUp(event);
|
|
8176
|
+
if (!this.navigationManager.panning) this.resumeEditHover();
|
|
8137
8177
|
}
|
|
8138
8178
|
handleViewportNavigationKey(event) {
|
|
8139
8179
|
switch (event.key) {
|
|
@@ -8318,6 +8358,66 @@ var InteractionManager = class {
|
|
|
8318
8358
|
}
|
|
8319
8359
|
};
|
|
8320
8360
|
//#endregion
|
|
8361
|
+
//#region src/utils/pathViewport.ts
|
|
8362
|
+
/**
|
|
8363
|
+
* True when the drawn edge path meets the viewport.
|
|
8364
|
+
* AABB-only cull keeps fat bezier control boxes on the walk even when the
|
|
8365
|
+
* curve never enters the view. Empty path stays visible for the first layout.
|
|
8366
|
+
*/
|
|
8367
|
+
function edgePathIntersectsViewport(input, viewport) {
|
|
8368
|
+
const path = input.path;
|
|
8369
|
+
if (path.length === 0) return true;
|
|
8370
|
+
const aabb = boundsFromPoints(path);
|
|
8371
|
+
if (aabb === null || !rectsIntersect(aabb, viewport)) return false;
|
|
8372
|
+
if (input.type === "bezier" && path.length >= 4) return polylineIntersectsRect(sampleBezier(path), viewport);
|
|
8373
|
+
return polylineIntersectsRect(path, viewport);
|
|
8374
|
+
}
|
|
8375
|
+
function boundsFromPoints(points) {
|
|
8376
|
+
if (points.length === 0) return null;
|
|
8377
|
+
let minX = Infinity;
|
|
8378
|
+
let minY = Infinity;
|
|
8379
|
+
let maxX = -Infinity;
|
|
8380
|
+
let maxY = -Infinity;
|
|
8381
|
+
for (const point of points) {
|
|
8382
|
+
minX = Math.min(minX, point.x);
|
|
8383
|
+
minY = Math.min(minY, point.y);
|
|
8384
|
+
maxX = Math.max(maxX, point.x);
|
|
8385
|
+
maxY = Math.max(maxY, point.y);
|
|
8386
|
+
}
|
|
8387
|
+
return {
|
|
8388
|
+
x: minX,
|
|
8389
|
+
y: minY,
|
|
8390
|
+
width: maxX - minX,
|
|
8391
|
+
height: maxY - minY
|
|
8392
|
+
};
|
|
8393
|
+
}
|
|
8394
|
+
function polylineIntersectsRect(points, rect) {
|
|
8395
|
+
if (points.length === 1) return pointInRect(points[0], rect);
|
|
8396
|
+
for (let i = 0; i < points.length - 1; i++) {
|
|
8397
|
+
const start = points[i];
|
|
8398
|
+
const end = points[i + 1];
|
|
8399
|
+
if (pointInRect(start, rect) || pointInRect(end, rect)) return true;
|
|
8400
|
+
if (segmentRectIntersections(start, end, rect).length > 0) return true;
|
|
8401
|
+
}
|
|
8402
|
+
return false;
|
|
8403
|
+
}
|
|
8404
|
+
function sampleBezier(path) {
|
|
8405
|
+
const samples = [];
|
|
8406
|
+
const steps = 20;
|
|
8407
|
+
for (let i = 1; i + 2 < path.length; i += 3) {
|
|
8408
|
+
const p0 = path[i - 1];
|
|
8409
|
+
const p1 = path[i];
|
|
8410
|
+
const p2 = path[i + 1];
|
|
8411
|
+
const p3 = path[i + 2];
|
|
8412
|
+
for (let s = 0; s <= steps; s++) {
|
|
8413
|
+
const t = s / steps;
|
|
8414
|
+
if (samples.length > 0 && t === 0) continue;
|
|
8415
|
+
samples.push(bezierPoint(p0, p1, p2, p3, t));
|
|
8416
|
+
}
|
|
8417
|
+
}
|
|
8418
|
+
return samples;
|
|
8419
|
+
}
|
|
8420
|
+
//#endregion
|
|
8321
8421
|
//#region src/core/AnimationManager.ts
|
|
8322
8422
|
var DEFAULT_OPTIONS$3 = {
|
|
8323
8423
|
enabled: false,
|
|
@@ -9296,9 +9396,10 @@ var DiagramRenderer = class extends EventEmitter {
|
|
|
9296
9396
|
this._dirty = true;
|
|
9297
9397
|
this._styleDirty = true;
|
|
9298
9398
|
this._contentDirty = true;
|
|
9399
|
+
this._contentRevision = 0;
|
|
9400
|
+
this._contentBoundsCache = null;
|
|
9299
9401
|
this._destroyed = false;
|
|
9300
9402
|
this._contextLost = false;
|
|
9301
|
-
this._lowResPan = false;
|
|
9302
9403
|
this._canvasRect = null;
|
|
9303
9404
|
this._nodeObstaclesCache = null;
|
|
9304
9405
|
this.animationFrameId = null;
|
|
@@ -9463,26 +9564,6 @@ var DiagramRenderer = class extends EventEmitter {
|
|
|
9463
9564
|
return this.devicePixelRatio;
|
|
9464
9565
|
}
|
|
9465
9566
|
/**
|
|
9466
|
-
* Shrink a retina backing store to 1x for the duration of a pan gesture.
|
|
9467
|
-
* Does not touch `canvas.width` while the 2D context is lost.
|
|
9468
|
-
*/
|
|
9469
|
-
beginLowResPan() {
|
|
9470
|
-
if (this._lowResPan || this._contextLost) return;
|
|
9471
|
-
if (this.nativePixelRatio() <= 1) return;
|
|
9472
|
-
this._lowResPan = true;
|
|
9473
|
-
this.setupCanvas();
|
|
9474
|
-
this.markDirty();
|
|
9475
|
-
}
|
|
9476
|
-
/**
|
|
9477
|
-
* Restore the native backing-store ratio after a pan gesture.
|
|
9478
|
-
*/
|
|
9479
|
-
endLowResPan() {
|
|
9480
|
-
if (!this._lowResPan) return;
|
|
9481
|
-
this._lowResPan = false;
|
|
9482
|
-
if (!this._contextLost) this.setupCanvas();
|
|
9483
|
-
this.markDirty();
|
|
9484
|
-
}
|
|
9485
|
-
/**
|
|
9486
9567
|
* Access the underlying canvas element
|
|
9487
9568
|
*/
|
|
9488
9569
|
getCanvas() {
|
|
@@ -9753,7 +9834,7 @@ var DiagramRenderer = class extends EventEmitter {
|
|
|
9753
9834
|
addGroup(group) {
|
|
9754
9835
|
group.setDirtyListener(() => this.markDirty());
|
|
9755
9836
|
this._groups.set(group.id, group);
|
|
9756
|
-
this.
|
|
9837
|
+
this.markContentDirty();
|
|
9757
9838
|
}
|
|
9758
9839
|
/**
|
|
9759
9840
|
* Remove a group from the diagram
|
|
@@ -9763,7 +9844,7 @@ var DiagramRenderer = class extends EventEmitter {
|
|
|
9763
9844
|
if (group === void 0) return false;
|
|
9764
9845
|
this._groups.delete(groupId);
|
|
9765
9846
|
group.setDirtyListener(void 0);
|
|
9766
|
-
this.
|
|
9847
|
+
this.markContentDirty();
|
|
9767
9848
|
return true;
|
|
9768
9849
|
}
|
|
9769
9850
|
/**
|
|
@@ -9837,10 +9918,18 @@ var DiagramRenderer = class extends EventEmitter {
|
|
|
9837
9918
|
*/
|
|
9838
9919
|
markContentDirty() {
|
|
9839
9920
|
this._contentDirty = true;
|
|
9921
|
+
this._contentRevision += 1;
|
|
9840
9922
|
this._nodeObstaclesCache = null;
|
|
9841
9923
|
this._dirty = true;
|
|
9842
9924
|
}
|
|
9843
9925
|
/**
|
|
9926
|
+
* Monotonic counter bumped when nodes/edges/layout change (not on pan/zoom).
|
|
9927
|
+
* Used by MiniMap to cache its content bake across viewport moves.
|
|
9928
|
+
*/
|
|
9929
|
+
getContentRevision() {
|
|
9930
|
+
return this._contentRevision;
|
|
9931
|
+
}
|
|
9932
|
+
/**
|
|
9844
9933
|
* Visible world rectangle plus padding so labels and arrow markers are not culled early.
|
|
9845
9934
|
*/
|
|
9846
9935
|
getViewportWorldBounds() {
|
|
@@ -9858,10 +9947,13 @@ var DiagramRenderer = class extends EventEmitter {
|
|
|
9858
9947
|
}
|
|
9859
9948
|
/**
|
|
9860
9949
|
* Edges without a computed path stay drawable so the first layout pass can paint them.
|
|
9950
|
+
* Bezier control-box AABB is not enough — walk the actual path.
|
|
9861
9951
|
*/
|
|
9862
9952
|
edgeIntersectsViewport(edge, viewport) {
|
|
9863
|
-
|
|
9864
|
-
|
|
9953
|
+
return edgePathIntersectsViewport({
|
|
9954
|
+
path: edge.path,
|
|
9955
|
+
type: edge.type
|
|
9956
|
+
}, viewport);
|
|
9865
9957
|
}
|
|
9866
9958
|
/**
|
|
9867
9959
|
* Force an immediate render
|
|
@@ -9910,8 +10002,7 @@ var DiagramRenderer = class extends EventEmitter {
|
|
|
9910
10002
|
return this.options.retina ? window.devicePixelRatio || 1 : 1;
|
|
9911
10003
|
}
|
|
9912
10004
|
resolvePixelRatio() {
|
|
9913
|
-
|
|
9914
|
-
return this._lowResPan ? 1 : native;
|
|
10005
|
+
return this.nativePixelRatio();
|
|
9915
10006
|
}
|
|
9916
10007
|
setupCanvas() {
|
|
9917
10008
|
const { width, height } = this.options;
|
|
@@ -9962,13 +10053,13 @@ var DiagramRenderer = class extends EventEmitter {
|
|
|
9962
10053
|
applyStyleManagerToElements(this.styleManager, this._groups.values(), this._edges.values(), this._nodes.values());
|
|
9963
10054
|
this._styleDirty = false;
|
|
9964
10055
|
}
|
|
9965
|
-
for (const group of this._groups.values()) group.recalculateBounds();
|
|
9966
10056
|
const viewport = this.getViewportWorldBounds();
|
|
9967
10057
|
for (const group of this._groups.values()) if (group.visible && this.intersectsViewport(group.getBounds(), viewport)) {
|
|
9968
10058
|
this.renderElementWithAnimation(ctx, group, () => group.render(ctx));
|
|
9969
10059
|
group.clearDirty();
|
|
9970
10060
|
}
|
|
9971
10061
|
if (this._contentDirty) {
|
|
10062
|
+
for (const group of this._groups.values()) group.recalculateBounds();
|
|
9972
10063
|
this.edgeEndpointUpdater.updateAll();
|
|
9973
10064
|
this._contentDirty = false;
|
|
9974
10065
|
}
|
|
@@ -10031,11 +10122,17 @@ var DiagramRenderer = class extends EventEmitter {
|
|
|
10031
10122
|
return this._nodeObstaclesCache;
|
|
10032
10123
|
}
|
|
10033
10124
|
getContentBounds() {
|
|
10034
|
-
return
|
|
10125
|
+
if (this._contentBoundsCache?.revision === this._contentRevision) return this._contentBoundsCache.bounds;
|
|
10126
|
+
const bounds = getContentBounds({
|
|
10035
10127
|
nodes: this._nodes.values(),
|
|
10036
10128
|
edges: this._edges.values(),
|
|
10037
10129
|
groups: this._groups.values()
|
|
10038
10130
|
});
|
|
10131
|
+
this._contentBoundsCache = {
|
|
10132
|
+
revision: this._contentRevision,
|
|
10133
|
+
bounds
|
|
10134
|
+
};
|
|
10135
|
+
return bounds;
|
|
10039
10136
|
}
|
|
10040
10137
|
notifyScrollbarInteraction() {
|
|
10041
10138
|
this.scrollbarController.notifyInteraction();
|
|
@@ -11971,6 +12068,7 @@ var Group = class Group extends Element {
|
|
|
11971
12068
|
*/
|
|
11972
12069
|
recalculateBounds() {
|
|
11973
12070
|
if (this._children.length === 0) {
|
|
12071
|
+
if (this._x === 0 && this._y === 0 && this._width === 0 && this._height === 0) return;
|
|
11974
12072
|
this._x = 0;
|
|
11975
12073
|
this._y = 0;
|
|
11976
12074
|
this._width = 0;
|
|
@@ -11989,10 +12087,15 @@ var Group = class Group extends Element {
|
|
|
11989
12087
|
maxX = Math.max(maxX, bounds.x + bounds.width);
|
|
11990
12088
|
maxY = Math.max(maxY, bounds.y + bounds.height);
|
|
11991
12089
|
}
|
|
11992
|
-
|
|
11993
|
-
|
|
11994
|
-
|
|
11995
|
-
|
|
12090
|
+
const nextX = minX - this._padding;
|
|
12091
|
+
const nextY = minY - this._padding;
|
|
12092
|
+
const nextWidth = maxX - minX + this._padding * 2;
|
|
12093
|
+
const nextHeight = maxY - minY + this._padding * 2;
|
|
12094
|
+
if (this._x === nextX && this._y === nextY && this._width === nextWidth && this._height === nextHeight) return;
|
|
12095
|
+
this._x = nextX;
|
|
12096
|
+
this._y = nextY;
|
|
12097
|
+
this._width = nextWidth;
|
|
12098
|
+
this._height = nextHeight;
|
|
11996
12099
|
this.markDirty();
|
|
11997
12100
|
}
|
|
11998
12101
|
hitTest(point) {
|
|
@@ -12880,6 +12983,7 @@ var CText = class extends CompositeComponentBase {
|
|
|
12880
12983
|
if (this.style.visible === false) return;
|
|
12881
12984
|
const opacity = this.style.opacity ?? 1;
|
|
12882
12985
|
if (opacity <= 0) return;
|
|
12986
|
+
if (!isScreenFontReadable(ctx, this._fontSize)) return;
|
|
12883
12987
|
ctx.save();
|
|
12884
12988
|
ctx.globalAlpha *= opacity;
|
|
12885
12989
|
ctx.font = this.getFont();
|
|
@@ -12932,8 +13036,14 @@ var CText = class extends CompositeComponentBase {
|
|
|
12932
13036
|
ctx.rotate(this._rotation * Math.PI / 180);
|
|
12933
13037
|
const offsetX = xBase - (textBounds.x + textBounds.width / 2);
|
|
12934
13038
|
const offsetY = yStart - (textBounds.y + textBounds.height / 2);
|
|
12935
|
-
for (let i = 0; i < lines.length; i++)
|
|
12936
|
-
|
|
13039
|
+
for (let i = 0; i < lines.length; i++) {
|
|
13040
|
+
const y = offsetY + i * lineHeightPx;
|
|
13041
|
+
ctx.fillText(lines[i], offsetX, y);
|
|
13042
|
+
}
|
|
13043
|
+
} else for (let i = 0; i < lines.length; i++) {
|
|
13044
|
+
const y = yStart + i * lineHeightPx;
|
|
13045
|
+
ctx.fillText(lines[i], xBase, y);
|
|
13046
|
+
}
|
|
12937
13047
|
ctx.restore();
|
|
12938
13048
|
}
|
|
12939
13049
|
serialize() {
|
|
@@ -15570,6 +15680,24 @@ function distributeNodes(nodes, type) {
|
|
|
15570
15680
|
}
|
|
15571
15681
|
}
|
|
15572
15682
|
}
|
|
15683
|
+
/**
|
|
15684
|
+
* World step that keeps the visible grid cell in a Miro-like range.
|
|
15685
|
+
* The base `gridSize` is doubled or halved so the screen size stays ~16–32 px.
|
|
15686
|
+
*/
|
|
15687
|
+
function adaptiveGridStep(gridSize, zoom) {
|
|
15688
|
+
if (!Number.isFinite(gridSize) || !Number.isFinite(zoom) || gridSize <= 0 || zoom <= 0) return gridSize;
|
|
15689
|
+
let step = gridSize;
|
|
15690
|
+
let screen = step * zoom;
|
|
15691
|
+
while (screen < 16) {
|
|
15692
|
+
step *= 2;
|
|
15693
|
+
screen *= 2;
|
|
15694
|
+
}
|
|
15695
|
+
while (screen > 32) {
|
|
15696
|
+
step /= 2;
|
|
15697
|
+
screen /= 2;
|
|
15698
|
+
}
|
|
15699
|
+
return step;
|
|
15700
|
+
}
|
|
15573
15701
|
//#endregion
|
|
15574
15702
|
//#region src/core/overlays/BaseOverlay.ts
|
|
15575
15703
|
/**
|
|
@@ -15608,20 +15736,20 @@ var GridOverlay = class extends BaseOverlay {
|
|
|
15608
15736
|
if (!this.enabled) return;
|
|
15609
15737
|
const width = renderer.width;
|
|
15610
15738
|
const height = renderer.height;
|
|
15611
|
-
const
|
|
15612
|
-
const
|
|
15613
|
-
const startX = Math.floor(-renderer.offsetX /
|
|
15614
|
-
const startY = Math.floor(-renderer.offsetY /
|
|
15615
|
-
const endX = Math.ceil((width - renderer.offsetX) /
|
|
15616
|
-
const endY = Math.ceil((height - renderer.offsetY) /
|
|
15617
|
-
ctx.strokeStyle = color;
|
|
15618
|
-
ctx.lineWidth = 1 /
|
|
15739
|
+
const zoom = renderer.zoom;
|
|
15740
|
+
const step = adaptiveGridStep(this.gridSize, zoom);
|
|
15741
|
+
const startX = Math.floor(-renderer.offsetX / zoom / step) * step;
|
|
15742
|
+
const startY = Math.floor(-renderer.offsetY / zoom / step) * step;
|
|
15743
|
+
const endX = Math.ceil((width - renderer.offsetX) / zoom / step) * step;
|
|
15744
|
+
const endY = Math.ceil((height - renderer.offsetY) / zoom / step) * step;
|
|
15745
|
+
ctx.strokeStyle = this.color;
|
|
15746
|
+
ctx.lineWidth = 1 / zoom;
|
|
15619
15747
|
ctx.beginPath();
|
|
15620
|
-
for (let x = startX; x <= endX; x +=
|
|
15748
|
+
for (let x = startX; x <= endX; x += step) {
|
|
15621
15749
|
ctx.moveTo(x, startY);
|
|
15622
15750
|
ctx.lineTo(x, endY);
|
|
15623
15751
|
}
|
|
15624
|
-
for (let y = startY; y <= endY; y +=
|
|
15752
|
+
for (let y = startY; y <= endY; y += step) {
|
|
15625
15753
|
ctx.moveTo(startX, y);
|
|
15626
15754
|
ctx.lineTo(endX, y);
|
|
15627
15755
|
}
|
|
@@ -15634,51 +15762,114 @@ var GridOverlay = class extends BaseOverlay {
|
|
|
15634
15762
|
var RulersOverlay = class extends BaseOverlay {
|
|
15635
15763
|
constructor(options = {}) {
|
|
15636
15764
|
super(options.enabled ?? true);
|
|
15765
|
+
this.tickBake = null;
|
|
15766
|
+
this.tickBakeGeneration = 0;
|
|
15637
15767
|
this.thickness = options.thickness ?? 20;
|
|
15638
15768
|
this.backgroundColor = options.backgroundColor ?? "#f4f4f5";
|
|
15639
15769
|
this.textColor = options.textColor ?? "#52525b";
|
|
15640
15770
|
this.tickColor = options.tickColor ?? "#a1a1aa";
|
|
15641
15771
|
}
|
|
15772
|
+
getTickBakeGeneration() {
|
|
15773
|
+
return this.tickBakeGeneration;
|
|
15774
|
+
}
|
|
15642
15775
|
install(renderer) {
|
|
15643
15776
|
this.removeOverlay = renderer.addOverlayRenderer((ctx) => {
|
|
15644
15777
|
if (!this.enabled) return;
|
|
15645
15778
|
const thickness = this.thickness;
|
|
15779
|
+
const zoom = renderer.zoom;
|
|
15780
|
+
const worldLeft = -renderer.offsetX / zoom;
|
|
15781
|
+
const worldTop = -renderer.offsetY / zoom;
|
|
15646
15782
|
ctx.save();
|
|
15647
15783
|
ctx.setTransform(renderer.pixelRatio, 0, 0, renderer.pixelRatio, 0, 0);
|
|
15648
15784
|
ctx.fillStyle = this.backgroundColor;
|
|
15649
15785
|
ctx.fillRect(0, 0, renderer.width, thickness);
|
|
15650
15786
|
ctx.fillRect(0, 0, thickness, renderer.height);
|
|
15651
|
-
|
|
15652
|
-
|
|
15653
|
-
|
|
15654
|
-
|
|
15655
|
-
ctx.
|
|
15656
|
-
|
|
15657
|
-
const worldLeft = -renderer.offsetX / renderer.zoom;
|
|
15658
|
-
const worldTop = -renderer.offsetY / renderer.zoom;
|
|
15659
|
-
const worldRight = worldLeft + renderer.width / renderer.zoom;
|
|
15660
|
-
const worldBottom = worldTop + renderer.height / renderer.zoom;
|
|
15661
|
-
ctx.beginPath();
|
|
15662
|
-
for (let x = Math.floor(worldLeft / step) * step; x <= worldRight; x += step) {
|
|
15663
|
-
const screenX = x * renderer.zoom + renderer.offsetX;
|
|
15664
|
-
ctx.moveTo(screenX, thickness);
|
|
15665
|
-
ctx.lineTo(screenX, thickness - 6);
|
|
15666
|
-
ctx.fillText(`${Math.round(x)}`, screenX + 2, 2);
|
|
15667
|
-
}
|
|
15668
|
-
for (let y = Math.floor(worldTop / step) * step; y <= worldBottom; y += step) {
|
|
15669
|
-
const screenY = y * renderer.zoom + renderer.offsetY;
|
|
15670
|
-
ctx.moveTo(thickness, screenY);
|
|
15671
|
-
ctx.lineTo(thickness - 6, screenY);
|
|
15672
|
-
ctx.save();
|
|
15673
|
-
ctx.translate(2, screenY + 2);
|
|
15674
|
-
ctx.rotate(-Math.PI / 2);
|
|
15675
|
-
ctx.fillText(`${Math.round(y)}`, 0, 0);
|
|
15676
|
-
ctx.restore();
|
|
15677
|
-
}
|
|
15678
|
-
ctx.stroke();
|
|
15787
|
+
const bake = this.ensureTickBake(renderer);
|
|
15788
|
+
const srcX = (worldLeft - bake.worldLeft) * zoom;
|
|
15789
|
+
const srcY = (worldTop - bake.worldTop) * zoom;
|
|
15790
|
+
const pr = renderer.pixelRatio;
|
|
15791
|
+
ctx.drawImage(bake.horizontal, srcX * pr, 0, renderer.width * pr, thickness * pr, 0, 0, renderer.width, thickness);
|
|
15792
|
+
ctx.drawImage(bake.vertical, 0, srcY * pr, thickness * pr, renderer.height * pr, 0, 0, thickness, renderer.height);
|
|
15679
15793
|
ctx.restore();
|
|
15680
15794
|
});
|
|
15681
15795
|
}
|
|
15796
|
+
ensureTickBake(renderer) {
|
|
15797
|
+
const zoom = renderer.zoom;
|
|
15798
|
+
const worldLeft = -renderer.offsetX / zoom;
|
|
15799
|
+
const worldTop = -renderer.offsetY / zoom;
|
|
15800
|
+
const worldRight = worldLeft + renderer.width / zoom;
|
|
15801
|
+
const worldBottom = worldTop + renderer.height / zoom;
|
|
15802
|
+
if (this.tickBake !== null && this.tickBake.zoom === zoom && this.tickBake.pixelRatio === renderer.pixelRatio && worldLeft >= this.tickBake.worldLeft && worldRight <= this.tickBake.worldRight && worldTop >= this.tickBake.worldTop && worldBottom <= this.tickBake.worldBottom) return this.tickBake;
|
|
15803
|
+
const extraX = renderer.width / zoom;
|
|
15804
|
+
const extraY = renderer.height / zoom;
|
|
15805
|
+
const bakeLeft = worldLeft - extraX;
|
|
15806
|
+
const bakeTop = worldTop - extraY;
|
|
15807
|
+
const bakeRight = worldRight + extraX;
|
|
15808
|
+
const bakeBottom = worldBottom + extraY;
|
|
15809
|
+
const pr = Math.max(1, renderer.pixelRatio);
|
|
15810
|
+
const thickness = this.thickness;
|
|
15811
|
+
const step = this.getTickStep(zoom);
|
|
15812
|
+
const horizontal = this.tickBake?.horizontal ?? document.createElement("canvas");
|
|
15813
|
+
const vertical = this.tickBake?.vertical ?? document.createElement("canvas");
|
|
15814
|
+
const hWidth = Math.max(1, Math.ceil((bakeRight - bakeLeft) * zoom));
|
|
15815
|
+
const vHeight = Math.max(1, Math.ceil((bakeBottom - bakeTop) * zoom));
|
|
15816
|
+
horizontal.width = Math.max(1, Math.ceil(hWidth * pr));
|
|
15817
|
+
horizontal.height = Math.max(1, Math.ceil(thickness * pr));
|
|
15818
|
+
vertical.width = Math.max(1, Math.ceil(thickness * pr));
|
|
15819
|
+
vertical.height = Math.max(1, Math.ceil(vHeight * pr));
|
|
15820
|
+
const hCtx = horizontal.getContext("2d");
|
|
15821
|
+
const vCtx = vertical.getContext("2d");
|
|
15822
|
+
if (hCtx !== null) {
|
|
15823
|
+
hCtx.setTransform(pr, 0, 0, pr, 0, 0);
|
|
15824
|
+
hCtx.clearRect(0, 0, hWidth, thickness);
|
|
15825
|
+
hCtx.strokeStyle = this.tickColor;
|
|
15826
|
+
hCtx.fillStyle = this.textColor;
|
|
15827
|
+
hCtx.font = "10px sans-serif";
|
|
15828
|
+
hCtx.textAlign = "left";
|
|
15829
|
+
hCtx.textBaseline = "top";
|
|
15830
|
+
hCtx.beginPath();
|
|
15831
|
+
for (let x = Math.floor(bakeLeft / step) * step; x <= bakeRight; x += step) {
|
|
15832
|
+
const screenX = (x - bakeLeft) * zoom;
|
|
15833
|
+
hCtx.moveTo(screenX, thickness);
|
|
15834
|
+
hCtx.lineTo(screenX, thickness - 6);
|
|
15835
|
+
hCtx.fillText(`${Math.round(x)}`, screenX + 2, 2);
|
|
15836
|
+
}
|
|
15837
|
+
hCtx.stroke();
|
|
15838
|
+
}
|
|
15839
|
+
if (vCtx !== null) {
|
|
15840
|
+
vCtx.setTransform(pr, 0, 0, pr, 0, 0);
|
|
15841
|
+
vCtx.clearRect(0, 0, thickness, vHeight);
|
|
15842
|
+
vCtx.strokeStyle = this.tickColor;
|
|
15843
|
+
vCtx.fillStyle = this.textColor;
|
|
15844
|
+
vCtx.font = "10px sans-serif";
|
|
15845
|
+
vCtx.textAlign = "left";
|
|
15846
|
+
vCtx.textBaseline = "top";
|
|
15847
|
+
vCtx.beginPath();
|
|
15848
|
+
for (let y = Math.floor(bakeTop / step) * step; y <= bakeBottom; y += step) {
|
|
15849
|
+
const screenY = (y - bakeTop) * zoom;
|
|
15850
|
+
vCtx.moveTo(thickness, screenY);
|
|
15851
|
+
vCtx.lineTo(thickness - 6, screenY);
|
|
15852
|
+
vCtx.save();
|
|
15853
|
+
vCtx.translate(2, screenY + 2);
|
|
15854
|
+
vCtx.rotate(-Math.PI / 2);
|
|
15855
|
+
vCtx.fillText(`${Math.round(y)}`, 0, 0);
|
|
15856
|
+
vCtx.restore();
|
|
15857
|
+
}
|
|
15858
|
+
vCtx.stroke();
|
|
15859
|
+
}
|
|
15860
|
+
this.tickBakeGeneration += 1;
|
|
15861
|
+
this.tickBake = {
|
|
15862
|
+
zoom,
|
|
15863
|
+
pixelRatio: renderer.pixelRatio,
|
|
15864
|
+
worldLeft: bakeLeft,
|
|
15865
|
+
worldTop: bakeTop,
|
|
15866
|
+
worldRight: bakeRight,
|
|
15867
|
+
worldBottom: bakeBottom,
|
|
15868
|
+
horizontal,
|
|
15869
|
+
vertical
|
|
15870
|
+
};
|
|
15871
|
+
return this.tickBake;
|
|
15872
|
+
}
|
|
15682
15873
|
getTickStep(zoom) {
|
|
15683
15874
|
const rawStep = 80 / zoom;
|
|
15684
15875
|
const magnitude = Math.pow(10, Math.floor(Math.log10(rawStep)));
|
|
@@ -15734,6 +15925,7 @@ var GuidesOverlay = class extends BaseOverlay {
|
|
|
15734
15925
|
var MiniMap = class extends BaseOverlay {
|
|
15735
15926
|
constructor(options = {}) {
|
|
15736
15927
|
super(options.enabled ?? true);
|
|
15928
|
+
this.contentBake = null;
|
|
15737
15929
|
this.options = {
|
|
15738
15930
|
width: options.width ?? 180,
|
|
15739
15931
|
height: options.height ?? 120,
|
|
@@ -15745,12 +15937,16 @@ var MiniMap = class extends BaseOverlay {
|
|
|
15745
15937
|
anchor: options.anchor ?? "bottom-right"
|
|
15746
15938
|
};
|
|
15747
15939
|
}
|
|
15940
|
+
/** Cached bake projection; stable across pan if only the viewport moved. */
|
|
15941
|
+
getContentBakeProjectionKey() {
|
|
15942
|
+
return this.contentBake?.projectionKey ?? null;
|
|
15943
|
+
}
|
|
15748
15944
|
install(renderer) {
|
|
15749
15945
|
this.removeOverlay = renderer.addTopOverlayRenderer((ctx) => {
|
|
15750
15946
|
if (!this.enabled) return;
|
|
15751
15947
|
const layout = this.computeLayout(renderer);
|
|
15752
15948
|
if (!layout) return;
|
|
15753
|
-
const { x, y, width, height,
|
|
15949
|
+
const { x, y, width, height, viewRect } = layout;
|
|
15754
15950
|
ctx.save();
|
|
15755
15951
|
ctx.setTransform(renderer.pixelRatio, 0, 0, renderer.pixelRatio, 0, 0);
|
|
15756
15952
|
ctx.setLineDash([]);
|
|
@@ -15760,42 +15956,61 @@ var MiniMap = class extends BaseOverlay {
|
|
|
15760
15956
|
ctx.strokeStyle = this.options.borderColor;
|
|
15761
15957
|
ctx.lineWidth = 1;
|
|
15762
15958
|
ctx.strokeRect(x, y, width, height);
|
|
15763
|
-
|
|
15764
|
-
ctx.
|
|
15765
|
-
|
|
15766
|
-
|
|
15767
|
-
|
|
15768
|
-
|
|
15769
|
-
|
|
15770
|
-
|
|
15771
|
-
for (const edge of renderer.edges.values()) {
|
|
15772
|
-
if (!edge.visible) continue;
|
|
15773
|
-
const path = edge.path;
|
|
15774
|
-
if (path.length < 2) continue;
|
|
15775
|
-
ctx.beginPath();
|
|
15776
|
-
ctx.moveTo(path[0].x, path[0].y);
|
|
15777
|
-
for (let i = 1; i < path.length; i++) ctx.lineTo(path[i].x, path[i].y);
|
|
15778
|
-
ctx.stroke();
|
|
15779
|
-
}
|
|
15780
|
-
for (const node of renderer.nodes.values()) {
|
|
15781
|
-
if (!node.visible) continue;
|
|
15782
|
-
const b = node.getBounds();
|
|
15783
|
-
ctx.fillStyle = "#e2e8f0";
|
|
15784
|
-
ctx.fillRect(b.x, b.y, b.width, b.height);
|
|
15959
|
+
const bake = this.ensureContentBake(renderer, layout);
|
|
15960
|
+
ctx.drawImage(bake, x, y, width, height);
|
|
15961
|
+
if (viewRect.width >= 0 && viewRect.height >= 0) {
|
|
15962
|
+
ctx.strokeStyle = this.options.viewportColor;
|
|
15963
|
+
ctx.lineWidth = 1.5;
|
|
15964
|
+
ctx.setLineDash([]);
|
|
15965
|
+
ctx.lineDashOffset = 0;
|
|
15966
|
+
ctx.strokeRect(viewRect.x, viewRect.y, viewRect.width, viewRect.height);
|
|
15785
15967
|
}
|
|
15786
15968
|
ctx.restore();
|
|
15787
|
-
if (viewRect.width < 0 || viewRect.height < 0) {
|
|
15788
|
-
ctx.restore();
|
|
15789
|
-
return;
|
|
15790
|
-
}
|
|
15791
|
-
ctx.strokeStyle = this.options.viewportColor;
|
|
15792
|
-
ctx.lineWidth = 1.5;
|
|
15793
|
-
ctx.setLineDash([]);
|
|
15794
|
-
ctx.lineDashOffset = 0;
|
|
15795
|
-
ctx.strokeRect(viewRect.x, viewRect.y, viewRect.width, viewRect.height);
|
|
15796
|
-
ctx.restore();
|
|
15797
15969
|
});
|
|
15798
15970
|
}
|
|
15971
|
+
ensureContentBake(renderer, layout) {
|
|
15972
|
+
const { x, y, width, height, bounds, scale, mapOffsetX, mapOffsetY } = layout;
|
|
15973
|
+
const revision = renderer.getContentRevision();
|
|
15974
|
+
const projectionKey = [
|
|
15975
|
+
width,
|
|
15976
|
+
height,
|
|
15977
|
+
Math.round(bounds.x),
|
|
15978
|
+
Math.round(bounds.y),
|
|
15979
|
+
Math.round(bounds.width),
|
|
15980
|
+
Math.round(bounds.height),
|
|
15981
|
+
scale.toFixed(5),
|
|
15982
|
+
Math.round(mapOffsetX),
|
|
15983
|
+
Math.round(mapOffsetY)
|
|
15984
|
+
].join("|");
|
|
15985
|
+
if (this.contentBake !== null && this.contentBake.revision === revision && this.contentBake.projectionKey === projectionKey) return this.contentBake.canvas;
|
|
15986
|
+
const canvas = this.contentBake?.canvas ?? document.createElement("canvas");
|
|
15987
|
+
const pixelRatio = Math.max(1, Math.min(2, renderer.pixelRatio));
|
|
15988
|
+
canvas.width = Math.max(1, Math.ceil(width * pixelRatio));
|
|
15989
|
+
canvas.height = Math.max(1, Math.ceil(height * pixelRatio));
|
|
15990
|
+
const ctx = canvas.getContext("2d");
|
|
15991
|
+
if (ctx === null) return canvas;
|
|
15992
|
+
ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
|
|
15993
|
+
ctx.clearRect(0, 0, width, height);
|
|
15994
|
+
ctx.save();
|
|
15995
|
+
ctx.translate(mapOffsetX - x, mapOffsetY - y);
|
|
15996
|
+
ctx.scale(scale, scale);
|
|
15997
|
+
ctx.translate(-bounds.x, -bounds.y);
|
|
15998
|
+
ctx.setLineDash([]);
|
|
15999
|
+
ctx.lineDashOffset = 0;
|
|
16000
|
+
for (const node of renderer.nodes.values()) {
|
|
16001
|
+
if (!node.visible) continue;
|
|
16002
|
+
const b = node.getBounds();
|
|
16003
|
+
ctx.fillStyle = "#e2e8f0";
|
|
16004
|
+
ctx.fillRect(b.x, b.y, b.width, b.height);
|
|
16005
|
+
}
|
|
16006
|
+
ctx.restore();
|
|
16007
|
+
this.contentBake = {
|
|
16008
|
+
revision,
|
|
16009
|
+
projectionKey,
|
|
16010
|
+
canvas
|
|
16011
|
+
};
|
|
16012
|
+
return canvas;
|
|
16013
|
+
}
|
|
15799
16014
|
beginOverlayDrag(renderer, screenX, screenY) {
|
|
15800
16015
|
const hit = this.hitTestMiniMap(renderer, screenX, screenY);
|
|
15801
16016
|
if (!hit) return null;
|
|
@@ -15857,12 +16072,11 @@ var MiniMap = class extends BaseOverlay {
|
|
|
15857
16072
|
computeLayout(renderer) {
|
|
15858
16073
|
const rawBounds = getContentBounds({
|
|
15859
16074
|
nodes: renderer.nodes.values(),
|
|
15860
|
-
edges: renderer.edges.values(),
|
|
15861
16075
|
groups: renderer.groups.values()
|
|
15862
16076
|
});
|
|
15863
16077
|
if (!rawBounds) return null;
|
|
15864
16078
|
const margin = this.options.contentMargin;
|
|
15865
|
-
const
|
|
16079
|
+
const bounds = {
|
|
15866
16080
|
x: rawBounds.x - margin,
|
|
15867
16081
|
y: rawBounds.y - margin,
|
|
15868
16082
|
width: rawBounds.width + 2 * margin,
|
|
@@ -15872,17 +16086,7 @@ var MiniMap = class extends BaseOverlay {
|
|
|
15872
16086
|
const x = anchor === "bottom-left" || anchor === "top-left" ? padding : renderer.width - width - padding;
|
|
15873
16087
|
const y = anchor === "top-left" || anchor === "top-right" ? padding : renderer.height - height - padding;
|
|
15874
16088
|
const viewportBounds = this.getViewportBounds(renderer);
|
|
15875
|
-
const
|
|
15876
|
-
const unionMinY = Math.min(expandedContentBounds.y, viewportBounds.y);
|
|
15877
|
-
const unionMaxX = Math.max(expandedContentBounds.x + expandedContentBounds.width, viewportBounds.x + viewportBounds.width);
|
|
15878
|
-
const unionMaxY = Math.max(expandedContentBounds.y + expandedContentBounds.height, viewportBounds.y + viewportBounds.height);
|
|
15879
|
-
const bounds = {
|
|
15880
|
-
x: unionMinX,
|
|
15881
|
-
y: unionMinY,
|
|
15882
|
-
width: unionMaxX - unionMinX,
|
|
15883
|
-
height: unionMaxY - unionMinY
|
|
15884
|
-
};
|
|
15885
|
-
const scale = Math.min(width / bounds.width, height / bounds.height);
|
|
16089
|
+
const scale = Math.min(width / Math.max(bounds.width, 1), height / Math.max(bounds.height, 1));
|
|
15886
16090
|
const mapOffsetX = x + (width - bounds.width * scale) / 2;
|
|
15887
16091
|
const mapOffsetY = y + (height - bounds.height * scale) / 2;
|
|
15888
16092
|
let viewX = mapOffsetX + (viewportBounds.x - bounds.x) * scale;
|