@phin-tech/dottie 0.5.4 → 0.6.1
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/PARITY.md +3 -0
- package/dist/compile.js +41 -4
- package/dist/dottie-compile.mjs +42 -5
- package/dist/dottie-player.js +103 -12
- package/dist/dottie-player.min.js +52 -50
- package/dist/dottie.js +102 -12
- package/dist/types/cli.d.ts +1 -0
- package/dist/types/clicks.d.ts +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/model.d.ts +26 -0
- package/dist/types/svg.d.ts +4 -2
- package/package.json +1 -1
package/PARITY.md
CHANGED
|
@@ -22,6 +22,8 @@ fixture, so the gap is visible rather than silent.
|
|
|
22
22
|
| Pages | Supported | [edge/themes](../fixtures/edge/themes.dottie) | `page` attribute or option: name or number |
|
|
23
23
|
| Connectors: straight, curved, elbow | Supported | [edge/connectors](../fixtures/edge/connectors.dottie) | |
|
|
24
24
|
| Ports and edge-following, rotated shapes, free ends | Supported | [edge/connectors](../fixtures/edge/connectors.dottie) | |
|
|
25
|
+
| Connectors and labels on outlines (ADR 0001) | Supported | [edge/extensions](../fixtures/edge/extensions.dottie) | Edge-following meets a `.path`'s actual outline, not its box (ray against 16-step flattened curves). Endpoints pinned with `portIndex` attach to the element's `ports`. A path's label goes in its `labelRect`. |
|
|
26
|
+
| Extension shapes as stored (ADR 0001) | Supported | [edge/extensions](../fixtures/edge/extensions.dottie) | Drawn from the stored path with no extension installed. The `extension` field is kept as metadata and nothing runs. Parameters, commands and handles are Dottie-only. |
|
|
25
27
|
| Arrowheads: arrow, triangle, dot, bar | Supported | [edge/connectors](../fixtures/edge/connectors.dottie) | |
|
|
26
28
|
| Connector labels | Supported | [edge/connectors](../fixtures/edge/connectors.dottie) | Label boxes sized with CoreText's measurements. The player paints them on the page color, like the app; Dottie's flipbook export leaves them unpainted |
|
|
27
29
|
| Keys and eases (linear, in, out, in-out, hold, spring, bounce, elastic) | Supported | [edge/timeline](../fixtures/edge/timeline.dottie), [edge/eases](../fixtures/edge/eases.dottie) | Unknown ease names play linear, with a warning |
|
|
@@ -43,6 +45,7 @@ fixture, so the gap is visible rather than silent.
|
|
|
43
45
|
| Symbol parameters (`{{name}}` in a symbol's text, filled per copy) | Supported | [edge/params](../fixtures/edge/params.dottie) | Defaults, undeclared names left as written, values passed into nested copies, filled before text types out |
|
|
44
46
|
| Copies that play when clicked | Supported | [edge/buttons](../fixtures/edge/buttons.dottie) | `<dottie-player>` only: the HTML export is drawn ahead of time and shows them at rest |
|
|
45
47
|
| Clicks: play a scene, open a link, hover looks, keyboard | Supported | [edge/clicks](../fixtures/edge/clicks.dottie) | As the HTML export does; only http, https and mailto links are followed |
|
|
48
|
+
| Links out of the drawing (`url`) | Supported | [edge/links](../fixtures/edge/links.dottie) | A web or mail `url` opens when clicked if there is no `click`, and SVG export wraps it in `<a>`; a link to another drawing does nothing on the web |
|
|
46
49
|
| Links between shapes and pages | Partial | [edge/clicks](../fixtures/edge/clicks.dottie) | A link to a shape on another page shows that page; one on the same page does nothing. The HTML export holds one page, so it has neither |
|
|
47
50
|
| Editing | Missing | | |
|
|
48
51
|
| Ticking task boxes in notes | Missing | | Drawn, not clickable |
|
package/dist/compile.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! dottie.js 0.
|
|
1
|
+
/*! dottie.js 0.6.1 | Apache-2.0 | https://github.com/phin-tech/dottie */
|
|
2
2
|
var __defProp = Object.defineProperty;
|
|
3
3
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
4
4
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
@@ -33,6 +33,7 @@ var KNOWN_FIELDS = {
|
|
|
33
33
|
"evenOdd",
|
|
34
34
|
"rotation",
|
|
35
35
|
"link",
|
|
36
|
+
"url",
|
|
36
37
|
"anchor",
|
|
37
38
|
"click",
|
|
38
39
|
"hover",
|
|
@@ -41,12 +42,18 @@ var KNOWN_FIELDS = {
|
|
|
41
42
|
"offset",
|
|
42
43
|
"args",
|
|
43
44
|
"image",
|
|
44
|
-
"reveal"
|
|
45
|
+
"reveal",
|
|
46
|
+
"ports",
|
|
47
|
+
"labelRect",
|
|
48
|
+
"extension"
|
|
45
49
|
],
|
|
46
50
|
strokePoint: ["x", "y"],
|
|
47
51
|
subpath: ["closed", "coords"],
|
|
48
52
|
inlineImage: ["data", "format"],
|
|
49
|
-
endpoint: ["elementID", "port", "x", "y"],
|
|
53
|
+
endpoint: ["elementID", "port", "portIndex", "x", "y"],
|
|
54
|
+
extensionRef: ["id", "shape", "version", "params"],
|
|
55
|
+
normalizedPoint: ["x", "y"],
|
|
56
|
+
normalizedRect: ["x", "y", "width", "height"],
|
|
50
57
|
connector: ["start", "end", "routing", "startHead", "endHead"],
|
|
51
58
|
timeline: ["fps", "duration", "boil", "settle", "poster", "tracks", "camera", "markers"],
|
|
52
59
|
track: ["element", "keys", "boil", "follow", "repeats", "march"],
|
|
@@ -129,9 +136,11 @@ var Reader = class {
|
|
|
129
136
|
endpoint(v) {
|
|
130
137
|
const e = isObj(v) ? v : {};
|
|
131
138
|
const port = str(e.port);
|
|
139
|
+
const portIndex = num(e.portIndex);
|
|
132
140
|
return {
|
|
133
141
|
elementID: uuid(e.elementID) ?? null,
|
|
134
142
|
port: port && ["top", "right", "bottom", "left"].includes(port) ? port : null,
|
|
143
|
+
portIndex: portIndex !== void 0 && Number.isInteger(portIndex) && portIndex >= 0 ? portIndex : null,
|
|
135
144
|
x: num(e.x) ?? 0,
|
|
136
145
|
y: num(e.y) ?? 0
|
|
137
146
|
};
|
|
@@ -196,6 +205,7 @@ var Reader = class {
|
|
|
196
205
|
evenOdd: bool(v.evenOdd) ?? null,
|
|
197
206
|
rotation: num(v.rotation) ?? null,
|
|
198
207
|
link: uuid(v.link) ?? null,
|
|
208
|
+
url: str(v.url) ?? null,
|
|
199
209
|
anchor: str(v.anchor) ?? null,
|
|
200
210
|
click: this.click(v.click),
|
|
201
211
|
hover: this.hover(v.hover),
|
|
@@ -204,9 +214,36 @@ var Reader = class {
|
|
|
204
214
|
offset: num(v.offset) ?? null,
|
|
205
215
|
args: strings(v.args),
|
|
206
216
|
image: this.image(v.image, images),
|
|
207
|
-
reveal: num(v.reveal) ?? null
|
|
217
|
+
reveal: num(v.reveal) ?? null,
|
|
218
|
+
ports: Array.isArray(v.ports) ? v.ports.map((p) => {
|
|
219
|
+
const o = isObj(p) ? p : {};
|
|
220
|
+
return { x: num(o.x) ?? 0, y: num(o.y) ?? 0 };
|
|
221
|
+
}) : null,
|
|
222
|
+
labelRect: this.labelRect(v.labelRect),
|
|
223
|
+
extension: this.extension(v.extension)
|
|
208
224
|
};
|
|
209
225
|
}
|
|
226
|
+
labelRect(v) {
|
|
227
|
+
if (!isObj(v)) return null;
|
|
228
|
+
this.fields(v, "normalizedRect");
|
|
229
|
+
return { x: num(v.x) ?? 0, y: num(v.y) ?? 0, width: num(v.width) ?? 0, height: num(v.height) ?? 0 };
|
|
230
|
+
}
|
|
231
|
+
extension(v) {
|
|
232
|
+
if (!isObj(v)) return null;
|
|
233
|
+
this.fields(v, "extensionRef");
|
|
234
|
+
const id = str(v.id), shape = str(v.shape), version = str(v.version);
|
|
235
|
+
if (id === void 0 || shape === void 0 || version === void 0) {
|
|
236
|
+
this.warn("Skipped an extension without an id, shape or version");
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
const params = {};
|
|
240
|
+
if (isObj(v.params)) {
|
|
241
|
+
for (const [k, p] of Object.entries(v.params)) {
|
|
242
|
+
if (typeof p === "number" || typeof p === "boolean" || typeof p === "string") params[k] = p;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return { id, shape, version, params };
|
|
246
|
+
}
|
|
210
247
|
click(v) {
|
|
211
248
|
if (!isObj(v)) return null;
|
|
212
249
|
this.fields(v, "click");
|
package/dist/dottie-compile.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
/*! dottie.js 0.
|
|
2
|
+
/*! dottie.js 0.6.1 | Apache-2.0 | https://github.com/phin-tech/dottie */
|
|
3
3
|
var __defProp = Object.defineProperty;
|
|
4
4
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
5
5
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
@@ -38,6 +38,7 @@ var KNOWN_FIELDS = {
|
|
|
38
38
|
"evenOdd",
|
|
39
39
|
"rotation",
|
|
40
40
|
"link",
|
|
41
|
+
"url",
|
|
41
42
|
"anchor",
|
|
42
43
|
"click",
|
|
43
44
|
"hover",
|
|
@@ -46,12 +47,18 @@ var KNOWN_FIELDS = {
|
|
|
46
47
|
"offset",
|
|
47
48
|
"args",
|
|
48
49
|
"image",
|
|
49
|
-
"reveal"
|
|
50
|
+
"reveal",
|
|
51
|
+
"ports",
|
|
52
|
+
"labelRect",
|
|
53
|
+
"extension"
|
|
50
54
|
],
|
|
51
55
|
strokePoint: ["x", "y"],
|
|
52
56
|
subpath: ["closed", "coords"],
|
|
53
57
|
inlineImage: ["data", "format"],
|
|
54
|
-
endpoint: ["elementID", "port", "x", "y"],
|
|
58
|
+
endpoint: ["elementID", "port", "portIndex", "x", "y"],
|
|
59
|
+
extensionRef: ["id", "shape", "version", "params"],
|
|
60
|
+
normalizedPoint: ["x", "y"],
|
|
61
|
+
normalizedRect: ["x", "y", "width", "height"],
|
|
55
62
|
connector: ["start", "end", "routing", "startHead", "endHead"],
|
|
56
63
|
timeline: ["fps", "duration", "boil", "settle", "poster", "tracks", "camera", "markers"],
|
|
57
64
|
track: ["element", "keys", "boil", "follow", "repeats", "march"],
|
|
@@ -134,9 +141,11 @@ var Reader = class {
|
|
|
134
141
|
endpoint(v) {
|
|
135
142
|
const e = isObj(v) ? v : {};
|
|
136
143
|
const port = str(e.port);
|
|
144
|
+
const portIndex = num(e.portIndex);
|
|
137
145
|
return {
|
|
138
146
|
elementID: uuid(e.elementID) ?? null,
|
|
139
147
|
port: port && ["top", "right", "bottom", "left"].includes(port) ? port : null,
|
|
148
|
+
portIndex: portIndex !== void 0 && Number.isInteger(portIndex) && portIndex >= 0 ? portIndex : null,
|
|
140
149
|
x: num(e.x) ?? 0,
|
|
141
150
|
y: num(e.y) ?? 0
|
|
142
151
|
};
|
|
@@ -201,6 +210,7 @@ var Reader = class {
|
|
|
201
210
|
evenOdd: bool(v.evenOdd) ?? null,
|
|
202
211
|
rotation: num(v.rotation) ?? null,
|
|
203
212
|
link: uuid(v.link) ?? null,
|
|
213
|
+
url: str(v.url) ?? null,
|
|
204
214
|
anchor: str(v.anchor) ?? null,
|
|
205
215
|
click: this.click(v.click),
|
|
206
216
|
hover: this.hover(v.hover),
|
|
@@ -209,9 +219,36 @@ var Reader = class {
|
|
|
209
219
|
offset: num(v.offset) ?? null,
|
|
210
220
|
args: strings(v.args),
|
|
211
221
|
image: this.image(v.image, images),
|
|
212
|
-
reveal: num(v.reveal) ?? null
|
|
222
|
+
reveal: num(v.reveal) ?? null,
|
|
223
|
+
ports: Array.isArray(v.ports) ? v.ports.map((p) => {
|
|
224
|
+
const o = isObj(p) ? p : {};
|
|
225
|
+
return { x: num(o.x) ?? 0, y: num(o.y) ?? 0 };
|
|
226
|
+
}) : null,
|
|
227
|
+
labelRect: this.labelRect(v.labelRect),
|
|
228
|
+
extension: this.extension(v.extension)
|
|
213
229
|
};
|
|
214
230
|
}
|
|
231
|
+
labelRect(v) {
|
|
232
|
+
if (!isObj(v)) return null;
|
|
233
|
+
this.fields(v, "normalizedRect");
|
|
234
|
+
return { x: num(v.x) ?? 0, y: num(v.y) ?? 0, width: num(v.width) ?? 0, height: num(v.height) ?? 0 };
|
|
235
|
+
}
|
|
236
|
+
extension(v) {
|
|
237
|
+
if (!isObj(v)) return null;
|
|
238
|
+
this.fields(v, "extensionRef");
|
|
239
|
+
const id = str(v.id), shape = str(v.shape), version = str(v.version);
|
|
240
|
+
if (id === void 0 || shape === void 0 || version === void 0) {
|
|
241
|
+
this.warn("Skipped an extension without an id, shape or version");
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
const params = {};
|
|
245
|
+
if (isObj(v.params)) {
|
|
246
|
+
for (const [k, p] of Object.entries(v.params)) {
|
|
247
|
+
if (typeof p === "number" || typeof p === "boolean" || typeof p === "string") params[k] = p;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return { id, shape, version, params };
|
|
251
|
+
}
|
|
215
252
|
click(v) {
|
|
216
253
|
if (!isObj(v)) return null;
|
|
217
254
|
this.fields(v, "click");
|
|
@@ -491,7 +528,7 @@ function compile(source2, runtime, options2 = {}) {
|
|
|
491
528
|
}
|
|
492
529
|
|
|
493
530
|
// src/index.ts
|
|
494
|
-
var VERSION = "0.
|
|
531
|
+
var VERSION = "0.6.1";
|
|
495
532
|
|
|
496
533
|
// src/cli.ts
|
|
497
534
|
var usage = `dottie-compile ${VERSION}: a Dottie drawing as one script that plays it on any page.
|
package/dist/dottie-player.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! dottie.js 0.
|
|
1
|
+
/*! dottie.js 0.6.1 | Apache-2.0 | https://github.com/phin-tech/dottie */
|
|
2
2
|
var __defProp = Object.defineProperty;
|
|
3
3
|
var __defNormalProp = (obj, key, value2) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value: value2 }) : obj[key] = value2;
|
|
4
4
|
var __export = (target, all) => {
|
|
@@ -56,6 +56,7 @@ __export(index_exports, {
|
|
|
56
56
|
themeNamed: () => themeNamed,
|
|
57
57
|
themes: () => themes,
|
|
58
58
|
transientElements: () => transientElements,
|
|
59
|
+
webLink: () => webLink,
|
|
59
60
|
withRoughness: () => withRoughness
|
|
60
61
|
});
|
|
61
62
|
|
|
@@ -89,6 +90,7 @@ var KNOWN_FIELDS = {
|
|
|
89
90
|
"evenOdd",
|
|
90
91
|
"rotation",
|
|
91
92
|
"link",
|
|
93
|
+
"url",
|
|
92
94
|
"anchor",
|
|
93
95
|
"click",
|
|
94
96
|
"hover",
|
|
@@ -97,12 +99,18 @@ var KNOWN_FIELDS = {
|
|
|
97
99
|
"offset",
|
|
98
100
|
"args",
|
|
99
101
|
"image",
|
|
100
|
-
"reveal"
|
|
102
|
+
"reveal",
|
|
103
|
+
"ports",
|
|
104
|
+
"labelRect",
|
|
105
|
+
"extension"
|
|
101
106
|
],
|
|
102
107
|
strokePoint: ["x", "y"],
|
|
103
108
|
subpath: ["closed", "coords"],
|
|
104
109
|
inlineImage: ["data", "format"],
|
|
105
|
-
endpoint: ["elementID", "port", "x", "y"],
|
|
110
|
+
endpoint: ["elementID", "port", "portIndex", "x", "y"],
|
|
111
|
+
extensionRef: ["id", "shape", "version", "params"],
|
|
112
|
+
normalizedPoint: ["x", "y"],
|
|
113
|
+
normalizedRect: ["x", "y", "width", "height"],
|
|
106
114
|
connector: ["start", "end", "routing", "startHead", "endHead"],
|
|
107
115
|
timeline: ["fps", "duration", "boil", "settle", "poster", "tracks", "camera", "markers"],
|
|
108
116
|
track: ["element", "keys", "boil", "follow", "repeats", "march"],
|
|
@@ -141,6 +149,9 @@ function allowedURL(url) {
|
|
|
141
149
|
if (!/^(https?:\/\/|mailto:)/i.test(u) || [...u].length <= 7 || /[\u0000-\u001f\u007f-\u009f]/.test(u)) return null;
|
|
142
150
|
return u;
|
|
143
151
|
}
|
|
152
|
+
function webLink(url) {
|
|
153
|
+
return url ? allowedURL(url) : null;
|
|
154
|
+
}
|
|
144
155
|
function rgba(v) {
|
|
145
156
|
if (!isObj(v)) return void 0;
|
|
146
157
|
const r = num(v.r), g = num(v.g), b = num(v.b);
|
|
@@ -187,9 +198,11 @@ var Reader = class {
|
|
|
187
198
|
endpoint(v) {
|
|
188
199
|
const e = isObj(v) ? v : {};
|
|
189
200
|
const port = str(e.port);
|
|
201
|
+
const portIndex = num(e.portIndex);
|
|
190
202
|
return {
|
|
191
203
|
elementID: uuid(e.elementID) ?? null,
|
|
192
204
|
port: port && ["top", "right", "bottom", "left"].includes(port) ? port : null,
|
|
205
|
+
portIndex: portIndex !== void 0 && Number.isInteger(portIndex) && portIndex >= 0 ? portIndex : null,
|
|
193
206
|
x: num(e.x) ?? 0,
|
|
194
207
|
y: num(e.y) ?? 0
|
|
195
208
|
};
|
|
@@ -254,6 +267,7 @@ var Reader = class {
|
|
|
254
267
|
evenOdd: bool(v.evenOdd) ?? null,
|
|
255
268
|
rotation: num(v.rotation) ?? null,
|
|
256
269
|
link: uuid(v.link) ?? null,
|
|
270
|
+
url: str(v.url) ?? null,
|
|
257
271
|
anchor: str(v.anchor) ?? null,
|
|
258
272
|
click: this.click(v.click),
|
|
259
273
|
hover: this.hover(v.hover),
|
|
@@ -262,9 +276,36 @@ var Reader = class {
|
|
|
262
276
|
offset: num(v.offset) ?? null,
|
|
263
277
|
args: strings(v.args),
|
|
264
278
|
image: this.image(v.image, images),
|
|
265
|
-
reveal: num(v.reveal) ?? null
|
|
279
|
+
reveal: num(v.reveal) ?? null,
|
|
280
|
+
ports: Array.isArray(v.ports) ? v.ports.map((p) => {
|
|
281
|
+
const o = isObj(p) ? p : {};
|
|
282
|
+
return { x: num(o.x) ?? 0, y: num(o.y) ?? 0 };
|
|
283
|
+
}) : null,
|
|
284
|
+
labelRect: this.labelRect(v.labelRect),
|
|
285
|
+
extension: this.extension(v.extension)
|
|
266
286
|
};
|
|
267
287
|
}
|
|
288
|
+
labelRect(v) {
|
|
289
|
+
if (!isObj(v)) return null;
|
|
290
|
+
this.fields(v, "normalizedRect");
|
|
291
|
+
return { x: num(v.x) ?? 0, y: num(v.y) ?? 0, width: num(v.width) ?? 0, height: num(v.height) ?? 0 };
|
|
292
|
+
}
|
|
293
|
+
extension(v) {
|
|
294
|
+
if (!isObj(v)) return null;
|
|
295
|
+
this.fields(v, "extensionRef");
|
|
296
|
+
const id = str(v.id), shape = str(v.shape), version = str(v.version);
|
|
297
|
+
if (id === void 0 || shape === void 0 || version === void 0) {
|
|
298
|
+
this.warn("Skipped an extension without an id, shape or version");
|
|
299
|
+
return null;
|
|
300
|
+
}
|
|
301
|
+
const params = {};
|
|
302
|
+
if (isObj(v.params)) {
|
|
303
|
+
for (const [k, p] of Object.entries(v.params)) {
|
|
304
|
+
if (typeof p === "number" || typeof p === "boolean" || typeof p === "string") params[k] = p;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return { id, shape, version, params };
|
|
308
|
+
}
|
|
268
309
|
click(v) {
|
|
269
310
|
if (!isObj(v)) return null;
|
|
270
311
|
this.fields(v, "click");
|
|
@@ -770,12 +811,45 @@ function portPoint(shape, port) {
|
|
|
770
811
|
const p = port === "top" ? { x: midX(r), y: r.y } : port === "right" ? { x: maxX(r), y: midY(r) } : port === "bottom" ? { x: midX(r), y: maxY(r) } : { x: r.x, y: midY(r) };
|
|
771
812
|
return rotated(shape, p);
|
|
772
813
|
}
|
|
814
|
+
function flattenContour(cp) {
|
|
815
|
+
const out = [];
|
|
816
|
+
for (let s = 0; s + 3 < cp.length; s += 3) {
|
|
817
|
+
const seg = cp.slice(s, s + 4);
|
|
818
|
+
for (let k = 0; k < 16; k++) out.push(bezierPoint(seg, k / 16));
|
|
819
|
+
}
|
|
820
|
+
out.push(cp[cp.length - 1]);
|
|
821
|
+
return out;
|
|
822
|
+
}
|
|
823
|
+
function outlineCrossing(shape, c, d) {
|
|
824
|
+
let nearest2 = null, farthest = null;
|
|
825
|
+
for (const contour of shapeContours(shape)) {
|
|
826
|
+
const pts = flattenContour(contour.points);
|
|
827
|
+
const n = pts.length;
|
|
828
|
+
const edges = contour.closed ? n : n - 1;
|
|
829
|
+
for (let i = 0; i < edges; i++) {
|
|
830
|
+
const a = pts[i], b = pts[(i + 1) % n];
|
|
831
|
+
const e = { x: b.x - a.x, y: b.y - a.y }, w = { x: a.x - c.x, y: a.y - c.y };
|
|
832
|
+
const det = e.x * d.y - d.x * e.y;
|
|
833
|
+
if (det === 0) continue;
|
|
834
|
+
const t = (e.x * w.y - e.y * w.x) / det, s = (d.x * w.y - d.y * w.x) / det;
|
|
835
|
+
if (!(t > 0 && s >= 0 && s <= 1)) continue;
|
|
836
|
+
if (nearest2 === null || t < nearest2) nearest2 = t;
|
|
837
|
+
if (t <= 1 && (farthest === null || t > farthest)) farthest = t;
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
const best = farthest ?? nearest2;
|
|
841
|
+
return best === null ? null : { x: c.x + d.x * best, y: c.y + d.y * best };
|
|
842
|
+
}
|
|
773
843
|
function edgePoint(shape, toward) {
|
|
774
844
|
const r = frame(shape);
|
|
775
845
|
const c = center(shape);
|
|
776
846
|
const target = unrotated(shape, toward);
|
|
777
847
|
const dx = target.x - c.x, dy = target.y - c.y;
|
|
778
848
|
if (!((dx !== 0 || dy !== 0) && r.width > 0 && r.height > 0)) return c;
|
|
849
|
+
if (shape.kind === "path") {
|
|
850
|
+
const hit = outlineCrossing(shape, c, { x: dx, y: dy });
|
|
851
|
+
if (hit) return rotated(shape, hit);
|
|
852
|
+
}
|
|
779
853
|
const hw = r.width / 2, hh = r.height / 2;
|
|
780
854
|
let t;
|
|
781
855
|
if (shape.kind === "ellipse") t = 1 / Math.sqrt(dx * dx / (hw * hw) + dy * dy / (hh * hh));
|
|
@@ -787,9 +861,15 @@ function reference(ep, index) {
|
|
|
787
861
|
const s = ep.elementID ? index.get(ep.elementID) : void 0;
|
|
788
862
|
return s ? center(s) : { x: ep.x, y: ep.y };
|
|
789
863
|
}
|
|
864
|
+
function normalizedPoint(shape, p) {
|
|
865
|
+
const r = frame(shape);
|
|
866
|
+
return rotated(shape, { x: r.x + p.x * r.width, y: r.y + p.y * r.height });
|
|
867
|
+
}
|
|
790
868
|
function resolve(ep, other, index) {
|
|
791
869
|
const s = ep.elementID ? index.get(ep.elementID) : void 0;
|
|
792
870
|
if (!s) return { x: ep.x, y: ep.y };
|
|
871
|
+
const i = ep.portIndex, ports = s.ports ?? [];
|
|
872
|
+
if (typeof i === "number" && Number.isInteger(i) && i >= 0 && i < ports.length) return normalizedPoint(s, ports[i]);
|
|
793
873
|
return ep.port ? portPoint(s, ep.port) : edgePoint(s, other);
|
|
794
874
|
}
|
|
795
875
|
function endpoints(e, index) {
|
|
@@ -1973,7 +2053,7 @@ function clickTargets(page, file) {
|
|
|
1973
2053
|
continue;
|
|
1974
2054
|
}
|
|
1975
2055
|
}
|
|
1976
|
-
const url = c?.url ? allowedURL(c.url) : null;
|
|
2056
|
+
const url = (c?.url ? allowedURL(c.url) : null) ?? webLink(e.url);
|
|
1977
2057
|
if (url) {
|
|
1978
2058
|
out.set(e.id, { url });
|
|
1979
2059
|
continue;
|
|
@@ -2773,8 +2853,8 @@ function svgOpen(b, background, paint) {
|
|
|
2773
2853
|
}
|
|
2774
2854
|
return out;
|
|
2775
2855
|
}
|
|
2776
|
-
function svgParts(page, background, fixed) {
|
|
2777
|
-
if (hasInstances(page)) return svgParts(expandingSymbols(page, 0), background, fixed);
|
|
2856
|
+
function svgParts(page, background, fixed, links = false) {
|
|
2857
|
+
if (hasInstances(page)) return svgParts(expandingSymbols(page, 0), background, fixed, links);
|
|
2778
2858
|
const theme = themeNamed(page.theme);
|
|
2779
2859
|
const bg = background ? theme?.background ?? background : null;
|
|
2780
2860
|
const ink = theme?.ink ?? black;
|
|
@@ -2798,14 +2878,19 @@ function svgParts(page, background, fixed) {
|
|
|
2798
2878
|
${body}</g>
|
|
2799
2879
|
`;
|
|
2800
2880
|
}
|
|
2801
|
-
|
|
2881
|
+
if (alpha < 1) body = `<g opacity="${fmt(alpha)}">
|
|
2802
2882
|
${body}</g>
|
|
2803
|
-
|
|
2883
|
+
`;
|
|
2884
|
+
const href = links ? (e.click?.url ? allowedURL(e.click.url) : null) ?? webLink(e.url) : null;
|
|
2885
|
+
if (href) body = `<a href="${escapeXML(href).replace(/"/g, """)}" target="_blank">
|
|
2886
|
+
${body}</a>
|
|
2887
|
+
`;
|
|
2888
|
+
parts.push({ key: e.id, markup: body });
|
|
2804
2889
|
}
|
|
2805
2890
|
return { bounds: b, parts };
|
|
2806
2891
|
}
|
|
2807
2892
|
function svg(page, background = { r: 1, g: 1, b: 1, a: 1 }, fixed) {
|
|
2808
|
-
const { bounds: b, parts } = svgParts(page, background, fixed);
|
|
2893
|
+
const { bounds: b, parts } = svgParts(page, background, fixed, true);
|
|
2809
2894
|
return svgOpen(b, themeNamed(page.theme)?.background ?? background, background !== null) + parts.map((p) => p.markup).join("") + "</svg>\n";
|
|
2810
2895
|
}
|
|
2811
2896
|
function labelRect(e, index) {
|
|
@@ -2900,7 +2985,7 @@ function svgElement(e, index, labelBackground) {
|
|
|
2900
2985
|
}
|
|
2901
2986
|
s += `<path d="${outline(e).data()}" fill="none" ${strokeAttrs}/>
|
|
2902
2987
|
`;
|
|
2903
|
-
if (text) s += e.kind === "note" ? noteMarkup(text, e) : textElement(text, frame(e), e, true);
|
|
2988
|
+
if (text) s += e.kind === "note" ? noteMarkup(text, e) : textElement(text, e.kind === "path" ? pathLabelBox(e) : frame(e), e, true);
|
|
2904
2989
|
return s;
|
|
2905
2990
|
}
|
|
2906
2991
|
default:
|
|
@@ -2913,6 +2998,11 @@ function placeholder(e, strokeAttrs) {
|
|
|
2913
2998
|
return `<path d="${p.data()}" fill="none" ${strokeAttrs} stroke-opacity="0.5" stroke-dasharray="6 4"/>
|
|
2914
2999
|
` + textElement(`${e.kind}${e.text ? `: ${e.text}` : ""}`, f, { ...e, style: { ...e.style, fontSize: Math.min(e.style.fontSize, 12) } }, true);
|
|
2915
3000
|
}
|
|
3001
|
+
function pathLabelBox(e) {
|
|
3002
|
+
const f = frame(e), r = e.labelRect;
|
|
3003
|
+
if (!r) return f;
|
|
3004
|
+
return { x: f.x + r.x * f.width, y: f.y + r.y * f.height, width: r.width * f.width, height: r.height * f.height };
|
|
3005
|
+
}
|
|
2916
3006
|
function textElement(text, f, e, centered) {
|
|
2917
3007
|
const size = e.style.fontSize;
|
|
2918
3008
|
const lines = text.split("\n");
|
|
@@ -3611,7 +3701,7 @@ function render(source, options = {}) {
|
|
|
3611
3701
|
function isFile(v) {
|
|
3612
3702
|
return typeof v === "object" && v !== null && Array.isArray(v.pages) && Array.isArray(v.warnings);
|
|
3613
3703
|
}
|
|
3614
|
-
var VERSION = "0.
|
|
3704
|
+
var VERSION = "0.6.1";
|
|
3615
3705
|
|
|
3616
3706
|
// src/player-entry.ts
|
|
3617
3707
|
definePlayer();
|
|
@@ -3663,5 +3753,6 @@ export {
|
|
|
3663
3753
|
themeNamed,
|
|
3664
3754
|
themes,
|
|
3665
3755
|
transientElements,
|
|
3756
|
+
webLink,
|
|
3666
3757
|
withRoughness
|
|
3667
3758
|
};
|