@tldraw/editor 3.16.0-canary.c2c4563957ce → 3.16.0-canary.c349490eaef0
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-cjs/index.d.ts +59 -4
- package/dist-cjs/index.js +3 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/TldrawEditor.js +1 -3
- package/dist-cjs/lib/TldrawEditor.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js +11 -1
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +38 -4
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/editor/derivations/notVisibleShapes.js +4 -0
- package/dist-cjs/lib/editor/derivations/notVisibleShapes.js.map +2 -2
- package/dist-cjs/lib/editor/managers/FocusManager/FocusManager.js +4 -2
- package/dist-cjs/lib/editor/managers/FocusManager/FocusManager.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js +10 -0
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
- package/dist-cjs/lib/hooks/useCanvasEvents.js +19 -16
- package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useDocumentEvents.js +5 -5
- package/dist-cjs/lib/hooks/useDocumentEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.js +1 -2
- package/dist-cjs/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useGestureEvents.js +1 -1
- package/dist-cjs/lib/hooks/useGestureEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useHandleEvents.js +6 -6
- package/dist-cjs/lib/hooks/useHandleEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useSelectionEvents.js +8 -8
- package/dist-cjs/lib/hooks/useSelectionEvents.js.map +2 -2
- package/dist-cjs/lib/license/LicenseManager.js +133 -38
- package/dist-cjs/lib/license/LicenseManager.js.map +2 -2
- package/dist-cjs/lib/license/LicenseProvider.js +36 -3
- package/dist-cjs/lib/license/LicenseProvider.js.map +2 -2
- package/dist-cjs/lib/license/Watermark.js +144 -75
- package/dist-cjs/lib/license/Watermark.js.map +3 -3
- package/dist-cjs/lib/primitives/geometry/Geometry2d.js +24 -2
- package/dist-cjs/lib/primitives/geometry/Geometry2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Group2d.js +5 -1
- package/dist-cjs/lib/primitives/geometry/Group2d.js.map +2 -2
- package/dist-cjs/lib/utils/dom.js.map +2 -2
- package/dist-cjs/lib/utils/getPointerInfo.js +2 -3
- package/dist-cjs/lib/utils/getPointerInfo.js.map +2 -2
- package/dist-cjs/version.js +3 -3
- package/dist-cjs/version.js.map +1 -1
- package/dist-esm/index.d.mts +59 -4
- package/dist-esm/index.mjs +3 -1
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/TldrawEditor.mjs +1 -3
- package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +11 -1
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +38 -4
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/editor/derivations/notVisibleShapes.mjs +4 -0
- package/dist-esm/lib/editor/derivations/notVisibleShapes.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/FocusManager/FocusManager.mjs +4 -2
- package/dist-esm/lib/editor/managers/FocusManager/FocusManager.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +10 -0
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/hooks/useCanvasEvents.mjs +20 -22
- package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useDocumentEvents.mjs +6 -6
- package/dist-esm/lib/hooks/useDocumentEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.mjs +1 -2
- package/dist-esm/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useGestureEvents.mjs +2 -2
- package/dist-esm/lib/hooks/useGestureEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useHandleEvents.mjs +6 -6
- package/dist-esm/lib/hooks/useHandleEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useSelectionEvents.mjs +9 -14
- package/dist-esm/lib/hooks/useSelectionEvents.mjs.map +2 -2
- package/dist-esm/lib/license/LicenseManager.mjs +134 -39
- package/dist-esm/lib/license/LicenseManager.mjs.map +2 -2
- package/dist-esm/lib/license/LicenseProvider.mjs +36 -4
- package/dist-esm/lib/license/LicenseProvider.mjs.map +2 -2
- package/dist-esm/lib/license/Watermark.mjs +145 -76
- package/dist-esm/lib/license/Watermark.mjs.map +3 -3
- package/dist-esm/lib/primitives/geometry/Geometry2d.mjs +24 -2
- package/dist-esm/lib/primitives/geometry/Geometry2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Group2d.mjs +5 -1
- package/dist-esm/lib/primitives/geometry/Group2d.mjs.map +2 -2
- package/dist-esm/lib/utils/dom.mjs.map +2 -2
- package/dist-esm/lib/utils/getPointerInfo.mjs +2 -3
- package/dist-esm/lib/utils/getPointerInfo.mjs.map +2 -2
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/editor.css +8 -3
- package/package.json +7 -7
- package/src/index.ts +1 -0
- package/src/lib/TldrawEditor.tsx +1 -4
- package/src/lib/components/default-components/DefaultCanvas.tsx +7 -1
- package/src/lib/editor/Editor.test.ts +90 -0
- package/src/lib/editor/Editor.ts +49 -4
- package/src/lib/editor/derivations/notVisibleShapes.ts +6 -0
- package/src/lib/editor/managers/FocusManager/FocusManager.ts +6 -2
- package/src/lib/editor/shapes/ShapeUtil.ts +11 -0
- package/src/lib/hooks/useCanvasEvents.ts +20 -20
- package/src/lib/hooks/useDocumentEvents.ts +6 -6
- package/src/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.ts +1 -1
- package/src/lib/hooks/useGestureEvents.ts +2 -2
- package/src/lib/hooks/useHandleEvents.ts +6 -6
- package/src/lib/hooks/useSelectionEvents.ts +9 -14
- package/src/lib/license/LicenseManager.test.ts +719 -387
- package/src/lib/license/LicenseManager.ts +187 -49
- package/src/lib/license/LicenseProvider.tsx +69 -5
- package/src/lib/license/Watermark.tsx +152 -77
- package/src/lib/primitives/geometry/Geometry2d.test.ts +420 -0
- package/src/lib/primitives/geometry/Geometry2d.ts +29 -2
- package/src/lib/primitives/geometry/Group2d.ts +6 -1
- package/src/lib/test/InFrontOfTheCanvas.test.tsx +187 -0
- package/src/lib/utils/dom.test.ts +103 -0
- package/src/lib/utils/dom.ts +8 -1
- package/src/lib/utils/getPointerInfo.ts +3 -2
- package/src/version.ts +3 -3
|
@@ -18,6 +18,7 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
var LicenseProvider_exports = {};
|
|
20
20
|
__export(LicenseProvider_exports, {
|
|
21
|
+
LICENSE_TIMEOUT: () => LICENSE_TIMEOUT,
|
|
21
22
|
LicenseContext: () => LicenseContext,
|
|
22
23
|
LicenseProvider: () => LicenseProvider,
|
|
23
24
|
useLicenseContext: () => useLicenseContext
|
|
@@ -27,17 +28,49 @@ var import_jsx_runtime = require("react/jsx-runtime");
|
|
|
27
28
|
var import_state_react = require("@tldraw/state-react");
|
|
28
29
|
var import_react = require("react");
|
|
29
30
|
var import_LicenseManager = require("./LicenseManager");
|
|
31
|
+
const import_meta = {};
|
|
30
32
|
const LicenseContext = (0, import_react.createContext)({});
|
|
31
33
|
const useLicenseContext = () => (0, import_react.useContext)(LicenseContext);
|
|
34
|
+
function shouldHideEditorAfterDelay(licenseState) {
|
|
35
|
+
return licenseState === "expired" || licenseState === "unlicensed-production";
|
|
36
|
+
}
|
|
37
|
+
const LICENSE_TIMEOUT = 5e3;
|
|
32
38
|
function LicenseProvider({
|
|
33
|
-
licenseKey,
|
|
39
|
+
licenseKey = getLicenseKeyFromEnv() ?? void 0,
|
|
34
40
|
children
|
|
35
41
|
}) {
|
|
36
42
|
const [licenseManager] = (0, import_react.useState)(() => new import_LicenseManager.LicenseManager(licenseKey));
|
|
37
43
|
const licenseState = (0, import_state_react.useValue)(licenseManager.state);
|
|
38
|
-
|
|
39
|
-
|
|
44
|
+
const [showEditor, setShowEditor] = (0, import_react.useState)(true);
|
|
45
|
+
(0, import_react.useEffect)(() => {
|
|
46
|
+
if (shouldHideEditorAfterDelay(licenseState) && showEditor) {
|
|
47
|
+
const timer = setTimeout(() => {
|
|
48
|
+
setShowEditor(false);
|
|
49
|
+
}, LICENSE_TIMEOUT);
|
|
50
|
+
return () => clearTimeout(timer);
|
|
51
|
+
}
|
|
52
|
+
}, [licenseState, showEditor]);
|
|
53
|
+
if (shouldHideEditorAfterDelay(licenseState) && !showEditor) {
|
|
54
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LicenseGate, {});
|
|
40
55
|
}
|
|
41
56
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LicenseContext.Provider, { value: licenseManager, children });
|
|
42
57
|
}
|
|
58
|
+
function LicenseGate() {
|
|
59
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { "data-testid": "tl-license-expired", style: { display: "none" } });
|
|
60
|
+
}
|
|
61
|
+
let envLicenseKey = void 0;
|
|
62
|
+
function getLicenseKeyFromEnv() {
|
|
63
|
+
if (envLicenseKey !== void 0) {
|
|
64
|
+
return envLicenseKey;
|
|
65
|
+
}
|
|
66
|
+
envLicenseKey = getEnv(() => process.env.TLDRAW_LICENSE_KEY) || getEnv(() => process.env.NEXT_PUBLIC_TLDRAW_LICENSE_KEY) || getEnv(() => process.env.REACT_APP_TLDRAW_LICENSE_KEY) || getEnv(() => process.env.GATSBY_TLDRAW_LICENSE_KEY) || getEnv(() => process.env.VITE_TLDRAW_LICENSE_KEY) || getEnv(() => process.env.PUBLIC_TLDRAW_LICENSE_KEY) || getEnv(() => import_meta.env.TLDRAW_LICENSE_KEY) || getEnv(() => import_meta.env.NEXT_PUBLIC_TLDRAW_LICENSE_KEY) || getEnv(() => import_meta.env.REACT_APP_TLDRAW_LICENSE_KEY) || getEnv(() => import_meta.env.GATSBY_TLDRAW_LICENSE_KEY) || getEnv(() => import_meta.env.VITE_TLDRAW_LICENSE_KEY) || getEnv(() => import_meta.env.PUBLIC_TLDRAW_LICENSE_KEY) || null;
|
|
67
|
+
return envLicenseKey;
|
|
68
|
+
}
|
|
69
|
+
function getEnv(cb) {
|
|
70
|
+
try {
|
|
71
|
+
return cb();
|
|
72
|
+
} catch {
|
|
73
|
+
return void 0;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
43
76
|
//# sourceMappingURL=LicenseProvider.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/license/LicenseProvider.tsx"],
|
|
4
|
-
"sourcesContent": ["import { useValue } from '@tldraw/state-react'\nimport { createContext, ReactNode, useContext, useState } from 'react'\nimport { LicenseManager } from './LicenseManager'\n\n/** @internal */\nexport const LicenseContext = createContext({} as LicenseManager)\n\n/** @internal */\nexport const useLicenseContext = () => useContext(LicenseContext)\n\n/** @internal */\nexport function LicenseProvider({\n\tlicenseKey,\n\tchildren,\n}: {\n\tlicenseKey?: string\n\tchildren: ReactNode\n}) {\n\tconst [licenseManager] = useState(() => new LicenseManager(licenseKey))\n\tconst licenseState = useValue(licenseManager.state)\n\n\t// If
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
4
|
+
"sourcesContent": ["import { useValue } from '@tldraw/state-react'\nimport { createContext, ReactNode, useContext, useEffect, useState } from 'react'\nimport { LicenseManager } from './LicenseManager'\n\n/** @internal */\nexport const LicenseContext = createContext({} as LicenseManager)\n\n/** @internal */\nexport const useLicenseContext = () => useContext(LicenseContext)\n\nfunction shouldHideEditorAfterDelay(licenseState: string): boolean {\n\treturn licenseState === 'expired' || licenseState === 'unlicensed-production'\n}\n\n/** @internal */\nexport const LICENSE_TIMEOUT = 5000\n\n/** @internal */\nexport function LicenseProvider({\n\tlicenseKey = getLicenseKeyFromEnv() ?? undefined,\n\tchildren,\n}: {\n\tlicenseKey?: string\n\tchildren: ReactNode\n}) {\n\tconst [licenseManager] = useState(() => new LicenseManager(licenseKey))\n\tconst licenseState = useValue(licenseManager.state)\n\tconst [showEditor, setShowEditor] = useState(true)\n\n\t// When license expires or no license in production, show for 5 seconds then hide\n\tuseEffect(() => {\n\t\tif (shouldHideEditorAfterDelay(licenseState) && showEditor) {\n\t\t\t// eslint-disable-next-line no-restricted-globals\n\t\t\tconst timer = setTimeout(() => {\n\t\t\t\tsetShowEditor(false)\n\t\t\t}, LICENSE_TIMEOUT)\n\n\t\t\treturn () => clearTimeout(timer)\n\t\t}\n\t}, [licenseState, showEditor])\n\n\t// If license is expired or no license in production and 5 seconds have passed, don't render anything (blank screen)\n\tif (shouldHideEditorAfterDelay(licenseState) && !showEditor) {\n\t\treturn <LicenseGate />\n\t}\n\n\treturn <LicenseContext.Provider value={licenseManager}>{children}</LicenseContext.Provider>\n}\n\n// Renders as a hidden div that can be detected by tests\nfunction LicenseGate() {\n\treturn <div data-testid=\"tl-license-expired\" style={{ display: 'none' }} />\n}\n\nlet envLicenseKey: string | undefined | null = undefined\nfunction getLicenseKeyFromEnv() {\n\tif (envLicenseKey !== undefined) {\n\t\treturn envLicenseKey\n\t}\n\t// it's important here that we write out the full process.env.WHATEVER expression instead of\n\t// doing something like process.env[someVariable]. This is because most bundlers do something\n\t// like a find-replace inject environment variables, and so won't pick up on dynamic ones. It\n\t// also means we can't do checks like `process.env && process.env.WHATEVER`, which is why we use\n\t// the `getEnv` try/catch approach.\n\n\t// framework-specific prefixes borrowed from the ones vercel uses, but trimmed down to just the\n\t// react-y ones: https://vercel.com/docs/environment-variables/framework-environment-variables\n\tenvLicenseKey =\n\t\tgetEnv(() => process.env.TLDRAW_LICENSE_KEY) ||\n\t\tgetEnv(() => process.env.NEXT_PUBLIC_TLDRAW_LICENSE_KEY) ||\n\t\tgetEnv(() => process.env.REACT_APP_TLDRAW_LICENSE_KEY) ||\n\t\tgetEnv(() => process.env.GATSBY_TLDRAW_LICENSE_KEY) ||\n\t\tgetEnv(() => process.env.VITE_TLDRAW_LICENSE_KEY) ||\n\t\tgetEnv(() => process.env.PUBLIC_TLDRAW_LICENSE_KEY) ||\n\t\tgetEnv(() => (import.meta as any).env.TLDRAW_LICENSE_KEY) ||\n\t\tgetEnv(() => (import.meta as any).env.NEXT_PUBLIC_TLDRAW_LICENSE_KEY) ||\n\t\tgetEnv(() => (import.meta as any).env.REACT_APP_TLDRAW_LICENSE_KEY) ||\n\t\tgetEnv(() => (import.meta as any).env.GATSBY_TLDRAW_LICENSE_KEY) ||\n\t\tgetEnv(() => (import.meta as any).env.VITE_TLDRAW_LICENSE_KEY) ||\n\t\tgetEnv(() => (import.meta as any).env.PUBLIC_TLDRAW_LICENSE_KEY) ||\n\t\tnull\n\n\treturn envLicenseKey\n}\n\nfunction getEnv(cb: () => string | undefined) {\n\ttry {\n\t\treturn cb()\n\t} catch {\n\t\treturn undefined\n\t}\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2CS;AA3CT,yBAAyB;AACzB,mBAA0E;AAC1E,4BAA+B;AAF/B;AAKO,MAAM,qBAAiB,4BAAc,CAAC,CAAmB;AAGzD,MAAM,oBAAoB,UAAM,yBAAW,cAAc;AAEhE,SAAS,2BAA2B,cAA+B;AAClE,SAAO,iBAAiB,aAAa,iBAAiB;AACvD;AAGO,MAAM,kBAAkB;AAGxB,SAAS,gBAAgB;AAAA,EAC/B,aAAa,qBAAqB,KAAK;AAAA,EACvC;AACD,GAGG;AACF,QAAM,CAAC,cAAc,QAAI,uBAAS,MAAM,IAAI,qCAAe,UAAU,CAAC;AACtE,QAAM,mBAAe,6BAAS,eAAe,KAAK;AAClD,QAAM,CAAC,YAAY,aAAa,QAAI,uBAAS,IAAI;AAGjD,8BAAU,MAAM;AACf,QAAI,2BAA2B,YAAY,KAAK,YAAY;AAE3D,YAAM,QAAQ,WAAW,MAAM;AAC9B,sBAAc,KAAK;AAAA,MACpB,GAAG,eAAe;AAElB,aAAO,MAAM,aAAa,KAAK;AAAA,IAChC;AAAA,EACD,GAAG,CAAC,cAAc,UAAU,CAAC;AAG7B,MAAI,2BAA2B,YAAY,KAAK,CAAC,YAAY;AAC5D,WAAO,4CAAC,eAAY;AAAA,EACrB;AAEA,SAAO,4CAAC,eAAe,UAAf,EAAwB,OAAO,gBAAiB,UAAS;AAClE;AAGA,SAAS,cAAc;AACtB,SAAO,4CAAC,SAAI,eAAY,sBAAqB,OAAO,EAAE,SAAS,OAAO,GAAG;AAC1E;AAEA,IAAI,gBAA2C;AAC/C,SAAS,uBAAuB;AAC/B,MAAI,kBAAkB,QAAW;AAChC,WAAO;AAAA,EACR;AASA,kBACC,OAAO,MAAM,QAAQ,IAAI,kBAAkB,KAC3C,OAAO,MAAM,QAAQ,IAAI,8BAA8B,KACvD,OAAO,MAAM,QAAQ,IAAI,4BAA4B,KACrD,OAAO,MAAM,QAAQ,IAAI,yBAAyB,KAClD,OAAO,MAAM,QAAQ,IAAI,uBAAuB,KAChD,OAAO,MAAM,QAAQ,IAAI,yBAAyB,KAClD,OAAO,MAAO,YAAoB,IAAI,kBAAkB,KACxD,OAAO,MAAO,YAAoB,IAAI,8BAA8B,KACpE,OAAO,MAAO,YAAoB,IAAI,4BAA4B,KAClE,OAAO,MAAO,YAAoB,IAAI,yBAAyB,KAC/D,OAAO,MAAO,YAAoB,IAAI,uBAAuB,KAC7D,OAAO,MAAO,YAAoB,IAAI,yBAAyB,KAC/D;AAED,SAAO;AACR;AAEA,SAAS,OAAO,IAA8B;AAC7C,MAAI;AACH,WAAO,GAAG;AAAA,EACX,QAAQ;AACP,WAAO;AAAA,EACR;AACD;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -45,10 +45,56 @@ const Watermark = (0, import_react.memo)(function Watermark2() {
|
|
|
45
45
|
if (!["licensed-with-watermark", "unlicensed"].includes(licenseManagerState)) return null;
|
|
46
46
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
47
47
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(LicenseStyles, {}),
|
|
48
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
48
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
49
|
+
WatermarkInner,
|
|
50
|
+
{
|
|
51
|
+
src: isMobile ? WATERMARK_MOBILE_LOCAL_SRC : WATERMARK_DESKTOP_LOCAL_SRC,
|
|
52
|
+
isUnlicensed: licenseManagerState === "unlicensed"
|
|
53
|
+
}
|
|
54
|
+
)
|
|
49
55
|
] });
|
|
50
56
|
});
|
|
51
|
-
const
|
|
57
|
+
const UnlicensedWatermark = (0, import_react.memo)(function UnlicensedWatermark2({
|
|
58
|
+
isDebugMode,
|
|
59
|
+
isMobile
|
|
60
|
+
}) {
|
|
61
|
+
const editor = (0, import_useEditor.useEditor)();
|
|
62
|
+
const events = (0, import_useCanvasEvents.useCanvasEvents)();
|
|
63
|
+
const ref = (0, import_react.useRef)(null);
|
|
64
|
+
(0, import_usePassThroughWheelEvents.usePassThroughWheelEvents)(ref);
|
|
65
|
+
const url = "https://tldraw.dev/pricing?utm_source=dotcom&utm_medium=organic&utm_campaign=watermark";
|
|
66
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
67
|
+
"div",
|
|
68
|
+
{
|
|
69
|
+
ref,
|
|
70
|
+
className: import_LicenseManager.LicenseManager.className,
|
|
71
|
+
"data-debug": isDebugMode,
|
|
72
|
+
"data-mobile": isMobile,
|
|
73
|
+
"data-unlicensed": true,
|
|
74
|
+
"data-testid": "tl-watermark-unlicensed",
|
|
75
|
+
draggable: false,
|
|
76
|
+
...events,
|
|
77
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
78
|
+
"button",
|
|
79
|
+
{
|
|
80
|
+
draggable: false,
|
|
81
|
+
role: "button",
|
|
82
|
+
onPointerDown: (e) => {
|
|
83
|
+
editor.markEventAsHandled(e);
|
|
84
|
+
(0, import_dom.preventDefault)(e);
|
|
85
|
+
},
|
|
86
|
+
title: "The tldraw SDK requires a license key to work in production. You can get a free 100-day trial license at tldraw.dev/pricing.",
|
|
87
|
+
onClick: () => import_runtime.runtime.openWindow(url, "_blank"),
|
|
88
|
+
children: "Get a license for production"
|
|
89
|
+
}
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
});
|
|
94
|
+
const WatermarkInner = (0, import_react.memo)(function WatermarkInner2({
|
|
95
|
+
src,
|
|
96
|
+
isUnlicensed
|
|
97
|
+
}) {
|
|
52
98
|
const editor = (0, import_useEditor.useEditor)();
|
|
53
99
|
const isDebugMode = (0, import_state_react.useValue)("debug mode", () => editor.getInstanceState().isDebugMode, [editor]);
|
|
54
100
|
const isMobile = (0, import_state_react.useValue)("is mobile", () => editor.getViewportScreenBounds().width < 700, [
|
|
@@ -59,6 +105,9 @@ const WatermarkInner = (0, import_react.memo)(function WatermarkInner2({ src })
|
|
|
59
105
|
(0, import_usePassThroughWheelEvents.usePassThroughWheelEvents)(ref);
|
|
60
106
|
const maskCss = `url('${src}') center 100% / 100% no-repeat`;
|
|
61
107
|
const url = "https://tldraw.dev/?utm_source=dotcom&utm_medium=organic&utm_campaign=watermark";
|
|
108
|
+
if (isUnlicensed) {
|
|
109
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(UnlicensedWatermark, { isDebugMode, isMobile });
|
|
110
|
+
}
|
|
62
111
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
63
112
|
"div",
|
|
64
113
|
{
|
|
@@ -66,6 +115,7 @@ const WatermarkInner = (0, import_react.memo)(function WatermarkInner2({ src })
|
|
|
66
115
|
className: import_LicenseManager.LicenseManager.className,
|
|
67
116
|
"data-debug": isDebugMode,
|
|
68
117
|
"data-mobile": isMobile,
|
|
118
|
+
"data-testid": "tl-watermark-licensed",
|
|
69
119
|
draggable: false,
|
|
70
120
|
...events,
|
|
71
121
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
@@ -74,10 +124,10 @@ const WatermarkInner = (0, import_react.memo)(function WatermarkInner2({ src })
|
|
|
74
124
|
draggable: false,
|
|
75
125
|
role: "button",
|
|
76
126
|
onPointerDown: (e) => {
|
|
77
|
-
|
|
127
|
+
editor.markEventAsHandled(e);
|
|
78
128
|
(0, import_dom.preventDefault)(e);
|
|
79
129
|
},
|
|
80
|
-
title: "
|
|
130
|
+
title: "Build infinite canvas applications with the tldraw SDK. Learn more at https://tldraw.dev.",
|
|
81
131
|
onClick: () => import_runtime.runtime.openWindow(url, "_blank"),
|
|
82
132
|
style: { mask: maskCss, WebkitMask: maskCss }
|
|
83
133
|
}
|
|
@@ -88,7 +138,8 @@ const WatermarkInner = (0, import_react.memo)(function WatermarkInner2({ src })
|
|
|
88
138
|
const LicenseStyles = (0, import_react.memo)(function LicenseStyles2() {
|
|
89
139
|
const editor = (0, import_useEditor.useEditor)();
|
|
90
140
|
const className = import_LicenseManager.LicenseManager.className;
|
|
91
|
-
const CSS =
|
|
141
|
+
const CSS = `
|
|
142
|
+
/* ------------------- SEE LICENSE -------------------
|
|
92
143
|
The tldraw watermark is part of tldraw's license. It is shown for unlicensed
|
|
93
144
|
or "licensed-with-watermark" users. By using this library, you agree to
|
|
94
145
|
preserve the watermark's behavior, keeping it visible, unobscured, and
|
|
@@ -97,87 +148,105 @@ available to user-interaction.
|
|
|
97
148
|
To remove the watermark, please purchase a license at tldraw.dev.
|
|
98
149
|
*/
|
|
99
150
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
151
|
+
.${className} {
|
|
152
|
+
position: absolute;
|
|
153
|
+
bottom: max(var(--tl-space-2), env(safe-area-inset-bottom));
|
|
154
|
+
right: max(var(--tl-space-2), env(safe-area-inset-right));
|
|
155
|
+
width: 96px;
|
|
156
|
+
height: 32px;
|
|
157
|
+
display: flex;
|
|
158
|
+
align-items: center;
|
|
159
|
+
justify-content: center;
|
|
160
|
+
z-index: var(--tl-layer-watermark) !important;
|
|
161
|
+
background-color: color-mix(in srgb, var(--tl-color-background) 62%, transparent);
|
|
162
|
+
opacity: 1;
|
|
163
|
+
border-radius: 5px;
|
|
164
|
+
pointer-events: all;
|
|
165
|
+
padding: 2px;
|
|
166
|
+
box-sizing: content-box;
|
|
167
|
+
}
|
|
117
168
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
169
|
+
.${className} > button {
|
|
170
|
+
position: absolute;
|
|
171
|
+
width: 96px;
|
|
172
|
+
height: 32px;
|
|
173
|
+
pointer-events: all;
|
|
174
|
+
cursor: inherit;
|
|
175
|
+
color: var(--tl-color-text);
|
|
176
|
+
opacity: .38;
|
|
177
|
+
border: 0;
|
|
178
|
+
padding: 0;
|
|
179
|
+
background-color: currentColor;
|
|
180
|
+
}
|
|
130
181
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
182
|
+
.${className}[data-debug='true'] {
|
|
183
|
+
bottom: max(46px, env(safe-area-inset-bottom));
|
|
184
|
+
}
|
|
134
185
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
186
|
+
.${className}[data-mobile='true'] {
|
|
187
|
+
border-radius: 4px 0px 0px 4px;
|
|
188
|
+
right: max(-2px, calc(env(safe-area-inset-right) - 2px));
|
|
189
|
+
width: 8px;
|
|
190
|
+
height: 48px;
|
|
191
|
+
}
|
|
141
192
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
193
|
+
.${className}[data-mobile='true'] > button {
|
|
194
|
+
width: 8px;
|
|
195
|
+
height: 32px;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.${className}[data-unlicensed='true'] > button {
|
|
199
|
+
font-size: 100px;
|
|
200
|
+
position: absolute;
|
|
201
|
+
pointer-events: all;
|
|
202
|
+
cursor: pointer;
|
|
203
|
+
color: var(--tl-color-text);
|
|
204
|
+
opacity: 0.8;
|
|
205
|
+
border: 0;
|
|
206
|
+
padding: 0;
|
|
207
|
+
background-color: transparent;
|
|
208
|
+
font-size: 11px;
|
|
209
|
+
font-weight: 600;
|
|
210
|
+
text-align: center;
|
|
211
|
+
}
|
|
146
212
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}
|
|
213
|
+
.${className}[data-mobile='true'][data-unlicensed='true'] > button {
|
|
214
|
+
display: none;
|
|
215
|
+
}
|
|
151
216
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
}
|
|
217
|
+
@media (hover: hover) {
|
|
218
|
+
.${className}[data-licensed='false'] > button {
|
|
219
|
+
pointer-events: none;
|
|
220
|
+
}
|
|
157
221
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
222
|
+
.${className}[data-licensed='false']:hover {
|
|
223
|
+
background-color: var(--tl-color-background);
|
|
224
|
+
transition: background-color 0.2s ease-in-out;
|
|
225
|
+
transition-delay: 0.32s;
|
|
226
|
+
}
|
|
162
227
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
228
|
+
.${className}[data-licensed='false']:hover > button {
|
|
229
|
+
animation: ${className}_delayed_link 0.2s forwards ease-in-out;
|
|
230
|
+
animation-delay: 0.32s;
|
|
166
231
|
}
|
|
167
232
|
|
|
233
|
+
.${className}[data-licensed='false'] > button:focus-visible {
|
|
234
|
+
opacity: 1;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
168
237
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
238
|
+
@keyframes ${className}_delayed_link {
|
|
239
|
+
0% {
|
|
240
|
+
cursor: inherit;
|
|
241
|
+
opacity: .38;
|
|
242
|
+
pointer-events: none;
|
|
243
|
+
}
|
|
244
|
+
100% {
|
|
245
|
+
cursor: pointer;
|
|
246
|
+
opacity: 1;
|
|
247
|
+
pointer-events: all;
|
|
248
|
+
}
|
|
249
|
+
}`;
|
|
181
250
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { nonce: editor.options.nonce, children: CSS });
|
|
182
251
|
});
|
|
183
252
|
//# sourceMappingURL=Watermark.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/license/Watermark.tsx"],
|
|
4
|
-
"sourcesContent": ["import { useValue } from '@tldraw/state-react'\nimport { memo, useRef } from 'react'\nimport { useCanvasEvents } from '../hooks/useCanvasEvents'\nimport { useEditor } from '../hooks/useEditor'\nimport { usePassThroughWheelEvents } from '../hooks/usePassThroughWheelEvents'\nimport { preventDefault
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA4BE;AA5BF,yBAAyB;AACzB,mBAA6B;AAC7B,6BAAgC;AAChC,uBAA0B;AAC1B,uCAA0C;AAC1C,
|
|
6
|
-
"names": ["Watermark", "WatermarkInner", "LicenseStyles"]
|
|
4
|
+
"sourcesContent": ["import { useValue } from '@tldraw/state-react'\nimport { memo, useRef } from 'react'\nimport { useCanvasEvents } from '../hooks/useCanvasEvents'\nimport { useEditor } from '../hooks/useEditor'\nimport { usePassThroughWheelEvents } from '../hooks/usePassThroughWheelEvents'\nimport { preventDefault } from '../utils/dom'\nimport { runtime } from '../utils/runtime'\nimport { watermarkDesktopSvg, watermarkMobileSvg } from '../watermarks'\nimport { LicenseManager } from './LicenseManager'\nimport { useLicenseContext } from './LicenseProvider'\nimport { useLicenseManagerState } from './useLicenseManagerState'\n\nconst WATERMARK_DESKTOP_LOCAL_SRC = `data:image/svg+xml;utf8,${encodeURIComponent(watermarkDesktopSvg)}`\nconst WATERMARK_MOBILE_LOCAL_SRC = `data:image/svg+xml;utf8,${encodeURIComponent(watermarkMobileSvg)}`\n\n/** @internal */\nexport const Watermark = memo(function Watermark() {\n\tconst licenseManager = useLicenseContext()\n\tconst editor = useEditor()\n\tconst isMobile = useValue('is mobile', () => editor.getViewportScreenBounds().width < 700, [\n\t\teditor,\n\t])\n\n\tconst licenseManagerState = useLicenseManagerState(licenseManager)\n\n\tif (!['licensed-with-watermark', 'unlicensed'].includes(licenseManagerState)) return null\n\n\treturn (\n\t\t<>\n\t\t\t<LicenseStyles />\n\t\t\t<WatermarkInner\n\t\t\t\tsrc={isMobile ? WATERMARK_MOBILE_LOCAL_SRC : WATERMARK_DESKTOP_LOCAL_SRC}\n\t\t\t\tisUnlicensed={licenseManagerState === 'unlicensed'}\n\t\t\t/>\n\t\t</>\n\t)\n})\n\nconst UnlicensedWatermark = memo(function UnlicensedWatermark({\n\tisDebugMode,\n\tisMobile,\n}: {\n\tisDebugMode: boolean\n\tisMobile: boolean\n}) {\n\tconst editor = useEditor()\n\tconst events = useCanvasEvents()\n\tconst ref = useRef<HTMLDivElement>(null)\n\tusePassThroughWheelEvents(ref)\n\n\tconst url =\n\t\t'https://tldraw.dev/pricing?utm_source=dotcom&utm_medium=organic&utm_campaign=watermark'\n\n\treturn (\n\t\t<div\n\t\t\tref={ref}\n\t\t\tclassName={LicenseManager.className}\n\t\t\tdata-debug={isDebugMode}\n\t\t\tdata-mobile={isMobile}\n\t\t\tdata-unlicensed={true}\n\t\t\tdata-testid=\"tl-watermark-unlicensed\"\n\t\t\tdraggable={false}\n\t\t\t{...events}\n\t\t>\n\t\t\t<button\n\t\t\t\tdraggable={false}\n\t\t\t\trole=\"button\"\n\t\t\t\tonPointerDown={(e) => {\n\t\t\t\t\teditor.markEventAsHandled(e)\n\t\t\t\t\tpreventDefault(e)\n\t\t\t\t}}\n\t\t\t\ttitle=\"The tldraw SDK requires a license key to work in production. You can get a free 100-day trial license at tldraw.dev/pricing.\"\n\t\t\t\tonClick={() => runtime.openWindow(url, '_blank')}\n\t\t\t>\n\t\t\t\tGet a license for production\n\t\t\t</button>\n\t\t</div>\n\t)\n})\n\nconst WatermarkInner = memo(function WatermarkInner({\n\tsrc,\n\tisUnlicensed,\n}: {\n\tsrc: string\n\tisUnlicensed: boolean\n}) {\n\tconst editor = useEditor()\n\tconst isDebugMode = useValue('debug mode', () => editor.getInstanceState().isDebugMode, [editor])\n\tconst isMobile = useValue('is mobile', () => editor.getViewportScreenBounds().width < 700, [\n\t\teditor,\n\t])\n\tconst events = useCanvasEvents()\n\n\tconst ref = useRef<HTMLDivElement>(null)\n\tusePassThroughWheelEvents(ref)\n\n\tconst maskCss = `url('${src}') center 100% / 100% no-repeat`\n\tconst url = 'https://tldraw.dev/?utm_source=dotcom&utm_medium=organic&utm_campaign=watermark'\n\n\tif (isUnlicensed) {\n\t\treturn <UnlicensedWatermark isDebugMode={isDebugMode} isMobile={isMobile} />\n\t}\n\n\treturn (\n\t\t<div\n\t\t\tref={ref}\n\t\t\tclassName={LicenseManager.className}\n\t\t\tdata-debug={isDebugMode}\n\t\t\tdata-mobile={isMobile}\n\t\t\tdata-testid=\"tl-watermark-licensed\"\n\t\t\tdraggable={false}\n\t\t\t{...events}\n\t\t>\n\t\t\t<button\n\t\t\t\tdraggable={false}\n\t\t\t\trole=\"button\"\n\t\t\t\tonPointerDown={(e) => {\n\t\t\t\t\teditor.markEventAsHandled(e)\n\t\t\t\t\tpreventDefault(e)\n\t\t\t\t}}\n\t\t\t\ttitle=\"Build infinite canvas applications with the tldraw SDK. Learn more at https://tldraw.dev.\"\n\t\t\t\tonClick={() => runtime.openWindow(url, '_blank')}\n\t\t\t\tstyle={{ mask: maskCss, WebkitMask: maskCss }}\n\t\t\t/>\n\t\t</div>\n\t)\n})\n\nconst LicenseStyles = memo(function LicenseStyles() {\n\tconst editor = useEditor()\n\tconst className = LicenseManager.className\n\n\tconst CSS = `\n/* ------------------- SEE LICENSE -------------------\nThe tldraw watermark is part of tldraw's license. It is shown for unlicensed\nor \"licensed-with-watermark\" users. By using this library, you agree to\npreserve the watermark's behavior, keeping it visible, unobscured, and\navailable to user-interaction.\n\nTo remove the watermark, please purchase a license at tldraw.dev.\n*/\n\n.${className} {\n\tposition: absolute;\n\tbottom: max(var(--tl-space-2), env(safe-area-inset-bottom));\n\tright: max(var(--tl-space-2), env(safe-area-inset-right));\n\twidth: 96px;\n\theight: 32px;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tz-index: var(--tl-layer-watermark) !important;\n\tbackground-color: color-mix(in srgb, var(--tl-color-background) 62%, transparent);\n\topacity: 1;\n\tborder-radius: 5px;\n\tpointer-events: all;\n\tpadding: 2px;\n\tbox-sizing: content-box;\n}\n\n.${className} > button {\n\tposition: absolute;\n\twidth: 96px;\n\theight: 32px;\n\tpointer-events: all;\n\tcursor: inherit;\n\tcolor: var(--tl-color-text);\n\topacity: .38;\n\tborder: 0;\n\tpadding: 0;\n\tbackground-color: currentColor;\n}\n\n.${className}[data-debug='true'] {\n\tbottom: max(46px, env(safe-area-inset-bottom));\n}\n\n.${className}[data-mobile='true'] {\n\tborder-radius: 4px 0px 0px 4px;\n\tright: max(-2px, calc(env(safe-area-inset-right) - 2px));\n\twidth: 8px;\n\theight: 48px;\n}\n\n.${className}[data-mobile='true'] > button {\n\twidth: 8px;\n\theight: 32px;\n}\n\n.${className}[data-unlicensed='true'] > button {\n\tfont-size: 100px;\n\tposition: absolute;\n\tpointer-events: all;\n\tcursor: pointer;\n\tcolor: var(--tl-color-text);\n\topacity: 0.8;\n\tborder: 0;\n\tpadding: 0;\n\tbackground-color: transparent;\n\tfont-size: 11px;\n\tfont-weight: 600;\n\ttext-align: center;\n}\n\n.${className}[data-mobile='true'][data-unlicensed='true'] > button {\n\tdisplay: none;\n}\n\n@media (hover: hover) {\n\t.${className}[data-licensed='false'] > button {\n\t\tpointer-events: none;\n\t}\n\n\t.${className}[data-licensed='false']:hover {\n\t\tbackground-color: var(--tl-color-background);\n\t\ttransition: background-color 0.2s ease-in-out;\n\t\ttransition-delay: 0.32s;\n\t}\n\n\t.${className}[data-licensed='false']:hover > button {\n\t\tanimation: ${className}_delayed_link 0.2s forwards ease-in-out;\n\t\tanimation-delay: 0.32s;\n\t}\n\n\t.${className}[data-licensed='false'] > button:focus-visible {\n\t\topacity: 1;\n\t}\n}\n\n@keyframes ${className}_delayed_link {\n\t0% {\n\t\tcursor: inherit;\n\t\topacity: .38;\n\t\tpointer-events: none;\n\t}\n\t100% {\n\t\tcursor: pointer;\n\t\topacity: 1;\n\t\tpointer-events: all;\n\t}\n}`\n\n\treturn <style nonce={editor.options.nonce}>{CSS}</style>\n})\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["Watermark", "UnlicensedWatermark", "WatermarkInner", "LicenseStyles"]
|
|
7
7
|
}
|
|
@@ -45,10 +45,16 @@ class Geometry2d {
|
|
|
45
45
|
isLabel = false;
|
|
46
46
|
isEmptyLabel = false;
|
|
47
47
|
isInternal = false;
|
|
48
|
+
excludeFromShapeBounds = false;
|
|
48
49
|
debugColor;
|
|
49
50
|
ignore;
|
|
50
51
|
constructor(opts) {
|
|
51
|
-
const {
|
|
52
|
+
const {
|
|
53
|
+
isLabel = false,
|
|
54
|
+
isEmptyLabel = false,
|
|
55
|
+
isInternal = false,
|
|
56
|
+
excludeFromShapeBounds = false
|
|
57
|
+
} = opts;
|
|
52
58
|
this.isFilled = opts.isFilled;
|
|
53
59
|
this.isClosed = opts.isClosed;
|
|
54
60
|
this.debugColor = opts.debugColor;
|
|
@@ -56,6 +62,7 @@ class Geometry2d {
|
|
|
56
62
|
this.isLabel = isLabel;
|
|
57
63
|
this.isEmptyLabel = isEmptyLabel;
|
|
58
64
|
this.isInternal = isInternal;
|
|
65
|
+
this.excludeFromShapeBounds = excludeFromShapeBounds;
|
|
59
66
|
}
|
|
60
67
|
isExcludedByFilter(filters) {
|
|
61
68
|
if (!filters) return false;
|
|
@@ -207,8 +214,20 @@ class Geometry2d {
|
|
|
207
214
|
}
|
|
208
215
|
return this._vertices;
|
|
209
216
|
}
|
|
217
|
+
getBoundsVertices() {
|
|
218
|
+
if (this.excludeFromShapeBounds) return [];
|
|
219
|
+
return this.vertices;
|
|
220
|
+
}
|
|
221
|
+
_boundsVertices;
|
|
222
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
223
|
+
get boundsVertices() {
|
|
224
|
+
if (!this._boundsVertices) {
|
|
225
|
+
this._boundsVertices = this.getBoundsVertices();
|
|
226
|
+
}
|
|
227
|
+
return this._boundsVertices;
|
|
228
|
+
}
|
|
210
229
|
getBounds() {
|
|
211
|
-
return import_Box.Box.FromPoints(this.
|
|
230
|
+
return import_Box.Box.FromPoints(this.boundsVertices);
|
|
212
231
|
}
|
|
213
232
|
_bounds;
|
|
214
233
|
// eslint-disable-next-line no-restricted-syntax
|
|
@@ -303,6 +322,9 @@ class TransformedGeometry2d extends Geometry2d {
|
|
|
303
322
|
getVertices(filters) {
|
|
304
323
|
return this.geometry.getVertices(filters).map((v) => import_Mat.Mat.applyToPoint(this.matrix, v));
|
|
305
324
|
}
|
|
325
|
+
getBoundsVertices() {
|
|
326
|
+
return this.geometry.getBoundsVertices().map((v) => import_Mat.Mat.applyToPoint(this.matrix, v));
|
|
327
|
+
}
|
|
306
328
|
nearestPoint(point, filters) {
|
|
307
329
|
return import_Mat.Mat.applyToPoint(
|
|
308
330
|
this.matrix,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lib/primitives/geometry/Geometry2d.ts"],
|
|
4
|
-
"sourcesContent": ["import { assert, invLerp } from '@tldraw/utils'\nimport { Box } from '../Box'\nimport { Mat, MatModel } from '../Mat'\nimport { Vec, VecLike } from '../Vec'\nimport {\n\tintersectCirclePolygon,\n\tintersectCirclePolyline,\n\tintersectLineSegmentPolygon,\n\tintersectLineSegmentPolyline,\n\tintersectPolys,\n\tlinesIntersect,\n\tpolygonIntersectsPolyline,\n\tpolygonsIntersect,\n} from '../intersect'\nimport { approximately, pointInPolygon } from '../utils'\n\n/**\n * Filter geometry within a group.\n *\n * Filters are ignored when called directly on primitive geometries, but can be used to narrow down\n * the results of an operation on `Group2d` geometries.\n *\n * @public\n */\nexport interface Geometry2dFilters {\n\treadonly includeLabels?: boolean\n\treadonly includeInternal?: boolean\n}\n\n/** @public */\nexport const Geometry2dFilters: {\n\tEXCLUDE_NON_STANDARD: Geometry2dFilters\n\tINCLUDE_ALL: Geometry2dFilters\n\tEXCLUDE_LABELS: Geometry2dFilters\n\tEXCLUDE_INTERNAL: Geometry2dFilters\n} = {\n\tEXCLUDE_NON_STANDARD: {\n\t\tincludeLabels: false,\n\t\tincludeInternal: false,\n\t},\n\tINCLUDE_ALL: { includeLabels: true, includeInternal: true },\n\tEXCLUDE_LABELS: { includeLabels: false, includeInternal: true },\n\tEXCLUDE_INTERNAL: { includeLabels: true, includeInternal: false },\n}\n\n/** @public */\nexport interface TransformedGeometry2dOptions {\n\tisLabel?: boolean\n\tisEmptyLabel?: boolean\n\tisInternal?: boolean\n\tdebugColor?: string\n\tignore?: boolean\n}\n\n/** @public */\nexport interface Geometry2dOptions extends TransformedGeometry2dOptions {\n\tisFilled: boolean\n\tisClosed: boolean\n}\n\n/** @public */\nexport abstract class Geometry2d {\n\t// todo: consider making accessors for these too, so that they can be overridden in subclasses by geometries with more complex logic\n\tisFilled = false\n\tisClosed = true\n\tisLabel = false\n\tisEmptyLabel = false\n\tisInternal = false\n\tdebugColor?: string\n\tignore?: boolean\n\n\tconstructor(opts: Geometry2dOptions) {\n\t\tconst { isLabel = false, isEmptyLabel = false, isInternal = false } = opts\n\t\tthis.isFilled = opts.isFilled\n\t\tthis.isClosed = opts.isClosed\n\t\tthis.debugColor = opts.debugColor\n\t\tthis.ignore = opts.ignore\n\t\tthis.isLabel = isLabel\n\t\tthis.isEmptyLabel = isEmptyLabel\n\t\tthis.isInternal = isInternal\n\t}\n\n\tisExcludedByFilter(filters?: Geometry2dFilters) {\n\t\tif (!filters) return false\n\t\tif (this.isLabel && !filters.includeLabels) return true\n\t\tif (this.isInternal && !filters.includeInternal) return true\n\t\treturn false\n\t}\n\n\tabstract getVertices(filters: Geometry2dFilters): Vec[]\n\n\tabstract nearestPoint(point: VecLike, _filters?: Geometry2dFilters): Vec\n\n\thitTestPoint(point: VecLike, margin = 0, hitInside = false, _filters?: Geometry2dFilters) {\n\t\t// First check whether the point is inside\n\t\tif (this.isClosed && (this.isFilled || hitInside) && pointInPolygon(point, this.vertices)) {\n\t\t\treturn true\n\t\t}\n\t\t// Then check whether the distance is within the margin\n\t\treturn Vec.Dist2(point, this.nearestPoint(point)) <= margin * margin\n\t}\n\n\tdistanceToPoint(point: VecLike, hitInside = false, filters?: Geometry2dFilters) {\n\t\treturn (\n\t\t\tVec.Dist(point, this.nearestPoint(point, filters)) *\n\t\t\t(this.isClosed && (this.isFilled || hitInside) && pointInPolygon(point, this.vertices)\n\t\t\t\t? -1\n\t\t\t\t: 1)\n\t\t)\n\t}\n\n\tdistanceToLineSegment(A: VecLike, B: VecLike, filters?: Geometry2dFilters) {\n\t\tif (Vec.Equals(A, B)) return this.distanceToPoint(A, false, filters)\n\t\tconst { vertices } = this\n\t\tlet nearest: Vec | undefined\n\t\tlet dist = Infinity\n\t\tlet d: number, p: Vec, q: Vec\n\t\tconst nextLimit = this.isClosed ? vertices.length : vertices.length - 1\n\t\tfor (let i = 0; i < vertices.length; i++) {\n\t\t\tp = vertices[i]\n\t\t\tif (i < nextLimit) {\n\t\t\t\tconst next = vertices[(i + 1) % vertices.length]\n\t\t\t\tif (linesIntersect(A, B, p, next)) return 0\n\t\t\t}\n\t\t\tq = Vec.NearestPointOnLineSegment(A, B, p, true)\n\t\t\td = Vec.Dist2(p, q)\n\t\t\tif (d < dist) {\n\t\t\t\tdist = d\n\t\t\t\tnearest = q\n\t\t\t}\n\t\t}\n\t\tif (!nearest) throw Error('nearest point not found')\n\t\treturn this.isClosed && this.isFilled && pointInPolygon(nearest, this.vertices) ? -dist : dist\n\t}\n\n\thitTestLineSegment(A: VecLike, B: VecLike, distance = 0, filters?: Geometry2dFilters): boolean {\n\t\treturn this.distanceToLineSegment(A, B, filters) <= distance\n\t}\n\n\tintersectLineSegment(A: VecLike, B: VecLike, _filters?: Geometry2dFilters): VecLike[] {\n\t\tconst intersections = this.isClosed\n\t\t\t? intersectLineSegmentPolygon(A, B, this.vertices)\n\t\t\t: intersectLineSegmentPolyline(A, B, this.vertices)\n\n\t\treturn intersections ?? []\n\t}\n\n\tintersectCircle(center: VecLike, radius: number, _filters?: Geometry2dFilters): VecLike[] {\n\t\tconst intersections = this.isClosed\n\t\t\t? intersectCirclePolygon(center, radius, this.vertices)\n\t\t\t: intersectCirclePolyline(center, radius, this.vertices)\n\n\t\treturn intersections ?? []\n\t}\n\n\tintersectPolygon(polygon: VecLike[], _filters?: Geometry2dFilters): VecLike[] {\n\t\treturn intersectPolys(polygon, this.vertices, true, this.isClosed)\n\t}\n\n\tintersectPolyline(polyline: VecLike[], _filters?: Geometry2dFilters): VecLike[] {\n\t\treturn intersectPolys(polyline, this.vertices, false, this.isClosed)\n\t}\n\n\t/**\n\t * Find a point along the edge of the geometry that is a fraction `t` along the entire way round.\n\t */\n\tinterpolateAlongEdge(t: number, _filters?: Geometry2dFilters): Vec {\n\t\tconst { vertices } = this\n\n\t\tif (t <= 0) return vertices[0]\n\n\t\tconst distanceToTravel = t * this.length\n\t\tlet distanceTraveled = 0\n\n\t\tfor (let i = 0; i < (this.isClosed ? vertices.length : vertices.length - 1); i++) {\n\t\t\tconst curr = vertices[i]\n\t\t\tconst next = vertices[(i + 1) % vertices.length]\n\t\t\tconst dist = Vec.Dist(curr, next)\n\t\t\tconst newDistanceTraveled = distanceTraveled + dist\n\t\t\tif (newDistanceTraveled >= distanceToTravel) {\n\t\t\t\tconst p = Vec.Lrp(\n\t\t\t\t\tcurr,\n\t\t\t\t\tnext,\n\t\t\t\t\tinvLerp(distanceTraveled, newDistanceTraveled, distanceToTravel)\n\t\t\t\t)\n\t\t\t\treturn p\n\t\t\t}\n\t\t\tdistanceTraveled = newDistanceTraveled\n\t\t}\n\n\t\treturn this.isClosed ? vertices[0] : vertices[vertices.length - 1]\n\t}\n\n\t/**\n\t * Take `point`, find the closest point to it on the edge of the geometry, and return how far\n\t * along the edge it is as a fraction of the total length.\n\t */\n\tuninterpolateAlongEdge(point: VecLike, _filters?: Geometry2dFilters): number {\n\t\tconst { vertices, length } = this\n\t\tlet closestSegment = null\n\t\tlet closestDistance = Infinity\n\t\tlet distanceTraveled = 0\n\n\t\tfor (let i = 0; i < (this.isClosed ? vertices.length : vertices.length - 1); i++) {\n\t\t\tconst curr = vertices[i]\n\t\t\tconst next = vertices[(i + 1) % vertices.length]\n\n\t\t\tconst nearestPoint = Vec.NearestPointOnLineSegment(curr, next, point, true)\n\t\t\tconst distance = Vec.Dist(nearestPoint, point)\n\n\t\t\tif (distance < closestDistance) {\n\t\t\t\tclosestDistance = distance\n\t\t\t\tclosestSegment = {\n\t\t\t\t\tstart: curr,\n\t\t\t\t\tend: next,\n\t\t\t\t\tnearestPoint,\n\t\t\t\t\tdistanceToStart: distanceTraveled,\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tdistanceTraveled += Vec.Dist(curr, next)\n\t\t}\n\n\t\tassert(closestSegment)\n\n\t\tconst distanceAlongRoute =\n\t\t\tclosestSegment.distanceToStart + Vec.Dist(closestSegment.start, closestSegment.nearestPoint)\n\n\t\treturn distanceAlongRoute / length\n\t}\n\n\tisPointInBounds(point: VecLike, margin = 0) {\n\t\tconst { bounds } = this\n\t\treturn !(\n\t\t\tpoint.x < bounds.minX - margin ||\n\t\t\tpoint.y < bounds.minY - margin ||\n\t\t\tpoint.x > bounds.maxX + margin ||\n\t\t\tpoint.y > bounds.maxY + margin\n\t\t)\n\t}\n\n\toverlapsPolygon(_polygon: VecLike[]): boolean {\n\t\tconst polygon = _polygon.map((v) => Vec.From(v))\n\n\t\t// Otherwise, check if the geometry itself overlaps the polygon\n\t\tconst { vertices, center, isFilled, isEmptyLabel, isClosed } = this\n\n\t\t// We'll do things in order of cheapest to most expensive checks\n\n\t\t// Skip empty labels\n\t\tif (isEmptyLabel) return false\n\n\t\t// If any of the geometry's vertices are inside the polygon, it's inside\n\t\tif (vertices.some((v) => pointInPolygon(v, polygon))) {\n\t\t\treturn true\n\t\t}\n\n\t\t// If the geometry is filled and closed and its center is inside the polygon, it's inside\n\t\tif (isClosed) {\n\t\t\tif (isFilled) {\n\t\t\t\t// If closed and filled, check if the center is inside the polygon\n\t\t\t\tif (pointInPolygon(center, polygon)) {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\n\t\t\t\t// ..then, slightly more expensive check, see the geometry covers the entire polygon but not its center\n\t\t\t\tif (polygon.every((v) => pointInPolygon(v, vertices))) {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If any the geometry's vertices intersect the edge of the polygon, it's inside.\n\t\t\t// for example when a rotated rectangle is moved over the corner of a parent rectangle\n\t\t\t// If the geometry is closed, intersect as a polygon\n\t\t\tif (polygonsIntersect(polygon, vertices)) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t} else {\n\t\t\t// If the geometry is not closed, intersect as a polyline\n\t\t\tif (polygonIntersectsPolyline(polygon, vertices)) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\n\t\t// If none of the above checks passed, the geometry is outside the polygon\n\t\treturn false\n\t}\n\n\ttransform(transform: MatModel, opts?: TransformedGeometry2dOptions): Geometry2d {\n\t\treturn new TransformedGeometry2d(this, transform, opts)\n\t}\n\n\tprivate _vertices: Vec[] | undefined\n\n\t// eslint-disable-next-line no-restricted-syntax\n\tget vertices(): Vec[] {\n\t\tif (!this._vertices) {\n\t\t\tthis._vertices = this.getVertices(Geometry2dFilters.EXCLUDE_LABELS)\n\t\t}\n\n\t\treturn this._vertices\n\t}\n\n\tgetBounds() {\n\t\treturn Box.FromPoints(this.vertices)\n\t}\n\n\tprivate _bounds: Box | undefined\n\n\t// eslint-disable-next-line no-restricted-syntax\n\tget bounds(): Box {\n\t\tif (!this._bounds) {\n\t\t\tthis._bounds = this.getBounds()\n\t\t}\n\t\treturn this._bounds\n\t}\n\n\t// eslint-disable-next-line no-restricted-syntax\n\tget center() {\n\t\treturn this.bounds.center\n\t}\n\n\tprivate _area: number | undefined\n\n\t// eslint-disable-next-line no-restricted-syntax\n\tget area() {\n\t\tif (!this._area) {\n\t\t\tthis._area = this.getArea()\n\t\t}\n\t\treturn this._area\n\t}\n\n\tgetArea() {\n\t\tif (!this.isClosed) {\n\t\t\treturn 0\n\t\t}\n\t\tconst { vertices } = this\n\t\tlet area = 0\n\t\tfor (let i = 0, n = vertices.length; i < n; i++) {\n\t\t\tconst curr = vertices[i]\n\t\t\tconst next = vertices[(i + 1) % n]\n\t\t\tarea += curr.x * next.y - next.x * curr.y\n\t\t}\n\t\treturn area / 2\n\t}\n\n\ttoSimpleSvgPath() {\n\t\tlet path = ''\n\n\t\tconst { vertices } = this\n\t\tconst n = vertices.length\n\n\t\tif (n === 0) return path\n\n\t\tpath += `M${vertices[0].x},${vertices[0].y}`\n\n\t\tfor (let i = 1; i < n; i++) {\n\t\t\tpath += `L${vertices[i].x},${vertices[i].y}`\n\t\t}\n\n\t\tif (this.isClosed) {\n\t\t\tpath += 'Z'\n\t\t}\n\n\t\treturn path\n\t}\n\n\tprivate _length?: number\n\n\t// eslint-disable-next-line no-restricted-syntax\n\tget length() {\n\t\tif (this._length) return this._length\n\t\tthis._length = this.getLength(Geometry2dFilters.EXCLUDE_LABELS)\n\t\treturn this._length\n\t}\n\n\tgetLength(_filters?: Geometry2dFilters) {\n\t\tconst vertices = this.getVertices(_filters ?? Geometry2dFilters.EXCLUDE_LABELS)\n\t\tif (vertices.length === 0) return 0\n\t\tlet prev = vertices[0]\n\t\tlet length = 0\n\t\tfor (let i = 1; i < vertices.length; i++) {\n\t\t\tconst next = vertices[i]\n\t\t\tlength += Vec.Dist(prev, next)\n\t\t\tprev = next\n\t\t}\n\t\tif (this.isClosed) {\n\t\t\tlength += Vec.Dist(vertices[vertices.length - 1], vertices[0])\n\t\t}\n\t\treturn length\n\t}\n\n\tabstract getSvgPathData(first: boolean): string\n}\n\n// =================================================================================================\n// Because Geometry2d.transform depends on TransformedGeometry2d, we need to define it here instead\n// of in its own files. This prevents a circular import error.\n// =================================================================================================\n\n/** @public */\nexport class TransformedGeometry2d extends Geometry2d {\n\tprivate readonly inverse: MatModel\n\tprivate readonly decomposed\n\n\tconstructor(\n\t\tprivate readonly geometry: Geometry2d,\n\t\tprivate readonly matrix: MatModel,\n\t\topts?: TransformedGeometry2dOptions\n\t) {\n\t\tsuper(geometry)\n\t\tthis.inverse = Mat.Inverse(matrix)\n\t\tthis.decomposed = Mat.Decompose(matrix)\n\n\t\tif (opts) {\n\t\t\tif (opts.isLabel != null) this.isLabel = opts.isLabel\n\t\t\tif (opts.isInternal != null) this.isInternal = opts.isInternal\n\t\t\tif (opts.debugColor != null) this.debugColor = opts.debugColor\n\t\t\tif (opts.ignore != null) this.ignore = opts.ignore\n\t\t}\n\n\t\tassert(\n\t\t\tapproximately(this.decomposed.scaleX, this.decomposed.scaleY),\n\t\t\t'non-uniform scaling is not yet supported'\n\t\t)\n\t}\n\n\tgetVertices(filters: Geometry2dFilters): Vec[] {\n\t\treturn this.geometry.getVertices(filters).map((v) => Mat.applyToPoint(this.matrix, v))\n\t}\n\n\tnearestPoint(point: VecLike, filters?: Geometry2dFilters): Vec {\n\t\treturn Mat.applyToPoint(\n\t\t\tthis.matrix,\n\t\t\tthis.geometry.nearestPoint(Mat.applyToPoint(this.inverse, point), filters)\n\t\t)\n\t}\n\n\toverride hitTestPoint(\n\t\tpoint: VecLike,\n\t\tmargin = 0,\n\t\thitInside?: boolean,\n\t\tfilters?: Geometry2dFilters\n\t): boolean {\n\t\treturn this.geometry.hitTestPoint(\n\t\t\tMat.applyToPoint(this.inverse, point),\n\t\t\tmargin / this.decomposed.scaleX,\n\t\t\thitInside,\n\t\t\tfilters\n\t\t)\n\t}\n\n\toverride distanceToPoint(point: VecLike, hitInside = false, filters?: Geometry2dFilters) {\n\t\treturn (\n\t\t\tthis.geometry.distanceToPoint(Mat.applyToPoint(this.inverse, point), hitInside, filters) *\n\t\t\tthis.decomposed.scaleX\n\t\t)\n\t}\n\n\toverride distanceToLineSegment(A: VecLike, B: VecLike, filters?: Geometry2dFilters) {\n\t\treturn (\n\t\t\tthis.geometry.distanceToLineSegment(\n\t\t\t\tMat.applyToPoint(this.inverse, A),\n\t\t\t\tMat.applyToPoint(this.inverse, B),\n\t\t\t\tfilters\n\t\t\t) * this.decomposed.scaleX\n\t\t)\n\t}\n\n\toverride hitTestLineSegment(\n\t\tA: VecLike,\n\t\tB: VecLike,\n\t\tdistance = 0,\n\t\tfilters?: Geometry2dFilters\n\t): boolean {\n\t\treturn this.geometry.hitTestLineSegment(\n\t\t\tMat.applyToPoint(this.inverse, A),\n\t\t\tMat.applyToPoint(this.inverse, B),\n\t\t\tdistance / this.decomposed.scaleX,\n\t\t\tfilters\n\t\t)\n\t}\n\n\toverride intersectLineSegment(A: VecLike, B: VecLike, filters?: Geometry2dFilters) {\n\t\treturn Mat.applyToPoints(\n\t\t\tthis.matrix,\n\t\t\tthis.geometry.intersectLineSegment(\n\t\t\t\tMat.applyToPoint(this.inverse, A),\n\t\t\t\tMat.applyToPoint(this.inverse, B),\n\t\t\t\tfilters\n\t\t\t)\n\t\t)\n\t}\n\n\toverride intersectCircle(center: VecLike, radius: number, filters?: Geometry2dFilters) {\n\t\treturn Mat.applyToPoints(\n\t\t\tthis.matrix,\n\t\t\tthis.geometry.intersectCircle(\n\t\t\t\tMat.applyToPoint(this.inverse, center),\n\t\t\t\tradius / this.decomposed.scaleX,\n\t\t\t\tfilters\n\t\t\t)\n\t\t)\n\t}\n\n\toverride intersectPolygon(polygon: VecLike[], filters?: Geometry2dFilters): VecLike[] {\n\t\treturn Mat.applyToPoints(\n\t\t\tthis.matrix,\n\t\t\tthis.geometry.intersectPolygon(Mat.applyToPoints(this.inverse, polygon), filters)\n\t\t)\n\t}\n\n\toverride intersectPolyline(polyline: VecLike[], filters?: Geometry2dFilters): VecLike[] {\n\t\treturn Mat.applyToPoints(\n\t\t\tthis.matrix,\n\t\t\tthis.geometry.intersectPolyline(Mat.applyToPoints(this.inverse, polyline), filters)\n\t\t)\n\t}\n\n\toverride transform(transform: MatModel, opts?: TransformedGeometry2dOptions): Geometry2d {\n\t\treturn new TransformedGeometry2d(this.geometry, Mat.Multiply(transform, this.matrix), {\n\t\t\tisLabel: opts?.isLabel ?? this.isLabel,\n\t\t\tisInternal: opts?.isInternal ?? this.isInternal,\n\t\t\tdebugColor: opts?.debugColor ?? this.debugColor,\n\t\t\tignore: opts?.ignore ?? this.ignore,\n\t\t})\n\t}\n\n\tgetSvgPathData(): string {\n\t\tthrow new Error('Cannot get SVG path data for transformed geometry.')\n\t}\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAgC;AAChC,iBAAoB;AACpB,iBAA8B;AAC9B,iBAA6B;AAC7B,uBASO;AACP,IAAAA,gBAA8C;AAgBvC,MAAM,oBAKT;AAAA,EACH,sBAAsB;AAAA,IACrB,eAAe;AAAA,IACf,iBAAiB;AAAA,EAClB;AAAA,EACA,aAAa,EAAE,eAAe,MAAM,iBAAiB,KAAK;AAAA,EAC1D,gBAAgB,EAAE,eAAe,OAAO,iBAAiB,KAAK;AAAA,EAC9D,kBAAkB,EAAE,eAAe,MAAM,iBAAiB,MAAM;AACjE;
|
|
4
|
+
"sourcesContent": ["import { assert, invLerp } from '@tldraw/utils'\nimport { Box } from '../Box'\nimport { Mat, MatModel } from '../Mat'\nimport { Vec, VecLike } from '../Vec'\nimport {\n\tintersectCirclePolygon,\n\tintersectCirclePolyline,\n\tintersectLineSegmentPolygon,\n\tintersectLineSegmentPolyline,\n\tintersectPolys,\n\tlinesIntersect,\n\tpolygonIntersectsPolyline,\n\tpolygonsIntersect,\n} from '../intersect'\nimport { approximately, pointInPolygon } from '../utils'\n\n/**\n * Filter geometry within a group.\n *\n * Filters are ignored when called directly on primitive geometries, but can be used to narrow down\n * the results of an operation on `Group2d` geometries.\n *\n * @public\n */\nexport interface Geometry2dFilters {\n\treadonly includeLabels?: boolean\n\treadonly includeInternal?: boolean\n}\n\n/** @public */\nexport const Geometry2dFilters: {\n\tEXCLUDE_NON_STANDARD: Geometry2dFilters\n\tINCLUDE_ALL: Geometry2dFilters\n\tEXCLUDE_LABELS: Geometry2dFilters\n\tEXCLUDE_INTERNAL: Geometry2dFilters\n} = {\n\tEXCLUDE_NON_STANDARD: {\n\t\tincludeLabels: false,\n\t\tincludeInternal: false,\n\t},\n\tINCLUDE_ALL: { includeLabels: true, includeInternal: true },\n\tEXCLUDE_LABELS: { includeLabels: false, includeInternal: true },\n\tEXCLUDE_INTERNAL: { includeLabels: true, includeInternal: false },\n}\n\n/** @public */\nexport interface TransformedGeometry2dOptions {\n\tisLabel?: boolean\n\tisEmptyLabel?: boolean\n\tisInternal?: boolean\n\tdebugColor?: string\n\tignore?: boolean\n\texcludeFromShapeBounds?: boolean\n}\n\n/** @public */\nexport interface Geometry2dOptions extends TransformedGeometry2dOptions {\n\tisFilled: boolean\n\tisClosed: boolean\n}\n\n/** @public */\nexport abstract class Geometry2d {\n\t// todo: consider making accessors for these too, so that they can be overridden in subclasses by geometries with more complex logic\n\tisFilled = false\n\tisClosed = true\n\tisLabel = false\n\tisEmptyLabel = false\n\tisInternal = false\n\texcludeFromShapeBounds = false\n\tdebugColor?: string\n\tignore?: boolean\n\n\tconstructor(opts: Geometry2dOptions) {\n\t\tconst {\n\t\t\tisLabel = false,\n\t\t\tisEmptyLabel = false,\n\t\t\tisInternal = false,\n\t\t\texcludeFromShapeBounds = false,\n\t\t} = opts\n\t\tthis.isFilled = opts.isFilled\n\t\tthis.isClosed = opts.isClosed\n\t\tthis.debugColor = opts.debugColor\n\t\tthis.ignore = opts.ignore\n\t\tthis.isLabel = isLabel\n\t\tthis.isEmptyLabel = isEmptyLabel\n\t\tthis.isInternal = isInternal\n\t\tthis.excludeFromShapeBounds = excludeFromShapeBounds\n\t}\n\n\tisExcludedByFilter(filters?: Geometry2dFilters) {\n\t\tif (!filters) return false\n\t\tif (this.isLabel && !filters.includeLabels) return true\n\t\tif (this.isInternal && !filters.includeInternal) return true\n\t\treturn false\n\t}\n\n\tabstract getVertices(filters: Geometry2dFilters): Vec[]\n\n\tabstract nearestPoint(point: VecLike, _filters?: Geometry2dFilters): Vec\n\n\thitTestPoint(point: VecLike, margin = 0, hitInside = false, _filters?: Geometry2dFilters) {\n\t\t// First check whether the point is inside\n\t\tif (this.isClosed && (this.isFilled || hitInside) && pointInPolygon(point, this.vertices)) {\n\t\t\treturn true\n\t\t}\n\t\t// Then check whether the distance is within the margin\n\t\treturn Vec.Dist2(point, this.nearestPoint(point)) <= margin * margin\n\t}\n\n\tdistanceToPoint(point: VecLike, hitInside = false, filters?: Geometry2dFilters) {\n\t\treturn (\n\t\t\tVec.Dist(point, this.nearestPoint(point, filters)) *\n\t\t\t(this.isClosed && (this.isFilled || hitInside) && pointInPolygon(point, this.vertices)\n\t\t\t\t? -1\n\t\t\t\t: 1)\n\t\t)\n\t}\n\n\tdistanceToLineSegment(A: VecLike, B: VecLike, filters?: Geometry2dFilters) {\n\t\tif (Vec.Equals(A, B)) return this.distanceToPoint(A, false, filters)\n\t\tconst { vertices } = this\n\t\tlet nearest: Vec | undefined\n\t\tlet dist = Infinity\n\t\tlet d: number, p: Vec, q: Vec\n\t\tconst nextLimit = this.isClosed ? vertices.length : vertices.length - 1\n\t\tfor (let i = 0; i < vertices.length; i++) {\n\t\t\tp = vertices[i]\n\t\t\tif (i < nextLimit) {\n\t\t\t\tconst next = vertices[(i + 1) % vertices.length]\n\t\t\t\tif (linesIntersect(A, B, p, next)) return 0\n\t\t\t}\n\t\t\tq = Vec.NearestPointOnLineSegment(A, B, p, true)\n\t\t\td = Vec.Dist2(p, q)\n\t\t\tif (d < dist) {\n\t\t\t\tdist = d\n\t\t\t\tnearest = q\n\t\t\t}\n\t\t}\n\t\tif (!nearest) throw Error('nearest point not found')\n\t\treturn this.isClosed && this.isFilled && pointInPolygon(nearest, this.vertices) ? -dist : dist\n\t}\n\n\thitTestLineSegment(A: VecLike, B: VecLike, distance = 0, filters?: Geometry2dFilters): boolean {\n\t\treturn this.distanceToLineSegment(A, B, filters) <= distance\n\t}\n\n\tintersectLineSegment(A: VecLike, B: VecLike, _filters?: Geometry2dFilters): VecLike[] {\n\t\tconst intersections = this.isClosed\n\t\t\t? intersectLineSegmentPolygon(A, B, this.vertices)\n\t\t\t: intersectLineSegmentPolyline(A, B, this.vertices)\n\n\t\treturn intersections ?? []\n\t}\n\n\tintersectCircle(center: VecLike, radius: number, _filters?: Geometry2dFilters): VecLike[] {\n\t\tconst intersections = this.isClosed\n\t\t\t? intersectCirclePolygon(center, radius, this.vertices)\n\t\t\t: intersectCirclePolyline(center, radius, this.vertices)\n\n\t\treturn intersections ?? []\n\t}\n\n\tintersectPolygon(polygon: VecLike[], _filters?: Geometry2dFilters): VecLike[] {\n\t\treturn intersectPolys(polygon, this.vertices, true, this.isClosed)\n\t}\n\n\tintersectPolyline(polyline: VecLike[], _filters?: Geometry2dFilters): VecLike[] {\n\t\treturn intersectPolys(polyline, this.vertices, false, this.isClosed)\n\t}\n\n\t/**\n\t * Find a point along the edge of the geometry that is a fraction `t` along the entire way round.\n\t */\n\tinterpolateAlongEdge(t: number, _filters?: Geometry2dFilters): Vec {\n\t\tconst { vertices } = this\n\n\t\tif (t <= 0) return vertices[0]\n\n\t\tconst distanceToTravel = t * this.length\n\t\tlet distanceTraveled = 0\n\n\t\tfor (let i = 0; i < (this.isClosed ? vertices.length : vertices.length - 1); i++) {\n\t\t\tconst curr = vertices[i]\n\t\t\tconst next = vertices[(i + 1) % vertices.length]\n\t\t\tconst dist = Vec.Dist(curr, next)\n\t\t\tconst newDistanceTraveled = distanceTraveled + dist\n\t\t\tif (newDistanceTraveled >= distanceToTravel) {\n\t\t\t\tconst p = Vec.Lrp(\n\t\t\t\t\tcurr,\n\t\t\t\t\tnext,\n\t\t\t\t\tinvLerp(distanceTraveled, newDistanceTraveled, distanceToTravel)\n\t\t\t\t)\n\t\t\t\treturn p\n\t\t\t}\n\t\t\tdistanceTraveled = newDistanceTraveled\n\t\t}\n\n\t\treturn this.isClosed ? vertices[0] : vertices[vertices.length - 1]\n\t}\n\n\t/**\n\t * Take `point`, find the closest point to it on the edge of the geometry, and return how far\n\t * along the edge it is as a fraction of the total length.\n\t */\n\tuninterpolateAlongEdge(point: VecLike, _filters?: Geometry2dFilters): number {\n\t\tconst { vertices, length } = this\n\t\tlet closestSegment = null\n\t\tlet closestDistance = Infinity\n\t\tlet distanceTraveled = 0\n\n\t\tfor (let i = 0; i < (this.isClosed ? vertices.length : vertices.length - 1); i++) {\n\t\t\tconst curr = vertices[i]\n\t\t\tconst next = vertices[(i + 1) % vertices.length]\n\n\t\t\tconst nearestPoint = Vec.NearestPointOnLineSegment(curr, next, point, true)\n\t\t\tconst distance = Vec.Dist(nearestPoint, point)\n\n\t\t\tif (distance < closestDistance) {\n\t\t\t\tclosestDistance = distance\n\t\t\t\tclosestSegment = {\n\t\t\t\t\tstart: curr,\n\t\t\t\t\tend: next,\n\t\t\t\t\tnearestPoint,\n\t\t\t\t\tdistanceToStart: distanceTraveled,\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tdistanceTraveled += Vec.Dist(curr, next)\n\t\t}\n\n\t\tassert(closestSegment)\n\n\t\tconst distanceAlongRoute =\n\t\t\tclosestSegment.distanceToStart + Vec.Dist(closestSegment.start, closestSegment.nearestPoint)\n\n\t\treturn distanceAlongRoute / length\n\t}\n\n\tisPointInBounds(point: VecLike, margin = 0) {\n\t\tconst { bounds } = this\n\t\treturn !(\n\t\t\tpoint.x < bounds.minX - margin ||\n\t\t\tpoint.y < bounds.minY - margin ||\n\t\t\tpoint.x > bounds.maxX + margin ||\n\t\t\tpoint.y > bounds.maxY + margin\n\t\t)\n\t}\n\n\toverlapsPolygon(_polygon: VecLike[]): boolean {\n\t\tconst polygon = _polygon.map((v) => Vec.From(v))\n\n\t\t// Otherwise, check if the geometry itself overlaps the polygon\n\t\tconst { vertices, center, isFilled, isEmptyLabel, isClosed } = this\n\n\t\t// We'll do things in order of cheapest to most expensive checks\n\n\t\t// Skip empty labels\n\t\tif (isEmptyLabel) return false\n\n\t\t// If any of the geometry's vertices are inside the polygon, it's inside\n\t\tif (vertices.some((v) => pointInPolygon(v, polygon))) {\n\t\t\treturn true\n\t\t}\n\n\t\t// If the geometry is filled and closed and its center is inside the polygon, it's inside\n\t\tif (isClosed) {\n\t\t\tif (isFilled) {\n\t\t\t\t// If closed and filled, check if the center is inside the polygon\n\t\t\t\tif (pointInPolygon(center, polygon)) {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\n\t\t\t\t// ..then, slightly more expensive check, see the geometry covers the entire polygon but not its center\n\t\t\t\tif (polygon.every((v) => pointInPolygon(v, vertices))) {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If any the geometry's vertices intersect the edge of the polygon, it's inside.\n\t\t\t// for example when a rotated rectangle is moved over the corner of a parent rectangle\n\t\t\t// If the geometry is closed, intersect as a polygon\n\t\t\tif (polygonsIntersect(polygon, vertices)) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t} else {\n\t\t\t// If the geometry is not closed, intersect as a polyline\n\t\t\tif (polygonIntersectsPolyline(polygon, vertices)) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\n\t\t// If none of the above checks passed, the geometry is outside the polygon\n\t\treturn false\n\t}\n\n\ttransform(transform: MatModel, opts?: TransformedGeometry2dOptions): Geometry2d {\n\t\treturn new TransformedGeometry2d(this, transform, opts)\n\t}\n\n\tprivate _vertices: Vec[] | undefined\n\n\t// eslint-disable-next-line no-restricted-syntax\n\tget vertices(): Vec[] {\n\t\tif (!this._vertices) {\n\t\t\tthis._vertices = this.getVertices(Geometry2dFilters.EXCLUDE_LABELS)\n\t\t}\n\n\t\treturn this._vertices\n\t}\n\n\tgetBoundsVertices(): Vec[] {\n\t\tif (this.excludeFromShapeBounds) return []\n\t\treturn this.vertices\n\t}\n\n\tprivate _boundsVertices: Vec[] | undefined\n\n\t// eslint-disable-next-line no-restricted-syntax\n\tget boundsVertices(): Vec[] {\n\t\tif (!this._boundsVertices) {\n\t\t\tthis._boundsVertices = this.getBoundsVertices()\n\t\t}\n\t\treturn this._boundsVertices\n\t}\n\n\tgetBounds() {\n\t\treturn Box.FromPoints(this.boundsVertices)\n\t}\n\n\tprivate _bounds: Box | undefined\n\n\t// eslint-disable-next-line no-restricted-syntax\n\tget bounds(): Box {\n\t\tif (!this._bounds) {\n\t\t\tthis._bounds = this.getBounds()\n\t\t}\n\t\treturn this._bounds\n\t}\n\n\t// eslint-disable-next-line no-restricted-syntax\n\tget center() {\n\t\treturn this.bounds.center\n\t}\n\n\tprivate _area: number | undefined\n\n\t// eslint-disable-next-line no-restricted-syntax\n\tget area() {\n\t\tif (!this._area) {\n\t\t\tthis._area = this.getArea()\n\t\t}\n\t\treturn this._area\n\t}\n\n\tgetArea() {\n\t\tif (!this.isClosed) {\n\t\t\treturn 0\n\t\t}\n\t\tconst { vertices } = this\n\t\tlet area = 0\n\t\tfor (let i = 0, n = vertices.length; i < n; i++) {\n\t\t\tconst curr = vertices[i]\n\t\t\tconst next = vertices[(i + 1) % n]\n\t\t\tarea += curr.x * next.y - next.x * curr.y\n\t\t}\n\t\treturn area / 2\n\t}\n\n\ttoSimpleSvgPath() {\n\t\tlet path = ''\n\n\t\tconst { vertices } = this\n\t\tconst n = vertices.length\n\n\t\tif (n === 0) return path\n\n\t\tpath += `M${vertices[0].x},${vertices[0].y}`\n\n\t\tfor (let i = 1; i < n; i++) {\n\t\t\tpath += `L${vertices[i].x},${vertices[i].y}`\n\t\t}\n\n\t\tif (this.isClosed) {\n\t\t\tpath += 'Z'\n\t\t}\n\n\t\treturn path\n\t}\n\n\tprivate _length?: number\n\n\t// eslint-disable-next-line no-restricted-syntax\n\tget length() {\n\t\tif (this._length) return this._length\n\t\tthis._length = this.getLength(Geometry2dFilters.EXCLUDE_LABELS)\n\t\treturn this._length\n\t}\n\n\tgetLength(_filters?: Geometry2dFilters) {\n\t\tconst vertices = this.getVertices(_filters ?? Geometry2dFilters.EXCLUDE_LABELS)\n\t\tif (vertices.length === 0) return 0\n\t\tlet prev = vertices[0]\n\t\tlet length = 0\n\t\tfor (let i = 1; i < vertices.length; i++) {\n\t\t\tconst next = vertices[i]\n\t\t\tlength += Vec.Dist(prev, next)\n\t\t\tprev = next\n\t\t}\n\t\tif (this.isClosed) {\n\t\t\tlength += Vec.Dist(vertices[vertices.length - 1], vertices[0])\n\t\t}\n\t\treturn length\n\t}\n\n\tabstract getSvgPathData(first: boolean): string\n}\n\n// =================================================================================================\n// Because Geometry2d.transform depends on TransformedGeometry2d, we need to define it here instead\n// of in its own files. This prevents a circular import error.\n// =================================================================================================\n\n/** @public */\nexport class TransformedGeometry2d extends Geometry2d {\n\tprivate readonly inverse: MatModel\n\tprivate readonly decomposed\n\n\tconstructor(\n\t\tprivate readonly geometry: Geometry2d,\n\t\tprivate readonly matrix: MatModel,\n\t\topts?: TransformedGeometry2dOptions\n\t) {\n\t\tsuper(geometry)\n\t\tthis.inverse = Mat.Inverse(matrix)\n\t\tthis.decomposed = Mat.Decompose(matrix)\n\n\t\tif (opts) {\n\t\t\tif (opts.isLabel != null) this.isLabel = opts.isLabel\n\t\t\tif (opts.isInternal != null) this.isInternal = opts.isInternal\n\t\t\tif (opts.debugColor != null) this.debugColor = opts.debugColor\n\t\t\tif (opts.ignore != null) this.ignore = opts.ignore\n\t\t}\n\n\t\tassert(\n\t\t\tapproximately(this.decomposed.scaleX, this.decomposed.scaleY),\n\t\t\t'non-uniform scaling is not yet supported'\n\t\t)\n\t}\n\n\tgetVertices(filters: Geometry2dFilters): Vec[] {\n\t\treturn this.geometry.getVertices(filters).map((v) => Mat.applyToPoint(this.matrix, v))\n\t}\n\n\tgetBoundsVertices(): Vec[] {\n\t\treturn this.geometry.getBoundsVertices().map((v) => Mat.applyToPoint(this.matrix, v))\n\t}\n\n\tnearestPoint(point: VecLike, filters?: Geometry2dFilters): Vec {\n\t\treturn Mat.applyToPoint(\n\t\t\tthis.matrix,\n\t\t\tthis.geometry.nearestPoint(Mat.applyToPoint(this.inverse, point), filters)\n\t\t)\n\t}\n\n\toverride hitTestPoint(\n\t\tpoint: VecLike,\n\t\tmargin = 0,\n\t\thitInside?: boolean,\n\t\tfilters?: Geometry2dFilters\n\t): boolean {\n\t\treturn this.geometry.hitTestPoint(\n\t\t\tMat.applyToPoint(this.inverse, point),\n\t\t\tmargin / this.decomposed.scaleX,\n\t\t\thitInside,\n\t\t\tfilters\n\t\t)\n\t}\n\n\toverride distanceToPoint(point: VecLike, hitInside = false, filters?: Geometry2dFilters) {\n\t\treturn (\n\t\t\tthis.geometry.distanceToPoint(Mat.applyToPoint(this.inverse, point), hitInside, filters) *\n\t\t\tthis.decomposed.scaleX\n\t\t)\n\t}\n\n\toverride distanceToLineSegment(A: VecLike, B: VecLike, filters?: Geometry2dFilters) {\n\t\treturn (\n\t\t\tthis.geometry.distanceToLineSegment(\n\t\t\t\tMat.applyToPoint(this.inverse, A),\n\t\t\t\tMat.applyToPoint(this.inverse, B),\n\t\t\t\tfilters\n\t\t\t) * this.decomposed.scaleX\n\t\t)\n\t}\n\n\toverride hitTestLineSegment(\n\t\tA: VecLike,\n\t\tB: VecLike,\n\t\tdistance = 0,\n\t\tfilters?: Geometry2dFilters\n\t): boolean {\n\t\treturn this.geometry.hitTestLineSegment(\n\t\t\tMat.applyToPoint(this.inverse, A),\n\t\t\tMat.applyToPoint(this.inverse, B),\n\t\t\tdistance / this.decomposed.scaleX,\n\t\t\tfilters\n\t\t)\n\t}\n\n\toverride intersectLineSegment(A: VecLike, B: VecLike, filters?: Geometry2dFilters) {\n\t\treturn Mat.applyToPoints(\n\t\t\tthis.matrix,\n\t\t\tthis.geometry.intersectLineSegment(\n\t\t\t\tMat.applyToPoint(this.inverse, A),\n\t\t\t\tMat.applyToPoint(this.inverse, B),\n\t\t\t\tfilters\n\t\t\t)\n\t\t)\n\t}\n\n\toverride intersectCircle(center: VecLike, radius: number, filters?: Geometry2dFilters) {\n\t\treturn Mat.applyToPoints(\n\t\t\tthis.matrix,\n\t\t\tthis.geometry.intersectCircle(\n\t\t\t\tMat.applyToPoint(this.inverse, center),\n\t\t\t\tradius / this.decomposed.scaleX,\n\t\t\t\tfilters\n\t\t\t)\n\t\t)\n\t}\n\n\toverride intersectPolygon(polygon: VecLike[], filters?: Geometry2dFilters): VecLike[] {\n\t\treturn Mat.applyToPoints(\n\t\t\tthis.matrix,\n\t\t\tthis.geometry.intersectPolygon(Mat.applyToPoints(this.inverse, polygon), filters)\n\t\t)\n\t}\n\n\toverride intersectPolyline(polyline: VecLike[], filters?: Geometry2dFilters): VecLike[] {\n\t\treturn Mat.applyToPoints(\n\t\t\tthis.matrix,\n\t\t\tthis.geometry.intersectPolyline(Mat.applyToPoints(this.inverse, polyline), filters)\n\t\t)\n\t}\n\n\toverride transform(transform: MatModel, opts?: TransformedGeometry2dOptions): Geometry2d {\n\t\treturn new TransformedGeometry2d(this.geometry, Mat.Multiply(transform, this.matrix), {\n\t\t\tisLabel: opts?.isLabel ?? this.isLabel,\n\t\t\tisInternal: opts?.isInternal ?? this.isInternal,\n\t\t\tdebugColor: opts?.debugColor ?? this.debugColor,\n\t\t\tignore: opts?.ignore ?? this.ignore,\n\t\t})\n\t}\n\n\tgetSvgPathData(): string {\n\t\tthrow new Error('Cannot get SVG path data for transformed geometry.')\n\t}\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["import_utils"]
|
|
7
7
|
}
|
|
@@ -99,6 +99,10 @@ class Group2d extends import_Geometry2d.Geometry2d {
|
|
|
99
99
|
return child.intersectCircle(center, radius, filters);
|
|
100
100
|
});
|
|
101
101
|
}
|
|
102
|
+
getBoundsVertices() {
|
|
103
|
+
if (this.excludeFromShapeBounds) return [];
|
|
104
|
+
return this.children.flatMap((child) => child.getBoundsVertices());
|
|
105
|
+
}
|
|
102
106
|
intersectPolygon(polygon, filters) {
|
|
103
107
|
return this.children.flatMap((child) => {
|
|
104
108
|
if (child.isExcludedByFilter(filters)) return import_state.EMPTY_ARRAY;
|
|
@@ -174,7 +178,7 @@ class Group2d extends import_Geometry2d.Geometry2d {
|
|
|
174
178
|
for (const child of this.children) {
|
|
175
179
|
path += child.toSimpleSvgPath();
|
|
176
180
|
}
|
|
177
|
-
const corners = import_Box.Box.FromPoints(this.
|
|
181
|
+
const corners = import_Box.Box.FromPoints(this.boundsVertices).corners;
|
|
178
182
|
for (let i = 0, n = corners.length; i < n; i++) {
|
|
179
183
|
const corner = corners[i];
|
|
180
184
|
const prevCorner = corners[(i - 1 + n) % n];
|