@diagrammo/dgmo 0.92.1 → 0.94.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/dist/advanced.d.ts +103 -38
- package/dist/advanced.js +457 -423
- package/dist/block.d.ts +2 -2
- package/dist/block.js +75 -70
- package/dist/{chart-meta-BBqLnv5q.d.ts → chart-meta-BbjsRY7o.d.ts} +2 -2
- package/dist/chart-meta.d.ts +3 -3
- package/dist/chart-meta.js +25 -19
- package/dist/{chart-types-CbXlZFLd.d.ts → chart-types-Cppnp31G.d.ts} +173 -4
- package/dist/{charts-d3-QUUDVETP.js → charts-d3-SZV2SFTM.js} +7 -6
- package/dist/{chunk-ADNIO3XY.js → chunk-2FDQEQID.js} +5 -5
- package/dist/{chunk-QUGC7GWB.js → chunk-2HSHWPTO.js} +15 -15
- package/dist/{chunk-L5NW3PVL.js → chunk-2I4UQG7W.js} +1 -1
- package/dist/{chunk-2YAFDND3.js → chunk-2MS623GW.js} +4 -6
- package/dist/{chunk-73EYNV4O.js → chunk-2XMTZ5JR.js} +4 -6
- package/dist/{chunk-ZJAK6C7Y.js → chunk-3PP746YM.js} +6 -1
- package/dist/{chunk-MDVJYRJT.js → chunk-3TWBMU7K.js} +22 -22
- package/dist/{chunk-FTUMRSGT.js → chunk-3ZP3QC47.js} +8 -288
- package/dist/{chunk-J2E7EUER.js → chunk-4EX4OKGZ.js} +86 -23
- package/dist/{chunk-Y2V5AEVG.js → chunk-4SP6OUO7.js} +1952 -1824
- package/dist/{chunk-HIWHIYLD.js → chunk-4TEPDQHJ.js} +19 -19
- package/dist/{chunk-DEFBUZWV.js → chunk-5HAYT43L.js} +70 -54
- package/dist/{chunk-6WVX4KNP.js → chunk-5ZUZZDW5.js} +97 -297
- package/dist/{chunk-X5BUX2GK.js → chunk-6JCTW74W.js} +7 -5
- package/dist/{chunk-Q6W2K33N.js → chunk-6XLMTAEX.js} +1 -1
- package/dist/{chunk-ONYO5WJW.js → chunk-7IOZ6JE4.js} +21 -21
- package/dist/chunk-7SXV7NUS.js +416 -0
- package/dist/{chunk-NPWVOFB3.js → chunk-7WEYXYLC.js} +1 -1
- package/dist/{chunk-GE7ICBX6.js → chunk-AM42TLSZ.js} +102 -97
- package/dist/{chunk-WLLO3PZ3.js → chunk-AYUSD4Z6.js} +45 -19
- package/dist/{chunk-45QUTYPD.js → chunk-B25IWGDH.js} +69 -20
- package/dist/{chunk-JKST4RTT.js → chunk-BH2SF4TT.js} +6 -6
- package/dist/{chunk-6OIMUSDX.js → chunk-C6G36F5S.js} +9 -9
- package/dist/{chunk-DRFGIOZ6.js → chunk-CIHHTS5B.js} +4 -6
- package/dist/chunk-CYTFO2LF.js +209 -0
- package/dist/{chunk-Q2UFOKPB.js → chunk-DDIOWNHS.js} +22 -22
- package/dist/{chunk-Q6ZQX2HX.js → chunk-DLJJOCIT.js} +4 -6
- package/dist/{chunk-26BBJUBW.js → chunk-DNM3XZCK.js} +4 -6
- package/dist/{chunk-AUS7V54P.js → chunk-ERT7XDQW.js} +1 -1
- package/dist/{chunk-7ENDOHAA.js → chunk-FMAVHTYB.js} +919 -927
- package/dist/{chunk-URQIWIKX.js → chunk-FWVE373X.js} +4 -4
- package/dist/{chunk-VOR32OHN.js → chunk-G3HZ4PGE.js} +13 -15
- package/dist/{chunk-RBFJT23E.js → chunk-GWQRTA5W.js} +6 -6
- package/dist/chunk-GXCDD6NG.js +24 -0
- package/dist/{chunk-3PFMGNOM.js → chunk-HHVIE45A.js} +26 -11
- package/dist/{chunk-MXAP37W6.js → chunk-HI6R27YA.js} +16 -7
- package/dist/{chunk-QQPNCXAO.js → chunk-I37S3EZE.js} +18 -18
- package/dist/{chunk-YITHYQCL.js → chunk-IGJEKO2P.js} +8 -8
- package/dist/{chunk-BZX7QCXJ.js → chunk-IHN6WDEY.js} +15 -15
- package/dist/{chunk-QT3KDDXK.js → chunk-IN7XI6NO.js} +0 -7
- package/dist/{chunk-4QLGGQNO.js → chunk-IZHGT5HD.js} +44 -18
- package/dist/{chunk-5SSTVFPX.js → chunk-JT2BG7LM.js} +5 -7
- package/dist/{chunk-2BJW7FSF.js → chunk-KBEWVCK3.js} +1 -1
- package/dist/{chunk-DUPZ2BBY.js → chunk-KBHT5XEY.js} +143 -6
- package/dist/{chunk-V4D2ZQBE.js → chunk-KRPLP5LP.js} +6 -1
- package/dist/{chunk-QKY6W4NA.js → chunk-KSZB7TIY.js} +25 -25
- package/dist/{chunk-6ZL2XYM7.js → chunk-MLY5ALOV.js} +6 -6
- package/dist/{chunk-VSOZZYLK.js → chunk-NERQSSYD.js} +20 -9
- package/dist/{chunk-OQW4ETJX.js → chunk-NM5V5EKY.js} +6 -1
- package/dist/{chunk-EBSFSOJC.js → chunk-NOQB4KMV.js} +22 -22
- package/dist/{chunk-6BNNLVAR.js → chunk-NPDVWFAQ.js} +6 -1
- package/dist/{chunk-FSJ3ZA6N.js → chunk-OSSTOSXU.js} +12 -12
- package/dist/chunk-P7TRFL4P.js +54 -0
- package/dist/{chunk-A4PNWAUW.js → chunk-PGSGJLUR.js} +6 -1
- package/dist/{chunk-S7W75MIM.js → chunk-QKPOIJBT.js} +23 -5
- package/dist/{chunk-YO6AQU4A.js → chunk-QPQWY5RU.js} +12 -12
- package/dist/{chunk-NREU4JFE.js → chunk-RBVFNUAL.js} +6 -8
- package/dist/{chunk-5EBYPETE.js → chunk-RESEJSCV.js} +3 -5
- package/dist/{chunk-BRSM6Z34.js → chunk-RITTLIDJ.js} +14 -14
- package/dist/{chunk-MX4SZLSV.js → chunk-S5Y3OO3V.js} +16 -8
- package/dist/{chunk-O5WUZGPV.js → chunk-TASRGDYP.js} +18 -18
- package/dist/{chunk-HXULJZA2.js → chunk-TDAGJJPZ.js} +6 -1
- package/dist/chunk-UCHZJJIT.js +421 -0
- package/dist/{chunk-42UJ23H3.js → chunk-UIEKW4SG.js} +1 -0
- package/dist/{chunk-WFA6IULY.js → chunk-URRAWU5D.js} +5 -0
- package/dist/{chunk-IGKFOHBG.js → chunk-VBMRZCMQ.js} +13 -13
- package/dist/{chunk-JRWUHLRP.js → chunk-VDY2GR6U.js} +51 -8
- package/dist/{chunk-EJS3K44P.js → chunk-VGAMBOOC.js} +5 -3
- package/dist/{chunk-B5PEKSRH.js → chunk-VSAKEMDD.js} +6 -1
- package/dist/chunk-WTTIODDV.js +9 -0
- package/dist/{chunk-JLU52ZDT.js → chunk-XJQ6Z3FO.js} +10 -10
- package/dist/{chunk-KTGZDMDX.js → chunk-XKCRKD2B.js} +140 -53
- package/dist/{chunk-LRP5FXST.js → chunk-YQMIKX54.js} +61 -24
- package/dist/{chunk-H5UEVW6Q.js → chunk-ZD3QCNB7.js} +1 -1
- package/dist/clock.js +168 -0
- package/dist/completion-registry.js +3 -1
- package/dist/countdown.js +36 -395
- package/dist/{dgmo-router-4UAPPIKN.js → dgmo-router-E5O7RJSW.js} +50 -43
- package/dist/{dimensions-SCNVYLRF.js → dimensions-DS6FWLRY.js} +3 -3
- package/dist/{d3-BThYBTQk.d.ts → export-context-Ceh3wr0E.d.ts} +2 -8
- package/dist/{flowchart-parser-NA75YQ77.js → flowchart-parser-NZXASOZG.js} +8 -3
- package/dist/{flowchart-renderer-6MGGX4RC.js → flowchart-renderer-PTCRIANF.js} +17 -19
- package/dist/index.d.ts +8 -7
- package/dist/index.js +80 -74
- package/dist/{layout-MBVBAMPA.js → layout-3TSVAGWH.js} +2 -2
- package/dist/layout-ISSBWBH7.js +24 -0
- package/dist/layout-IT4ZTV6C.js +24 -0
- package/dist/{layout-BNLFQHSB.js → layout-U3AH6M7J.js} +9 -10
- package/dist/layout-VC3MXRB4.js +29 -0
- package/dist/layout-VDCJOZSH.js +11 -0
- package/dist/{layout-search-PMYL3VWS.js → layout-search-BBX2BMEF.js} +11 -12
- package/dist/{palettes-IN7ZFRJM.js → palettes-4Y7CL2QL.js} +4 -2
- package/dist/{parser-QYISOAGR.js → parser-4RFY7D52.js} +8 -3
- package/dist/{parser-3MK56JZC.js → parser-4Y6PODW6.js} +2 -2
- package/dist/{parser-GX5YLRIP.js → parser-7QKQ4P4P.js} +8 -3
- package/dist/{parser-2NWH5JUS.js → parser-A3AN76RQ.js} +2 -1
- package/dist/{parser-LCJ76UXS.js → parser-BT4NI6JY.js} +5 -1
- package/dist/{parser-FXDS4JDK.js → parser-F7NDRPMA.js} +2 -2
- package/dist/{parser-BES6LV3G.js → parser-GDLKUBTO.js} +5 -1
- package/dist/{parser-SEUTXN6U.js → parser-KJPPUN4D.js} +2 -2
- package/dist/{parser-SIKL4PLF.js → parser-KMKVFET2.js} +5 -1
- package/dist/{parser-5LW5JDYG.js → parser-NL73FSFI.js} +5 -1
- package/dist/{parser-VA7ZQQTA.js → parser-NUU3DVW4.js} +5 -1
- package/dist/{parser-XZUKNZPB.js → parser-R3LPEQIT.js} +7 -1
- package/dist/{parser-X23GRTQJ.js → parser-RCIEKN7Y.js} +5 -1
- package/dist/{parser-L6RWDXQN.js → parser-TAYRTCPR.js} +8 -3
- package/dist/redraw-AHW7EUUF.js +1698 -0
- package/dist/redraw-STZ4WJAI.js +73 -0
- package/dist/{renderer-LM4ICK6I.js → renderer-2LYX6NHN.js} +4 -5
- package/dist/{renderer-NHTR7IRR.js → renderer-3NLDX7DQ.js} +4 -5
- package/dist/{renderer-TO2NVJP3.js → renderer-4SE7R22T.js} +50 -45
- package/dist/{renderer-3IHQI4A4.js → renderer-53B523PM.js} +11 -10
- package/dist/{renderer-3JY6JAQJ.js → renderer-7OGGV327.js} +5 -6
- package/dist/{renderer-2FVUPBGV.js → renderer-AM7P4LN7.js} +1 -1
- package/dist/{renderer-5VKPB4LL.js → renderer-BXD5KVSR.js} +5 -5
- package/dist/{renderer-OAR5VPH4.js → renderer-DAZWHNLI.js} +2 -2
- package/dist/{renderer-WIU5BJUK.js → renderer-DDWDCM2K.js} +2 -2
- package/dist/{renderer-3QAFDXEY.js → renderer-FMTLSOCX.js} +16 -12
- package/dist/{renderer-JEJT3YET.js → renderer-HX6ICPDX.js} +2 -3
- package/dist/{renderer-NDA2FFYB.js → renderer-ISQJ2ELA.js} +5 -5
- package/dist/{renderer-XGG2UNXT.js → renderer-IXBOT6DU.js} +3 -4
- package/dist/{renderer-S3YCLJKL.js → renderer-J3GPDK73.js} +20 -22
- package/dist/{renderer-DVNMCYHZ.js → renderer-J7ZSTJUE.js} +15 -15
- package/dist/{renderer-ALWVK3EJ.js → renderer-JJ4QW3SK.js} +6 -6
- package/dist/{renderer-RUSFL7WU.js → renderer-JYHA6R2D.js} +8 -7
- package/dist/{renderer-5TZVFQ7K.js → renderer-KJ3V5BYP.js} +7 -8
- package/dist/{renderer-RSK6QFWN.js → renderer-LNP23NSM.js} +7 -9
- package/dist/{renderer-ZHGHTSNG.js → renderer-M5DUMITP.js} +13 -12
- package/dist/{renderer-O6DY46AV.js → renderer-MWZC7TMD.js} +7 -7
- package/dist/{renderer-DC7C5Q3G.js → renderer-NOYLNVTI.js} +2 -2
- package/dist/{renderer-ISSDGK54.js → renderer-O6RP52CQ.js} +3 -3
- package/dist/{renderer-ZGY7P4BM.js → renderer-OUDHH5MV.js} +19 -22
- package/dist/{renderer-QGIHLZOJ.js → renderer-PHLCYVSN.js} +9 -10
- package/dist/{renderer-VPIELEE5.js → renderer-QTPWRRJ7.js} +8 -9
- package/dist/{renderer-LQP3AGEJ.js → renderer-RUSQJFFC.js} +3 -4
- package/dist/{renderer-MM27BSBO.js → renderer-TINHO2IO.js} +3 -4
- package/dist/{renderer-7ZZG5HR3.js → renderer-UTEEJDGB.js} +9 -9
- package/dist/{renderer-J5FKF423.js → renderer-W4MUMXJE.js} +7 -4
- package/dist/{renderer-XO57LTU4.js → renderer-WPN2SXGT.js} +5 -5
- package/dist/{renderer-ZZ6MWVB7.js → renderer-XCLARXCK.js} +4 -4
- package/dist/{renderer-J666LZXJ.js → renderer-XOWDERU2.js} +8 -8
- package/dist/{state-parser-TIR2ORJY.js → state-parser-KPVW5CRI.js} +8 -3
- package/dist/{state-renderer-G6SUXU4J.js → state-renderer-ZVEI265C.js} +18 -21
- package/dist/{tag-groups-DsoVpAY-.d.ts → tag-groups-DydewK3D.d.ts} +2 -173
- package/dist/{themes-DRNjxX7Q.d.ts → themes-DzIH3Hjv.d.ts} +3 -2
- package/docs/ai-integration.md +1 -1
- package/docs/language-reference.md +23 -2
- package/gallery/fixtures/whiteboard.dgmo +3 -0
- package/package.json +2 -6
- package/dist/chunk-3Y63RFJL.js +0 -75
- package/dist/chunk-5DH3KYFH.js +0 -20
- package/dist/chunk-O753JUEZ.js +0 -67
- package/dist/chunk-RJNZHFNG.js +0 -51
- package/dist/chunk-Z6DXWULM.js +0 -23
- package/dist/layout-5USEVQBY.js +0 -25
- package/dist/layout-J3AGFZZ7.js +0 -10
- package/dist/layout-S3RLVPH4.js +0 -25
- package/dist/layout-WRG4APSJ.js +0 -32
- package/dist/{chunk-DGUGE67L.js → chunk-CDYV46JE.js} +3 -3
- package/dist/{chunk-TKAB3FTK.js → chunk-DRQSB72S.js} +11 -11
- package/dist/{chunk-ZKP77MB3.js → chunk-FVTYJUXR.js} +5 -5
- package/dist/{chunk-MA42PIGJ.js → chunk-H5NVCOEJ.js} +4 -4
- package/dist/{chunk-BEA4D7OS.js → chunk-IXHWS2HI.js} +3 -3
- package/dist/{chunk-SOHZDW6N.js → chunk-UXNA2H2V.js} +3 -3
- package/dist/{chunk-NO3UX6AP.js → chunk-V2NQV7VL.js} +4 -4
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
import {
|
|
2
|
+
normalizeName
|
|
3
|
+
} from "./chunk-NOTA6TEI.js";
|
|
4
|
+
import {
|
|
5
|
+
NOTE_GAP,
|
|
6
|
+
noteBoxSize,
|
|
7
|
+
noteConnectorPoints
|
|
8
|
+
} from "./chunk-VDY2GR6U.js";
|
|
9
|
+
import {
|
|
10
|
+
extractColor,
|
|
11
|
+
measureIndent
|
|
12
|
+
} from "./chunk-TIIZIAGS.js";
|
|
13
|
+
import {
|
|
14
|
+
makeDgmoError,
|
|
15
|
+
suggest
|
|
16
|
+
} from "./chunk-BYU54C3S.js";
|
|
17
|
+
|
|
18
|
+
// src/utils/notes/parse.ts
|
|
19
|
+
function parseNoteHeader(rest) {
|
|
20
|
+
const t = rest.trim();
|
|
21
|
+
const quoted = t.match(/^"([^"]+)"\s*(.*)$/);
|
|
22
|
+
if (quoted) {
|
|
23
|
+
return { ref: quoted[1].trim(), inlineBody: quoted[2].trim() };
|
|
24
|
+
}
|
|
25
|
+
const m = t.match(/^(\S+)\s*(.*)$/);
|
|
26
|
+
if (m) {
|
|
27
|
+
return { ref: m[1], inlineBody: m[2].trim() };
|
|
28
|
+
}
|
|
29
|
+
return { ref: t, inlineBody: "" };
|
|
30
|
+
}
|
|
31
|
+
function collectNoteBody(lines, noteIndex, noteIndent, inlineBody) {
|
|
32
|
+
const parts = [];
|
|
33
|
+
if (inlineBody) parts.push(inlineBody);
|
|
34
|
+
let lastIndex = noteIndex;
|
|
35
|
+
let endLineNumber = noteIndex + 1;
|
|
36
|
+
for (let j = noteIndex + 1; j < lines.length; j++) {
|
|
37
|
+
const raw = lines[j];
|
|
38
|
+
const trimmed = raw.trim();
|
|
39
|
+
if (!trimmed) break;
|
|
40
|
+
if (measureIndent(raw) <= noteIndent) break;
|
|
41
|
+
parts.push(trimmed);
|
|
42
|
+
lastIndex = j;
|
|
43
|
+
endLineNumber = j + 1;
|
|
44
|
+
}
|
|
45
|
+
return { body: parts.join("\n"), endLineNumber, lastIndex };
|
|
46
|
+
}
|
|
47
|
+
function tryCollectNote(lines, index, indent, palette, diagnostics) {
|
|
48
|
+
const trimmed = lines[index].trim();
|
|
49
|
+
const m = trimmed.match(/^note\s+(.+)$/i);
|
|
50
|
+
if (!m || /^note\s+->/i.test(trimmed)) return null;
|
|
51
|
+
const lineNumber = index + 1;
|
|
52
|
+
const { label: headerNoColor, color } = extractColor(
|
|
53
|
+
m[1],
|
|
54
|
+
palette,
|
|
55
|
+
diagnostics,
|
|
56
|
+
lineNumber
|
|
57
|
+
);
|
|
58
|
+
const { ref, inlineBody } = parseNoteHeader(headerNoColor);
|
|
59
|
+
const collected = collectNoteBody(lines, index, indent, inlineBody);
|
|
60
|
+
if (!collected.body.trim()) {
|
|
61
|
+
diagnostics.push(
|
|
62
|
+
makeDgmoError(
|
|
63
|
+
lineNumber,
|
|
64
|
+
`Note on "${ref}" has no text \u2014 ignored.`,
|
|
65
|
+
"warning"
|
|
66
|
+
)
|
|
67
|
+
);
|
|
68
|
+
return { lastIndex: collected.lastIndex };
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
note: {
|
|
72
|
+
ref,
|
|
73
|
+
body: collected.body,
|
|
74
|
+
...color && { color },
|
|
75
|
+
lineNumber,
|
|
76
|
+
endLineNumber: collected.endLineNumber
|
|
77
|
+
},
|
|
78
|
+
lastIndex: collected.lastIndex
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// src/utils/notes/resolve.ts
|
|
83
|
+
function resolveNotes(notes, targets, diagnostics) {
|
|
84
|
+
const byNodeId = /* @__PURE__ */ new Map();
|
|
85
|
+
if (notes.length === 0) return byNodeId;
|
|
86
|
+
const byNormLabel = /* @__PURE__ */ new Map();
|
|
87
|
+
for (const t of targets) {
|
|
88
|
+
const key = normalizeName(t.label);
|
|
89
|
+
const arr = byNormLabel.get(key);
|
|
90
|
+
if (arr) arr.push(t);
|
|
91
|
+
else byNormLabel.set(key, [t]);
|
|
92
|
+
}
|
|
93
|
+
for (const note of notes) {
|
|
94
|
+
const matches = byNormLabel.get(normalizeName(note.ref));
|
|
95
|
+
if (!matches || matches.length === 0) {
|
|
96
|
+
if (diagnostics) {
|
|
97
|
+
const hint = suggest(
|
|
98
|
+
note.ref,
|
|
99
|
+
targets.map((t) => t.label)
|
|
100
|
+
);
|
|
101
|
+
diagnostics.push(
|
|
102
|
+
makeDgmoError(
|
|
103
|
+
note.lineNumber,
|
|
104
|
+
`Note references unknown node id "${note.ref}".${hint ? " " + hint : ""}`,
|
|
105
|
+
"error"
|
|
106
|
+
)
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
const target = matches[0];
|
|
112
|
+
if (matches.length > 1 && diagnostics) {
|
|
113
|
+
diagnostics.push(
|
|
114
|
+
makeDgmoError(
|
|
115
|
+
note.lineNumber,
|
|
116
|
+
`Note ref "${note.ref}" matches ${matches.length} nodes; attaching to the first.`,
|
|
117
|
+
"warning"
|
|
118
|
+
)
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
if (byNodeId.has(target.id)) {
|
|
122
|
+
if (diagnostics) {
|
|
123
|
+
diagnostics.push(
|
|
124
|
+
makeDgmoError(
|
|
125
|
+
note.lineNumber,
|
|
126
|
+
`Multiple notes on node "${target.label}"; keeping the first.`,
|
|
127
|
+
"warning"
|
|
128
|
+
)
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
byNodeId.set(target.id, note);
|
|
134
|
+
}
|
|
135
|
+
return byNodeId;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// src/utils/notes/place.ts
|
|
139
|
+
var NOTE_CLEAR = 14;
|
|
140
|
+
var intersects = (a, b, pad) => !(a.right + pad <= b.left || b.right + pad <= a.left || a.bottom + pad <= b.top || b.bottom + pad <= a.top);
|
|
141
|
+
var CONNECTOR_CLEAR = 4;
|
|
142
|
+
var EDGE_CLEAR = 6;
|
|
143
|
+
var SLIDE_STEP = 10;
|
|
144
|
+
var SEARCH_REACH = 480;
|
|
145
|
+
var segmentCrosses = (x1, y1, x2, y2, r) => {
|
|
146
|
+
const dx = x2 - x1;
|
|
147
|
+
const dy = y2 - y1;
|
|
148
|
+
const p = [-dx, dx, -dy, dy];
|
|
149
|
+
const q = [x1 - r.left, r.right - x1, y1 - r.top, r.bottom - y1];
|
|
150
|
+
let t0 = 0;
|
|
151
|
+
let t1 = 1;
|
|
152
|
+
for (let i = 0; i < 4; i++) {
|
|
153
|
+
const pi = p[i];
|
|
154
|
+
const qi = q[i];
|
|
155
|
+
if (pi === 0) {
|
|
156
|
+
if (qi <= 0) return false;
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
const t = qi / pi;
|
|
160
|
+
if (pi < 0) t0 = Math.max(t0, t);
|
|
161
|
+
else t1 = Math.min(t1, t);
|
|
162
|
+
}
|
|
163
|
+
return t0 < t1;
|
|
164
|
+
};
|
|
165
|
+
function placeNotes(obstacles, requests, direction, edges = []) {
|
|
166
|
+
const placements = /* @__PURE__ */ new Map();
|
|
167
|
+
const occupied = obstacles.map((p) => ({
|
|
168
|
+
left: p.x - p.width / 2,
|
|
169
|
+
top: p.y - p.height / 2,
|
|
170
|
+
right: p.x + p.width / 2,
|
|
171
|
+
bottom: p.y + p.height / 2
|
|
172
|
+
}));
|
|
173
|
+
for (const req of requests) {
|
|
174
|
+
if (req.collapsed) {
|
|
175
|
+
placements.set(req.key, {
|
|
176
|
+
collapsed: true,
|
|
177
|
+
side: "right",
|
|
178
|
+
x: 0,
|
|
179
|
+
y: 0
|
|
180
|
+
});
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
const p = req.node;
|
|
184
|
+
const cx = p.x;
|
|
185
|
+
const cy = p.y;
|
|
186
|
+
const nodeLeft = cx - p.width / 2;
|
|
187
|
+
const nodeRight = cx + p.width / 2;
|
|
188
|
+
const nodeTop = cy - p.height / 2;
|
|
189
|
+
const nodeBottom = cy + p.height / 2;
|
|
190
|
+
const { noteW, noteH } = req;
|
|
191
|
+
const rectFor = (side) => {
|
|
192
|
+
switch (side) {
|
|
193
|
+
case "right": {
|
|
194
|
+
const left = nodeRight + NOTE_GAP;
|
|
195
|
+
const top = cy - noteH / 2;
|
|
196
|
+
return { left, top, right: left + noteW, bottom: top + noteH };
|
|
197
|
+
}
|
|
198
|
+
case "left": {
|
|
199
|
+
const right = nodeLeft - NOTE_GAP;
|
|
200
|
+
const top = cy - noteH / 2;
|
|
201
|
+
return { left: right - noteW, top, right, bottom: top + noteH };
|
|
202
|
+
}
|
|
203
|
+
case "below": {
|
|
204
|
+
const left = cx - noteW / 2;
|
|
205
|
+
const top = nodeBottom + NOTE_GAP;
|
|
206
|
+
return { left, top, right: left + noteW, bottom: top + noteH };
|
|
207
|
+
}
|
|
208
|
+
case "above":
|
|
209
|
+
default: {
|
|
210
|
+
const left = cx - noteW / 2;
|
|
211
|
+
const bottom = nodeTop - NOTE_GAP;
|
|
212
|
+
return { left, top: bottom - noteH, right: left + noteW, bottom };
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
const order = direction === "LR" ? ["below", "above", "right", "left"] : ["right", "left", "below", "above"];
|
|
217
|
+
const anchor = {
|
|
218
|
+
left: nodeLeft,
|
|
219
|
+
top: nodeTop,
|
|
220
|
+
right: nodeRight,
|
|
221
|
+
bottom: nodeBottom
|
|
222
|
+
};
|
|
223
|
+
const isAnchor = (o) => o.left === anchor.left && o.top === anchor.top && o.right === anchor.right && o.bottom === anchor.bottom;
|
|
224
|
+
const connector = (rect, side) => {
|
|
225
|
+
const [x1, y1, x2, y2] = noteConnectorPoints(p, {
|
|
226
|
+
x: rect.left - cx,
|
|
227
|
+
y: rect.top - cy,
|
|
228
|
+
width: noteW,
|
|
229
|
+
height: noteH,
|
|
230
|
+
side
|
|
231
|
+
});
|
|
232
|
+
return [cx + x1, cy + y1, cx + x2, cy + y2];
|
|
233
|
+
};
|
|
234
|
+
const onEdge = (rect) => {
|
|
235
|
+
const padded = {
|
|
236
|
+
left: rect.left - EDGE_CLEAR,
|
|
237
|
+
top: rect.top - EDGE_CLEAR,
|
|
238
|
+
right: rect.right + EDGE_CLEAR,
|
|
239
|
+
bottom: rect.bottom + EDGE_CLEAR
|
|
240
|
+
};
|
|
241
|
+
return edges.some(
|
|
242
|
+
(path) => path.some(
|
|
243
|
+
(pt, i) => i > 0 && segmentCrosses(path[i - 1].x, path[i - 1].y, pt.x, pt.y, padded)
|
|
244
|
+
)
|
|
245
|
+
);
|
|
246
|
+
};
|
|
247
|
+
const isClear = (rect, side, avoidEdges) => {
|
|
248
|
+
if (occupied.some((o) => intersects(rect, o, NOTE_CLEAR))) return false;
|
|
249
|
+
if (avoidEdges && onEdge(rect)) return false;
|
|
250
|
+
const [x1, y1, x2, y2] = connector(rect, side);
|
|
251
|
+
return !occupied.some(
|
|
252
|
+
(o) => !isAnchor(o) && segmentCrosses(x1, y1, x2, y2, {
|
|
253
|
+
left: o.left - CONNECTOR_CLEAR,
|
|
254
|
+
top: o.top - CONNECTOR_CLEAR,
|
|
255
|
+
right: o.right + CONNECTOR_CLEAR,
|
|
256
|
+
bottom: o.bottom + CONNECTOR_CLEAR
|
|
257
|
+
})
|
|
258
|
+
);
|
|
259
|
+
};
|
|
260
|
+
const search = (avoidEdges) => {
|
|
261
|
+
let chosen2 = null;
|
|
262
|
+
for (const side of order.slice(0, 2)) {
|
|
263
|
+
const rect = rectFor(side);
|
|
264
|
+
if (isClear(rect, side, avoidEdges)) {
|
|
265
|
+
chosen2 = { rect, side };
|
|
266
|
+
break;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
if (chosen2) return chosen2;
|
|
270
|
+
let bestLen = Infinity;
|
|
271
|
+
for (const side of order) {
|
|
272
|
+
const axisIsY = side === "above" || side === "below";
|
|
273
|
+
const outward = side === "below" || side === "right" ? 1 : -1;
|
|
274
|
+
const reach = axisIsY ? noteW / 2 : SEARCH_REACH;
|
|
275
|
+
const slides = [0];
|
|
276
|
+
for (let s = SLIDE_STEP; s <= reach; s += SLIDE_STEP) {
|
|
277
|
+
slides.push(s, -s);
|
|
278
|
+
}
|
|
279
|
+
const base = rectFor(side);
|
|
280
|
+
for (let out = 0; out <= SEARCH_REACH; out += NOTE_CLEAR) {
|
|
281
|
+
for (const slide of slides) {
|
|
282
|
+
const dx = axisIsY ? slide : out * outward;
|
|
283
|
+
const dy = axisIsY ? out * outward : slide;
|
|
284
|
+
const rect = {
|
|
285
|
+
left: base.left + dx,
|
|
286
|
+
top: base.top + dy,
|
|
287
|
+
right: base.right + dx,
|
|
288
|
+
bottom: base.bottom + dy
|
|
289
|
+
};
|
|
290
|
+
if (!isClear(rect, side, avoidEdges)) continue;
|
|
291
|
+
const [x1, y1, x2, y2] = connector(rect, side);
|
|
292
|
+
const len = Math.hypot(x2 - x1, y2 - y1);
|
|
293
|
+
if (len < bestLen) {
|
|
294
|
+
bestLen = len;
|
|
295
|
+
chosen2 = { rect, side };
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return chosen2;
|
|
301
|
+
};
|
|
302
|
+
let chosen = search(true) ?? search(false);
|
|
303
|
+
if (!chosen) {
|
|
304
|
+
const side = order[0];
|
|
305
|
+
let rect = rectFor(side);
|
|
306
|
+
const axisIsY = side === "above" || side === "below";
|
|
307
|
+
const outward = side === "below" || side === "right" ? 1 : -1;
|
|
308
|
+
for (let guard = 0; guard < 50; guard++) {
|
|
309
|
+
const blockers = occupied.filter(
|
|
310
|
+
(o) => intersects(rect, o, NOTE_CLEAR)
|
|
311
|
+
);
|
|
312
|
+
if (blockers.length === 0) break;
|
|
313
|
+
if (axisIsY && outward > 0) {
|
|
314
|
+
const top = Math.max(...blockers.map((b) => b.bottom)) + NOTE_CLEAR;
|
|
315
|
+
rect = { ...rect, top, bottom: top + noteH };
|
|
316
|
+
} else if (axisIsY) {
|
|
317
|
+
const bottom = Math.min(...blockers.map((b) => b.top)) - NOTE_CLEAR;
|
|
318
|
+
rect = { ...rect, bottom, top: bottom - noteH };
|
|
319
|
+
} else if (outward > 0) {
|
|
320
|
+
const left = Math.max(...blockers.map((b) => b.right)) + NOTE_CLEAR;
|
|
321
|
+
rect = { ...rect, left, right: left + noteW };
|
|
322
|
+
} else {
|
|
323
|
+
const right = Math.min(...blockers.map((b) => b.left)) - NOTE_CLEAR;
|
|
324
|
+
rect = { ...rect, right, left: right - noteW };
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
chosen = { rect, side };
|
|
328
|
+
}
|
|
329
|
+
occupied.push(chosen.rect);
|
|
330
|
+
placements.set(req.key, {
|
|
331
|
+
collapsed: false,
|
|
332
|
+
side: chosen.side,
|
|
333
|
+
x: chosen.rect.left - p.x,
|
|
334
|
+
y: chosen.rect.top - p.y
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
return placements;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// src/utils/notes/build.ts
|
|
341
|
+
function buildPlacedNotes(anchors, noteByNode, direction, collapsedNotes) {
|
|
342
|
+
const placed = /* @__PURE__ */ new Map();
|
|
343
|
+
if (noteByNode.size === 0) return placed;
|
|
344
|
+
const geoms = /* @__PURE__ */ new Map();
|
|
345
|
+
const requests = [];
|
|
346
|
+
for (const a of anchors) {
|
|
347
|
+
const note = noteByNode.get(a.id);
|
|
348
|
+
if (!note) continue;
|
|
349
|
+
const size = noteBoxSize(note.body);
|
|
350
|
+
geoms.set(a.id, {
|
|
351
|
+
noteW: size.width,
|
|
352
|
+
noteH: size.height,
|
|
353
|
+
...note.color && { color: note.color },
|
|
354
|
+
lines: size.lines,
|
|
355
|
+
lineNumber: note.lineNumber,
|
|
356
|
+
endLineNumber: note.endLineNumber
|
|
357
|
+
});
|
|
358
|
+
requests.push({
|
|
359
|
+
key: a.id,
|
|
360
|
+
node: { x: a.x, y: a.y, width: a.width, height: a.height },
|
|
361
|
+
noteW: size.width,
|
|
362
|
+
noteH: size.height,
|
|
363
|
+
collapsed: collapsedNotes?.has(note.lineNumber) ?? false
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
const placements = placeNotes(
|
|
367
|
+
anchors.map((a) => ({ x: a.x, y: a.y, width: a.width, height: a.height })),
|
|
368
|
+
requests,
|
|
369
|
+
direction
|
|
370
|
+
);
|
|
371
|
+
for (const [id, g] of geoms) {
|
|
372
|
+
const p = placements.get(id);
|
|
373
|
+
placed.set(
|
|
374
|
+
id,
|
|
375
|
+
p.collapsed ? {
|
|
376
|
+
x: 0,
|
|
377
|
+
y: 0,
|
|
378
|
+
width: 0,
|
|
379
|
+
height: 0,
|
|
380
|
+
side: "right",
|
|
381
|
+
...g.color && { color: g.color },
|
|
382
|
+
lines: [],
|
|
383
|
+
lineNumber: g.lineNumber,
|
|
384
|
+
endLineNumber: g.endLineNumber,
|
|
385
|
+
collapsed: true
|
|
386
|
+
} : {
|
|
387
|
+
x: p.x,
|
|
388
|
+
y: p.y,
|
|
389
|
+
width: g.noteW,
|
|
390
|
+
height: g.noteH,
|
|
391
|
+
side: p.side,
|
|
392
|
+
...g.color && { color: g.color },
|
|
393
|
+
lines: g.lines,
|
|
394
|
+
lineNumber: g.lineNumber,
|
|
395
|
+
endLineNumber: g.endLineNumber
|
|
396
|
+
}
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
return placed;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// src/utils/notes/bounds.ts
|
|
403
|
+
function noteCanvasShift(minX, minY, margin = 20) {
|
|
404
|
+
return {
|
|
405
|
+
shiftX: minX < 0 ? margin - minX : 0,
|
|
406
|
+
shiftY: minY < 0 ? margin - minY : 0
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
export {
|
|
411
|
+
tryCollectNote,
|
|
412
|
+
resolveNotes,
|
|
413
|
+
placeNotes,
|
|
414
|
+
buildPlacedNotes,
|
|
415
|
+
noteCanvasShift
|
|
416
|
+
};
|
|
@@ -9,14 +9,14 @@ import {
|
|
|
9
9
|
rectsOverlap,
|
|
10
10
|
segmentRectOverlap
|
|
11
11
|
} from "./chunk-KMU65FYM.js";
|
|
12
|
-
import {
|
|
13
|
-
compactNumber,
|
|
14
|
-
computeLegendLayout
|
|
15
|
-
} from "./chunk-JILEYZ2V.js";
|
|
16
12
|
import {
|
|
17
13
|
TITLE_FONT_SIZE,
|
|
18
14
|
TITLE_Y
|
|
19
15
|
} from "./chunk-VLC6WNRD.js";
|
|
16
|
+
import {
|
|
17
|
+
compactNumber,
|
|
18
|
+
computeLegendLayout
|
|
19
|
+
} from "./chunk-JILEYZ2V.js";
|
|
20
20
|
import {
|
|
21
21
|
tagAttrKey
|
|
22
22
|
} from "./chunk-4SACN2C5.js";
|
|
@@ -620,6 +620,88 @@ function layoutEdgeLabels(args) {
|
|
|
620
620
|
return chosen;
|
|
621
621
|
}
|
|
622
622
|
|
|
623
|
+
// src/map/dot-labels.ts
|
|
624
|
+
var DOT_LABEL_GAP = 3;
|
|
625
|
+
function dotLabelRect(dot, w, h, side) {
|
|
626
|
+
const GAP2 = DOT_LABEL_GAP;
|
|
627
|
+
switch (side) {
|
|
628
|
+
case "right":
|
|
629
|
+
return { x: dot.cx + dot.r + GAP2, y: dot.cy - h / 2, w, h };
|
|
630
|
+
case "left":
|
|
631
|
+
return { x: dot.cx - dot.r - GAP2 - w, y: dot.cy - h / 2, w, h };
|
|
632
|
+
case "above":
|
|
633
|
+
return { x: dot.cx - w / 2, y: dot.cy - dot.r - GAP2 - h, w, h };
|
|
634
|
+
case "below":
|
|
635
|
+
return { x: dot.cx - w / 2, y: dot.cy + dot.r + GAP2, w, h };
|
|
636
|
+
// Diagonal corners: offset both axes by (r+GAP)/√2 so the box's near
|
|
637
|
+
// corner clears the dot rim by the same gap as a cardinal side.
|
|
638
|
+
case "below-right": {
|
|
639
|
+
const d = (dot.r + GAP2) * 0.7071;
|
|
640
|
+
return { x: dot.cx + d, y: dot.cy + d, w, h };
|
|
641
|
+
}
|
|
642
|
+
case "below-left": {
|
|
643
|
+
const d = (dot.r + GAP2) * 0.7071;
|
|
644
|
+
return { x: dot.cx - d - w, y: dot.cy + d, w, h };
|
|
645
|
+
}
|
|
646
|
+
case "above-right": {
|
|
647
|
+
const d = (dot.r + GAP2) * 0.7071;
|
|
648
|
+
return { x: dot.cx + d, y: dot.cy - d - h, w, h };
|
|
649
|
+
}
|
|
650
|
+
case "above-left": {
|
|
651
|
+
const d = (dot.r + GAP2) * 0.7071;
|
|
652
|
+
return { x: dot.cx - d - w, y: dot.cy - d - h, w, h };
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
function dotLabelFits(rect, width, height, collides) {
|
|
657
|
+
return rect.x >= 0 && rect.x + rect.w <= width && rect.y >= 0 && rect.y + rect.h <= height && !collides(rect);
|
|
658
|
+
}
|
|
659
|
+
var CLEAR_CAP = 48;
|
|
660
|
+
var CLEAR_W = 8;
|
|
661
|
+
var WATER_W = 0.25;
|
|
662
|
+
var LEGIBILITY = {
|
|
663
|
+
right: 160,
|
|
664
|
+
left: 160,
|
|
665
|
+
above: 100,
|
|
666
|
+
below: 100,
|
|
667
|
+
"below-right": 0,
|
|
668
|
+
"below-left": 0,
|
|
669
|
+
"above-right": 0,
|
|
670
|
+
"above-left": 0
|
|
671
|
+
};
|
|
672
|
+
var ALL_SIDES = Object.keys(LEGIBILITY);
|
|
673
|
+
function ptSegDist(px, py, ax, ay, bx, by) {
|
|
674
|
+
const dx = bx - ax;
|
|
675
|
+
const dy = by - ay;
|
|
676
|
+
const len2 = dx * dx + dy * dy;
|
|
677
|
+
let t = len2 > 0 ? ((px - ax) * dx + (py - ay) * dy) / len2 : 0;
|
|
678
|
+
t = Math.max(0, Math.min(1, t));
|
|
679
|
+
return Math.hypot(px - (ax + t * dx), py - (ay + t * dy));
|
|
680
|
+
}
|
|
681
|
+
function clearanceOf(rect, ownId, dots, segments) {
|
|
682
|
+
const cxL = rect.x + rect.w / 2;
|
|
683
|
+
const cyL = rect.y + rect.h / 2;
|
|
684
|
+
let d = CLEAR_CAP;
|
|
685
|
+
for (const q of dots) {
|
|
686
|
+
if (q.id === ownId) continue;
|
|
687
|
+
d = Math.min(d, Math.hypot(q.cx - cxL, q.cy - cyL) - q.r);
|
|
688
|
+
}
|
|
689
|
+
for (const s of segments)
|
|
690
|
+
d = Math.min(d, ptSegDist(cxL, cyL, s[0], s[1], s[2], s[3]));
|
|
691
|
+
return Math.max(0, d);
|
|
692
|
+
}
|
|
693
|
+
function placeDotLabel(args) {
|
|
694
|
+
const { dot, w, h, width, height, collides, dots, segments, openness } = args;
|
|
695
|
+
let best = null;
|
|
696
|
+
for (const side of ALL_SIDES) {
|
|
697
|
+
const rect = dotLabelRect(dot, w, h, side);
|
|
698
|
+
if (!dotLabelFits(rect, width, height, collides)) continue;
|
|
699
|
+
const v = CLEAR_W * clearanceOf(rect, dot.id, dots, segments) + WATER_W * openness(rect) + LEGIBILITY[side];
|
|
700
|
+
if (best === null || v > best.v) best = { side, rect, v };
|
|
701
|
+
}
|
|
702
|
+
return best && { side: best.side, rect: best.rect };
|
|
703
|
+
}
|
|
704
|
+
|
|
623
705
|
// src/map/connectors.ts
|
|
624
706
|
var W_MIN = 1.25;
|
|
625
707
|
var W_MAX = 8;
|
|
@@ -2920,7 +3002,7 @@ function layoutMap(resolvedIn, data, size, opts) {
|
|
|
2920
3002
|
const text = labelText(p);
|
|
2921
3003
|
return { text, w: measureLegendText(text, FONT2) };
|
|
2922
3004
|
};
|
|
2923
|
-
const GAP2 =
|
|
3005
|
+
const GAP2 = DOT_LABEL_GAP;
|
|
2924
3006
|
const POI_EDGE_CLEAR = Math.max(
|
|
2925
3007
|
20,
|
|
2926
3008
|
Math.round(Math.min(width, height) * 0.03)
|
|
@@ -2932,46 +3014,7 @@ function layoutMap(resolvedIn, data, size, opts) {
|
|
|
2932
3014
|
if (arr) arr.push(p);
|
|
2933
3015
|
else clusterMembersById.set(p.clusterId, [p]);
|
|
2934
3016
|
}
|
|
2935
|
-
const inlineRect = (p, w, side) =>
|
|
2936
|
-
switch (side) {
|
|
2937
|
-
case "right":
|
|
2938
|
-
return { x: p.cx + p.r + GAP2, y: p.cy - poiLabH / 2, w, h: poiLabH };
|
|
2939
|
-
case "left":
|
|
2940
|
-
return {
|
|
2941
|
-
x: p.cx - p.r - GAP2 - w,
|
|
2942
|
-
y: p.cy - poiLabH / 2,
|
|
2943
|
-
w,
|
|
2944
|
-
h: poiLabH
|
|
2945
|
-
};
|
|
2946
|
-
case "above":
|
|
2947
|
-
return {
|
|
2948
|
-
x: p.cx - w / 2,
|
|
2949
|
-
y: p.cy - p.r - GAP2 - poiLabH,
|
|
2950
|
-
w,
|
|
2951
|
-
h: poiLabH
|
|
2952
|
-
};
|
|
2953
|
-
case "below":
|
|
2954
|
-
return { x: p.cx - w / 2, y: p.cy + p.r + GAP2, w, h: poiLabH };
|
|
2955
|
-
// Diagonal corners: offset both axes by (r+GAP)/√2 so the box's near
|
|
2956
|
-
// corner clears the dot rim by the same gap as a cardinal side.
|
|
2957
|
-
case "below-right": {
|
|
2958
|
-
const d = (p.r + GAP2) * 0.7071;
|
|
2959
|
-
return { x: p.cx + d, y: p.cy + d, w, h: poiLabH };
|
|
2960
|
-
}
|
|
2961
|
-
case "below-left": {
|
|
2962
|
-
const d = (p.r + GAP2) * 0.7071;
|
|
2963
|
-
return { x: p.cx - d - w, y: p.cy + d, w, h: poiLabH };
|
|
2964
|
-
}
|
|
2965
|
-
case "above-right": {
|
|
2966
|
-
const d = (p.r + GAP2) * 0.7071;
|
|
2967
|
-
return { x: p.cx + d, y: p.cy - d - poiLabH, w, h: poiLabH };
|
|
2968
|
-
}
|
|
2969
|
-
case "above-left": {
|
|
2970
|
-
const d = (p.r + GAP2) * 0.7071;
|
|
2971
|
-
return { x: p.cx - d - w, y: p.cy - d - poiLabH, w, h: poiLabH };
|
|
2972
|
-
}
|
|
2973
|
-
}
|
|
2974
|
-
};
|
|
3017
|
+
const inlineRect = (p, w, side) => dotLabelRect(p, w, poiLabH, side);
|
|
2975
3018
|
const pushInline = (p, text, w, side, clusterId) => {
|
|
2976
3019
|
const rect = inlineRect(p, w, side);
|
|
2977
3020
|
obstacles.push(rect);
|
|
@@ -2992,10 +3035,6 @@ function layoutMap(resolvedIn, data, size, opts) {
|
|
|
2992
3035
|
...clusterId !== void 0 && { clusterMember: clusterId }
|
|
2993
3036
|
});
|
|
2994
3037
|
};
|
|
2995
|
-
const inlineFits = (p, w, side) => {
|
|
2996
|
-
const rect = inlineRect(p, w, side);
|
|
2997
|
-
return rect.x >= 0 && rect.x + rect.w <= width && rect.y >= 0 && rect.y + rect.h <= height && !collides(rect);
|
|
2998
|
-
};
|
|
2999
3038
|
const GROUP_R = 30;
|
|
3000
3039
|
const groups2 = [];
|
|
3001
3040
|
for (const p of ordered) {
|
|
@@ -3135,7 +3174,7 @@ function layoutMap(resolvedIn, data, size, opts) {
|
|
|
3135
3174
|
];
|
|
3136
3175
|
const side = order.find((s) => {
|
|
3137
3176
|
const rect = inlineRect(p, w, s);
|
|
3138
|
-
return rect
|
|
3177
|
+
return dotLabelFits(rect, width, height, collides) && !temp.some((t) => rectsOverlap(t, rect));
|
|
3139
3178
|
});
|
|
3140
3179
|
if (side === void 0) return false;
|
|
3141
3180
|
temp.push(inlineRect(p, w, side));
|
|
@@ -3154,62 +3193,28 @@ function layoutMap(resolvedIn, data, size, opts) {
|
|
|
3154
3193
|
const side = cleanR && cleanL ? defaultColumnSide(items) : cleanR ? "right" : cleanL ? "left" : defaultColumnSide(items);
|
|
3155
3194
|
commitColumn(items, side, clusterId);
|
|
3156
3195
|
}
|
|
3157
|
-
const CLEAR_CAP = 48;
|
|
3158
|
-
const CLEAR_W = 8;
|
|
3159
|
-
const WATER_W = 0.25;
|
|
3160
|
-
const ptSegDist = (px, py, ax, ay, bx, by) => {
|
|
3161
|
-
const dx = bx - ax;
|
|
3162
|
-
const dy = by - ay;
|
|
3163
|
-
const len2 = dx * dx + dy * dy;
|
|
3164
|
-
let t = len2 > 0 ? ((px - ax) * dx + (py - ay) * dy) / len2 : 0;
|
|
3165
|
-
t = Math.max(0, Math.min(1, t));
|
|
3166
|
-
return Math.hypot(px - (ax + t * dx), py - (ay + t * dy));
|
|
3167
|
-
};
|
|
3168
|
-
const clearanceOf = (rect, ownId) => {
|
|
3169
|
-
const cxL = rect.x + rect.w / 2;
|
|
3170
|
-
const cyL = rect.y + rect.h / 2;
|
|
3171
|
-
let d = CLEAR_CAP;
|
|
3172
|
-
for (const q of pois) {
|
|
3173
|
-
if (q.id === ownId) continue;
|
|
3174
|
-
d = Math.min(d, Math.hypot(q.cx - cxL, q.cy - cyL) - q.r);
|
|
3175
|
-
}
|
|
3176
|
-
for (const s of legSegments)
|
|
3177
|
-
d = Math.min(d, ptSegDist(cxL, cyL, s[0], s[1], s[2], s[3]));
|
|
3178
|
-
return Math.max(0, d);
|
|
3179
|
-
};
|
|
3180
|
-
const LEGIBILITY = {
|
|
3181
|
-
right: 160,
|
|
3182
|
-
left: 160,
|
|
3183
|
-
above: 100,
|
|
3184
|
-
below: 100,
|
|
3185
|
-
"below-right": 0,
|
|
3186
|
-
"below-left": 0,
|
|
3187
|
-
"above-right": 0,
|
|
3188
|
-
"above-left": 0
|
|
3189
|
-
};
|
|
3190
|
-
const ALL_SIDES = Object.keys(LEGIBILITY);
|
|
3191
|
-
const placementScore = (p, w, side) => {
|
|
3192
|
-
const rect = inlineRect(p, w, side);
|
|
3193
|
-
return CLEAR_W * clearanceOf(rect, p.id) + WATER_W * openness(rect) + LEGIBILITY[side];
|
|
3194
|
-
};
|
|
3195
3196
|
const maxExtent = MAX_CLUSTER_EXTENT_FACTOR * Math.min(width, height);
|
|
3196
3197
|
const clusterPending = [];
|
|
3197
3198
|
for (const g of groups2) {
|
|
3198
3199
|
const items = makeItems(g);
|
|
3199
3200
|
if (g.length === 1) {
|
|
3200
3201
|
const { p, text, w } = items[0];
|
|
3201
|
-
const
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3202
|
+
const placed = placeDotLabel({
|
|
3203
|
+
dot: p,
|
|
3204
|
+
w,
|
|
3205
|
+
h: poiLabH,
|
|
3206
|
+
width,
|
|
3207
|
+
height,
|
|
3208
|
+
collides,
|
|
3209
|
+
dots: pois,
|
|
3210
|
+
segments: legSegments,
|
|
3211
|
+
openness
|
|
3212
|
+
});
|
|
3213
|
+
if (placed === null) {
|
|
3208
3214
|
commitColumn(items, defaultColumnSide(items));
|
|
3209
3215
|
continue;
|
|
3210
3216
|
}
|
|
3211
|
-
|
|
3212
|
-
pushInline(p, text, w, side);
|
|
3217
|
+
pushInline(p, text, w, placed.side);
|
|
3213
3218
|
continue;
|
|
3214
3219
|
}
|
|
3215
3220
|
const left = Math.min(...items.map((o) => o.p.cx - o.p.r));
|