@servicetitan/anvil2 2.8.0 → 2.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/dist/{AiMark-Cwc9KoyE.js → AiMark-DR-w6Nbm.js} +4 -4
- package/dist/{AiMark-Cwc9KoyE.js.map → AiMark-DR-w6Nbm.js.map} +1 -1
- package/dist/AiMark.js +1 -1
- package/dist/{Alert-5qhkSUN3.js → Alert-Dj61Bq8h.js} +3 -3
- package/dist/{Alert-5qhkSUN3.js.map → Alert-Dj61Bq8h.js.map} +1 -1
- package/dist/Alert.js +1 -1
- package/dist/{Announcement-fQmFNysn.js → Announcement-B9zm-_1S.js} +2 -2
- package/dist/{Announcement-fQmFNysn.js.map → Announcement-B9zm-_1S.js.map} +1 -1
- package/dist/Announcement.js +1 -1
- package/dist/{AnvilProvider-ClfmLl_6.js → AnvilProvider-DUPYyMc7.js} +2 -2
- package/dist/{AnvilProvider-ClfmLl_6.js.map → AnvilProvider-DUPYyMc7.js.map} +1 -1
- package/dist/AnvilProvider.js +1 -1
- package/dist/{Breadcrumbs-BXo2FO2n.js → Breadcrumbs-ojgYVZwe.js} +2 -2
- package/dist/{Breadcrumbs-BXo2FO2n.js.map → Breadcrumbs-ojgYVZwe.js.map} +1 -1
- package/dist/Breadcrumbs.js +1 -1
- package/dist/Button-BdrrhBTI.js +2185 -0
- package/dist/Button-BdrrhBTI.js.map +1 -0
- package/dist/Button.js +1 -1
- package/dist/{ButtonToggle-CmY77gUp.js → ButtonToggle-DaFQ3DBG.js} +2 -2
- package/dist/{ButtonToggle-CmY77gUp.js.map → ButtonToggle-DaFQ3DBG.js.map} +1 -1
- package/dist/ButtonToggle.js +1 -1
- package/dist/{Calendar-d2owsYe9.js → Calendar-Cka4unyi.js} +2 -2
- package/dist/{Calendar-d2owsYe9.js.map → Calendar-Cka4unyi.js.map} +1 -1
- package/dist/{Calendar-Bd_WELZC.js → Calendar-Dxl9QnfP.js} +3 -3
- package/dist/{Calendar-Bd_WELZC.js.map → Calendar-Dxl9QnfP.js.map} +1 -1
- package/dist/Calendar.js +2 -2
- package/dist/{Checkbox-BlFc6ZWy.js → Checkbox-B-XTVPbX.js} +3 -3
- package/dist/{Checkbox-BlFc6ZWy.js.map → Checkbox-B-XTVPbX.js.map} +1 -1
- package/dist/{Checkbox-DbaZrUE2.js → Checkbox-Cw1-KFvq.js} +2 -2
- package/dist/{Checkbox-DbaZrUE2.js.map → Checkbox-Cw1-KFvq.js.map} +1 -1
- package/dist/Checkbox.js +1 -1
- package/dist/{Chip-BnofwIUN.js → Chip-Ce0WGKAc.js} +2 -2
- package/dist/{Chip-BnofwIUN.js.map → Chip-Ce0WGKAc.js.map} +1 -1
- package/dist/Chip.js +1 -1
- package/dist/{Combobox-BOxAzG9v.js → Combobox-CNQUROyr.js} +4 -4
- package/dist/{Combobox-BOxAzG9v.js.map → Combobox-CNQUROyr.js.map} +1 -1
- package/dist/Combobox.js +1 -1
- package/dist/{DataTable-DK9xRjnq.js → DataTable-BCV_mtSy.js} +475 -67
- package/dist/DataTable-BCV_mtSy.js.map +1 -0
- package/dist/DataTable.css +64 -29
- package/dist/{DateFieldRange-5Jrz6dLl.js → DateFieldRange-D2hnF50O.js} +4 -4
- package/dist/{DateFieldRange-5Jrz6dLl.js.map → DateFieldRange-D2hnF50O.js.map} +1 -1
- package/dist/DateFieldRange.js +1 -1
- package/dist/{DateFieldSingle-DWFr6Ew4.js → DateFieldSingle-BuaB7RDr.js} +4 -4
- package/dist/{DateFieldSingle-DWFr6Ew4.js.map → DateFieldSingle-BuaB7RDr.js.map} +1 -1
- package/dist/DateFieldSingle.js +1 -1
- package/dist/{DateFieldYearless-UU22A5-E.js → DateFieldYearless-DLeMEutt.js} +4 -4
- package/dist/{DateFieldYearless-UU22A5-E.js.map → DateFieldYearless-DLeMEutt.js.map} +1 -1
- package/dist/DateFieldYearless.js +1 -1
- package/dist/{DateFieldYearlessRange-BoPLxm6t.js → DateFieldYearlessRange-BfPuYKKC.js} +3 -3
- package/dist/{DateFieldYearlessRange-BoPLxm6t.js.map → DateFieldYearlessRange-BfPuYKKC.js.map} +1 -1
- package/dist/DateFieldYearlessRange.js +1 -1
- package/dist/{DaysOfTheWeek-4cfTmjzm.js → DaysOfTheWeek-BW1T8sTU.js} +3 -3
- package/dist/{DaysOfTheWeek-4cfTmjzm.js.map → DaysOfTheWeek-BW1T8sTU.js.map} +1 -1
- package/dist/DaysOfTheWeek.js +1 -1
- package/dist/{Dialog-Dn836WQM.js → Dialog-Cewu2pd_.js} +38 -10
- package/dist/Dialog-Cewu2pd_.js.map +1 -0
- package/dist/Dialog.js +1 -1
- package/dist/{DialogCancelButton-B-jfihJr.js → DialogCancelButton-Czz4Wpse.js} +2 -2
- package/dist/{DialogCancelButton-B-jfihJr.js.map → DialogCancelButton-Czz4Wpse.js.map} +1 -1
- package/dist/{Drawer-CdDWt_Ba.js → Drawer-Cb5asXWf.js} +38 -10
- package/dist/Drawer-Cb5asXWf.js.map +1 -0
- package/dist/Drawer.js +1 -1
- package/dist/DrillDown.js +1 -1
- package/dist/DrillDown.module-C8VOhzaF.js.map +1 -1
- package/dist/{EditCard-CZibhEfS.js → EditCard-DlJE3LXN.js} +3 -3
- package/dist/{EditCard-CZibhEfS.js.map → EditCard-DlJE3LXN.js.map} +1 -1
- package/dist/EditCard.js +1 -1
- package/dist/{FieldLabel-Dr41PRxH.js → FieldLabel-HO2VP-4B.js} +2 -2
- package/dist/{FieldLabel-Dr41PRxH.js.map → FieldLabel-HO2VP-4B.js.map} +1 -1
- package/dist/FieldLabel.js +1 -1
- package/dist/{InputMask-CcXqzqdx.js → InputMask-CLLTehFI.js} +3 -3
- package/dist/{InputMask-CcXqzqdx.js.map → InputMask-CLLTehFI.js.map} +1 -1
- package/dist/InputMask.js +1 -1
- package/dist/{ListView-D9cZUVer.js → ListView-CPi-qG2w.js} +2 -2
- package/dist/{ListView-D9cZUVer.js.map → ListView-CPi-qG2w.js.map} +1 -1
- package/dist/ListView.js +1 -1
- package/dist/{Listbox-CgDwzRfz.js → Listbox-Bp4hqIpH.js} +2 -2
- package/dist/{Listbox-CgDwzRfz.js.map → Listbox-Bp4hqIpH.js.map} +1 -1
- package/dist/Listbox.js +1 -1
- package/dist/{Menu-CPbuIsqC.js → Menu-CCavGohP.js} +91 -93
- package/dist/Menu-CCavGohP.js.map +1 -0
- package/dist/Menu.js +1 -1
- package/dist/MultiSelectField.js +1 -1
- package/dist/{MultiSelectFieldSync-Ei7DXzvs.js → MultiSelectFieldSync-ChZCW4M9.js} +7 -7
- package/dist/{MultiSelectFieldSync-Ei7DXzvs.js.map → MultiSelectFieldSync-ChZCW4M9.js.map} +1 -1
- package/dist/MultiSelectMenu.js +1 -1
- package/dist/{MultiSelectMenuSync-B_mXpTEe.js → MultiSelectMenuSync-7C1wW4oO.js} +3 -3
- package/dist/{MultiSelectMenuSync-B_mXpTEe.js.map → MultiSelectMenuSync-7C1wW4oO.js.map} +1 -1
- package/dist/{NumberField-C5t47Obp.js → NumberField-CZSTHBeO.js} +4 -4
- package/dist/{NumberField-C5t47Obp.js.map → NumberField-CZSTHBeO.js.map} +1 -1
- package/dist/NumberField.js +1 -1
- package/dist/{Page-2hbQxUj6.js → Page-BHdvTlfE.js} +111 -62
- package/dist/Page-BHdvTlfE.js.map +1 -0
- package/dist/Page.css +76 -76
- package/dist/Page.js +1 -1
- package/dist/{Pagination-CjGmJ_rU.js → Pagination-DecGSuW4.js} +5 -5
- package/dist/{Pagination-CjGmJ_rU.js.map → Pagination-DecGSuW4.js.map} +1 -1
- package/dist/Pagination.js +1 -1
- package/dist/{Popover-CpU9VAcb.js → Popover-BbqTZw-1.js} +3 -3
- package/dist/{Popover-CpU9VAcb.js.map → Popover-BbqTZw-1.js.map} +1 -1
- package/dist/Popover.js +1 -1
- package/dist/{ProgressBar-FMuK8viJ.js → ProgressBar-CZcxkdX6.js} +2 -2
- package/dist/{ProgressBar-FMuK8viJ.js.map → ProgressBar-CZcxkdX6.js.map} +1 -1
- package/dist/ProgressBar.js +1 -1
- package/dist/{Radio-DmtVWAmN.js → Radio-BFr8AdHc.js} +2 -2
- package/dist/{Radio-DmtVWAmN.js.map → Radio-BFr8AdHc.js.map} +1 -1
- package/dist/{Radio-CZZd8phn.js → Radio-DJZVMCv0.js} +3 -3
- package/dist/{Radio-CZZd8phn.js.map → Radio-DJZVMCv0.js.map} +1 -1
- package/dist/Radio.js +1 -1
- package/dist/{SelectCard-8OmIDl1m.js → SelectCard-DVcWJRbX.js} +3 -3
- package/dist/{SelectCard-8OmIDl1m.js.map → SelectCard-DVcWJRbX.js.map} +1 -1
- package/dist/SelectCard.js +1 -1
- package/dist/SelectField.js +1 -1
- package/dist/{SelectFieldLabel-C8PrXxDU.js → SelectFieldLabel-kEBS8L4l.js} +2 -2
- package/dist/{SelectFieldLabel-C8PrXxDU.js.map → SelectFieldLabel-kEBS8L4l.js.map} +1 -1
- package/dist/{SelectFieldSync-DGK8F2G9.js → SelectFieldSync-o1Cp9UYC.js} +6 -6
- package/dist/{SelectFieldSync-DGK8F2G9.js.map → SelectFieldSync-o1Cp9UYC.js.map} +1 -1
- package/dist/SelectMenu.js +1 -1
- package/dist/{SelectMenuSync-CuZp9mnt.js → SelectMenuSync-DXrwecFt.js} +3 -3
- package/dist/{SelectMenuSync-CuZp9mnt.js.map → SelectMenuSync-DXrwecFt.js.map} +1 -1
- package/dist/{SelectOptions-CmElsiTd.js → SelectOptions-Dy2OWqxn.js} +2 -2
- package/dist/{SelectOptions-CmElsiTd.js.map → SelectOptions-Dy2OWqxn.js.map} +1 -1
- package/dist/{SelectTrigger-KF8w6Ynk.js → SelectTrigger-DhKYzEAr.js} +2 -2
- package/dist/{SelectTrigger-KF8w6Ynk.js.map → SelectTrigger-DhKYzEAr.js.map} +1 -1
- package/dist/SelectTrigger.js +1 -1
- package/dist/{SelectTriggerBase-Bxmv6oXk.js → SelectTriggerBase-Ni8WqeUx.js} +76 -63
- package/dist/SelectTriggerBase-Ni8WqeUx.js.map +1 -0
- package/dist/SelectTriggerBase.css +83 -66
- package/dist/SelectTriggerBase.module-CKoq6qzX.js +38 -0
- package/dist/SelectTriggerBase.module-CKoq6qzX.js.map +1 -0
- package/dist/{Stepper-_27Lmm2K.js → Stepper-Dt2xAXth.js} +2 -2
- package/dist/{Stepper-_27Lmm2K.js.map → Stepper-Dt2xAXth.js.map} +1 -1
- package/dist/Stepper.js +1 -1
- package/dist/{Switch-DPGz7wC_.js → Switch-C84MBChG.js} +2 -2
- package/dist/{Switch-DPGz7wC_.js.map → Switch-C84MBChG.js.map} +1 -1
- package/dist/Switch.js +1 -1
- package/dist/Table.js +1 -1
- package/dist/{Text-MVxRo6yx.js → Text-WiS8UZkY.js} +2 -2
- package/dist/{Text-MVxRo6yx.js.map → Text-WiS8UZkY.js.map} +1 -1
- package/dist/Text.js +1 -1
- package/dist/{TextField-BpSxZa0z.js → TextField-Bul_uln5.js} +3 -3
- package/dist/{TextField-BpSxZa0z.js.map → TextField-Bul_uln5.js.map} +1 -1
- package/dist/{TextField-D93iv_pk.js → TextField-OznkTx4e.js} +2 -2
- package/dist/{TextField-D93iv_pk.js.map → TextField-OznkTx4e.js.map} +1 -1
- package/dist/TextField.js +1 -1
- package/dist/{Textarea-1u2fSMTh.js → Textarea-CCYLsJ1x.js} +3 -3
- package/dist/{Textarea-1u2fSMTh.js.map → Textarea-CCYLsJ1x.js.map} +1 -1
- package/dist/Textarea.js +1 -1
- package/dist/{TimeField-B4gLlBQJ.js → TimeField-BPvPbD8H.js} +4 -4
- package/dist/{TimeField-B4gLlBQJ.js.map → TimeField-BPvPbD8H.js.map} +1 -1
- package/dist/TimeField.js +1 -1
- package/dist/Toast.js +2 -2
- package/dist/{Toaster-DbWYnF_t.js → Toaster-CIaIvwH6.js} +2 -2
- package/dist/{Toaster-DbWYnF_t.js.map → Toaster-CIaIvwH6.js.map} +1 -1
- package/dist/{Toaster-CSJfSOHx.js → Toaster-DYJm06Vb.js} +4 -4
- package/dist/{Toaster-CSJfSOHx.js.map → Toaster-DYJm06Vb.js.map} +1 -1
- package/dist/{Toolbar-CWRk523l.js → Toolbar-ByyI7SqG.js} +14 -14
- package/dist/{Toolbar-CWRk523l.js.map → Toolbar-ByyI7SqG.js.map} +1 -1
- package/dist/Toolbar.js +1 -1
- package/dist/{YearlessDateInputWithPicker-BSl5z2zo.js → YearlessDateInputWithPicker-C_twiQW5.js} +2 -2
- package/dist/{YearlessDateInputWithPicker-BSl5z2zo.js.map → YearlessDateInputWithPicker-C_twiQW5.js.map} +1 -1
- package/dist/beta/components/Table/DataTable/DataTable.d.ts +6 -3
- package/dist/beta/components/Table/DataTable/internal/DataTableFooter.d.ts +5 -5
- package/dist/beta/components/Table/DataTable/internal/cells/DataTableHeaderCell.d.ts +4 -4
- package/dist/beta/components/Table/DataTable/internal/util/getTanStackColumnDef.d.ts +13 -2
- package/dist/beta/components/Table/base/cells/TableHeaderCell.d.ts +4 -0
- package/dist/beta/components/Table/createColumnHelper.d.ts +17 -10
- package/dist/beta/components/Table/formatters/htmlFormatter.d.ts +13 -0
- package/dist/beta/components/Table/formatters/htmlToMarkdown.d.ts +11 -0
- package/dist/beta/components/Table/formatters/index.d.ts +2 -0
- package/dist/beta/components/Table/formatters/markdownFormatter.d.ts +11 -0
- package/dist/beta/components/Table/types.d.ts +41 -8
- package/dist/beta.js +9 -9
- package/dist/components/DrillDown/internal/DrillDownContext.d.ts +4 -0
- package/dist/components/DrillDown/internal/useDrillDownContextState.d.ts +4 -0
- package/dist/index.js +43 -44
- package/dist/index.js.map +1 -1
- package/dist/internal/flubber/a2c.d.ts +16 -0
- package/dist/internal/flubber/add.d.ts +3 -0
- package/dist/internal/flubber/arc.d.ts +26 -0
- package/dist/internal/flubber/bezier.d.ts +32 -0
- package/dist/internal/flubber/errors.d.ts +5 -0
- package/dist/internal/flubber/index.d.ts +6 -0
- package/dist/internal/flubber/interpolate.d.ts +7 -0
- package/dist/internal/flubber/linear.d.ts +27 -0
- package/dist/internal/flubber/math.d.ts +10 -0
- package/dist/internal/flubber/normalize.d.ts +4 -0
- package/dist/internal/flubber/parse.d.ts +7 -0
- package/dist/internal/flubber/path-properties.d.ts +23 -0
- package/dist/internal/flubber/rotate.d.ts +2 -0
- package/dist/internal/flubber/svg.d.ts +9 -0
- package/dist/internal/index.d.ts +1 -0
- package/dist/{stripInlineMarkdown-DyqLAQnf.js → stripInlineMarkdown-Cg1qlNwL.js} +2 -2
- package/dist/{stripInlineMarkdown-DyqLAQnf.js.map → stripInlineMarkdown-Cg1qlNwL.js.map} +1 -1
- package/dist/{syncFilterUtils-CsbCnI1-.js → syncFilterUtils-UR5Vgqkh.js} +7 -8
- package/dist/{syncFilterUtils-CsbCnI1-.js.map → syncFilterUtils-UR5Vgqkh.js.map} +1 -1
- package/dist/{useDrilldown-C7eMBl68.js → useDrilldown-D6VZNSCX.js} +46 -20
- package/dist/{useDrilldown-C7eMBl68.js.map → useDrilldown-D6VZNSCX.js.map} +1 -1
- package/dist/{useInitialFocus-DbaB-x5T.js → useInitialFocus-BUxEDMEG.js} +65 -23
- package/dist/useInitialFocus-BUxEDMEG.js.map +1 -0
- package/dist/{usePopoverTransitionStates-B1opfxxn.js → usePopoverTransitionStates-CDXCdyKa.js} +2 -1
- package/dist/{usePopoverTransitionStates-B1opfxxn.js.map → usePopoverTransitionStates-CDXCdyKa.js.map} +1 -1
- package/dist/{useToggleSelection-BM8asdFj.js → useToggleSelection-BBdrIVWs.js} +2 -2
- package/dist/{useToggleSelection-BM8asdFj.js.map → useToggleSelection-BBdrIVWs.js.map} +1 -1
- package/package.json +3 -5
- package/dist/Button-a_D7tUgM.js +0 -4517
- package/dist/Button-a_D7tUgM.js.map +0 -1
- package/dist/DataTable-DK9xRjnq.js.map +0 -1
- package/dist/Dialog-Dn836WQM.js.map +0 -1
- package/dist/Drawer-CdDWt_Ba.js.map +0 -1
- package/dist/Menu-CPbuIsqC.js.map +0 -1
- package/dist/Page-2hbQxUj6.js.map +0 -1
- package/dist/SelectTriggerBase-Bxmv6oXk.js.map +0 -1
- package/dist/SelectTriggerBase.module-B0NFRlQP.js +0 -36
- package/dist/SelectTriggerBase.module-B0NFRlQP.js.map +0 -1
- package/dist/useInitialFocus-DbaB-x5T.js.map +0 -1
- /package/dist/{anvil-fonts.css → AnvilProvider.css} +0 -0
package/dist/Button-a_D7tUgM.js
DELETED
|
@@ -1,4517 +0,0 @@
|
|
|
1
|
-
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
-
import * as React from 'react';
|
|
3
|
-
import { useContext, useState, useEffect, useMemo, memo, forwardRef, useCallback } from 'react';
|
|
4
|
-
import { I as Icon } from './Icon-DuIlne4x.js';
|
|
5
|
-
import { S as Spinner } from './Spinner-BqmcE2pb.js';
|
|
6
|
-
import { w as warnOnce } from './warnOnce-Y9PRHcU4.js';
|
|
7
|
-
import { g as getDefaultExportFromCjs, c as cx } from './index-De1g9FRV.js';
|
|
8
|
-
import { u as usePrefersReducedMotion } from './usePrefersReducedMotion-DR9B_D6w.js';
|
|
9
|
-
import { u as useTheme } from './useTheme-B4i6a3bM.js';
|
|
10
|
-
import { d as isEasingArray, e as interpolate$1, u as useConstant, f as motionValue, M as MotionConfigContext, c as useIsomorphicLayoutEffect, g as frame, j as cancelFrame, k as collectMotionValues, r as resolveElements, l as mixNumber, n as removeItem, o as isMotionValue, q as defaultOffset, s as createGeneratorEasing, t as fillOffset, v as isGenerator, x as secondsToMilliseconds, y as invariant, z as progress, V as VisualElement, A as createBox, B as isSVGElement, C as isSVGSVGElement, S as SVGVisualElement, H as HTMLVisualElement, D as visualElementStore, E as animateSingleValue, F as animateTarget, G as spring, m as motion } from './proxy-DEehATlA.js';
|
|
11
|
-
import { s as styles } from './Button.module-wCtFYGVD.js';
|
|
12
|
-
import { u as useLayoutPropsUtil } from './useLayoutPropsUtil-DMDdfIah.js';
|
|
13
|
-
import { c as childrenToString } from './childrenToString-Bz9MqbHb.js';
|
|
14
|
-
import { useTrackingId } from './useTrackingId.js';
|
|
15
|
-
|
|
16
|
-
const wrap = (min, max, v) => {
|
|
17
|
-
const rangeSize = max - min;
|
|
18
|
-
return ((((v - min) % rangeSize) + rangeSize) % rangeSize) + min;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
function getEasingForSegment(easing, i) {
|
|
22
|
-
return isEasingArray(easing) ? easing[wrap(0, easing.length, i)] : easing;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
class GroupAnimation {
|
|
26
|
-
constructor(animations) {
|
|
27
|
-
// Bound to accomadate common `return animation.stop` pattern
|
|
28
|
-
this.stop = () => this.runAll("stop");
|
|
29
|
-
this.animations = animations.filter(Boolean);
|
|
30
|
-
}
|
|
31
|
-
get finished() {
|
|
32
|
-
return Promise.all(this.animations.map((animation) => animation.finished));
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* TODO: Filter out cancelled or stopped animations before returning
|
|
36
|
-
*/
|
|
37
|
-
getAll(propName) {
|
|
38
|
-
return this.animations[0][propName];
|
|
39
|
-
}
|
|
40
|
-
setAll(propName, newValue) {
|
|
41
|
-
for (let i = 0; i < this.animations.length; i++) {
|
|
42
|
-
this.animations[i][propName] = newValue;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
attachTimeline(timeline) {
|
|
46
|
-
const subscriptions = this.animations.map((animation) => animation.attachTimeline(timeline));
|
|
47
|
-
return () => {
|
|
48
|
-
subscriptions.forEach((cancel, i) => {
|
|
49
|
-
cancel && cancel();
|
|
50
|
-
this.animations[i].stop();
|
|
51
|
-
});
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
get time() {
|
|
55
|
-
return this.getAll("time");
|
|
56
|
-
}
|
|
57
|
-
set time(time) {
|
|
58
|
-
this.setAll("time", time);
|
|
59
|
-
}
|
|
60
|
-
get speed() {
|
|
61
|
-
return this.getAll("speed");
|
|
62
|
-
}
|
|
63
|
-
set speed(speed) {
|
|
64
|
-
this.setAll("speed", speed);
|
|
65
|
-
}
|
|
66
|
-
get state() {
|
|
67
|
-
return this.getAll("state");
|
|
68
|
-
}
|
|
69
|
-
get startTime() {
|
|
70
|
-
return this.getAll("startTime");
|
|
71
|
-
}
|
|
72
|
-
get duration() {
|
|
73
|
-
let max = 0;
|
|
74
|
-
for (let i = 0; i < this.animations.length; i++) {
|
|
75
|
-
max = Math.max(max, this.animations[i].duration);
|
|
76
|
-
}
|
|
77
|
-
return max;
|
|
78
|
-
}
|
|
79
|
-
runAll(methodName) {
|
|
80
|
-
this.animations.forEach((controls) => controls[methodName]());
|
|
81
|
-
}
|
|
82
|
-
play() {
|
|
83
|
-
this.runAll("play");
|
|
84
|
-
}
|
|
85
|
-
pause() {
|
|
86
|
-
this.runAll("pause");
|
|
87
|
-
}
|
|
88
|
-
cancel() {
|
|
89
|
-
this.runAll("cancel");
|
|
90
|
-
}
|
|
91
|
-
complete() {
|
|
92
|
-
this.runAll("complete");
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
class GroupAnimationWithThen extends GroupAnimation {
|
|
97
|
-
then(onResolve, _onReject) {
|
|
98
|
-
return this.finished.finally(onResolve).then(() => { });
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
function transform(...args) {
|
|
103
|
-
const useImmediate = !Array.isArray(args[0]);
|
|
104
|
-
const argOffset = useImmediate ? 0 : -1;
|
|
105
|
-
const inputValue = args[0 + argOffset];
|
|
106
|
-
const inputRange = args[1 + argOffset];
|
|
107
|
-
const outputRange = args[2 + argOffset];
|
|
108
|
-
const options = args[3 + argOffset];
|
|
109
|
-
const interpolator = interpolate$1(inputRange, outputRange, options);
|
|
110
|
-
return useImmediate ? interpolator(inputValue) : interpolator;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Creates a `MotionValue` to track the state and velocity of a value.
|
|
115
|
-
*
|
|
116
|
-
* Usually, these are created automatically. For advanced use-cases, like use with `useTransform`, you can create `MotionValue`s externally and pass them into the animated component via the `style` prop.
|
|
117
|
-
*
|
|
118
|
-
* ```jsx
|
|
119
|
-
* export const MyComponent = () => {
|
|
120
|
-
* const scale = useMotionValue(1)
|
|
121
|
-
*
|
|
122
|
-
* return <motion.div style={{ scale }} />
|
|
123
|
-
* }
|
|
124
|
-
* ```
|
|
125
|
-
*
|
|
126
|
-
* @param initial - The initial state.
|
|
127
|
-
*
|
|
128
|
-
* @public
|
|
129
|
-
*/
|
|
130
|
-
function useMotionValue(initial) {
|
|
131
|
-
const value = useConstant(() => motionValue(initial));
|
|
132
|
-
/**
|
|
133
|
-
* If this motion value is being used in static mode, like on
|
|
134
|
-
* the Framer canvas, force components to rerender when the motion
|
|
135
|
-
* value is updated.
|
|
136
|
-
*/
|
|
137
|
-
const { isStatic } = useContext(MotionConfigContext);
|
|
138
|
-
if (isStatic) {
|
|
139
|
-
const [, setLatest] = useState(initial);
|
|
140
|
-
useEffect(() => value.on("change", setLatest), []);
|
|
141
|
-
}
|
|
142
|
-
return value;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
function useCombineMotionValues(values, combineValues) {
|
|
146
|
-
/**
|
|
147
|
-
* Initialise the returned motion value. This remains the same between renders.
|
|
148
|
-
*/
|
|
149
|
-
const value = useMotionValue(combineValues());
|
|
150
|
-
/**
|
|
151
|
-
* Create a function that will update the template motion value with the latest values.
|
|
152
|
-
* This is pre-bound so whenever a motion value updates it can schedule its
|
|
153
|
-
* execution in Framesync. If it's already been scheduled it won't be fired twice
|
|
154
|
-
* in a single frame.
|
|
155
|
-
*/
|
|
156
|
-
const updateValue = () => value.set(combineValues());
|
|
157
|
-
/**
|
|
158
|
-
* Synchronously update the motion value with the latest values during the render.
|
|
159
|
-
* This ensures that within a React render, the styles applied to the DOM are up-to-date.
|
|
160
|
-
*/
|
|
161
|
-
updateValue();
|
|
162
|
-
/**
|
|
163
|
-
* Subscribe to all motion values found within the template. Whenever any of them change,
|
|
164
|
-
* schedule an update.
|
|
165
|
-
*/
|
|
166
|
-
useIsomorphicLayoutEffect(() => {
|
|
167
|
-
const scheduleUpdate = () => frame.preRender(updateValue, false, true);
|
|
168
|
-
const subscriptions = values.map((v) => v.on("change", scheduleUpdate));
|
|
169
|
-
return () => {
|
|
170
|
-
subscriptions.forEach((unsubscribe) => unsubscribe());
|
|
171
|
-
cancelFrame(updateValue);
|
|
172
|
-
};
|
|
173
|
-
});
|
|
174
|
-
return value;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
function useComputed(compute) {
|
|
178
|
-
/**
|
|
179
|
-
* Open session of collectMotionValues. Any MotionValue that calls get()
|
|
180
|
-
* will be saved into this array.
|
|
181
|
-
*/
|
|
182
|
-
collectMotionValues.current = [];
|
|
183
|
-
compute();
|
|
184
|
-
const value = useCombineMotionValues(collectMotionValues.current, compute);
|
|
185
|
-
/**
|
|
186
|
-
* Synchronously close session of collectMotionValues.
|
|
187
|
-
*/
|
|
188
|
-
collectMotionValues.current = undefined;
|
|
189
|
-
return value;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
function useTransform(input, inputRangeOrTransformer, outputRange, options) {
|
|
193
|
-
if (typeof input === "function") {
|
|
194
|
-
return useComputed(input);
|
|
195
|
-
}
|
|
196
|
-
const transformer = typeof inputRangeOrTransformer === "function"
|
|
197
|
-
? inputRangeOrTransformer
|
|
198
|
-
: transform(inputRangeOrTransformer, outputRange, options);
|
|
199
|
-
return Array.isArray(input)
|
|
200
|
-
? useListTransform(input, transformer)
|
|
201
|
-
: useListTransform([input], ([latest]) => transformer(latest));
|
|
202
|
-
}
|
|
203
|
-
function useListTransform(values, transformer) {
|
|
204
|
-
const latest = useConstant(() => []);
|
|
205
|
-
return useCombineMotionValues(values, () => {
|
|
206
|
-
latest.length = 0;
|
|
207
|
-
const numValues = values.length;
|
|
208
|
-
for (let i = 0; i < numValues; i++) {
|
|
209
|
-
latest[i] = values[i].get();
|
|
210
|
-
}
|
|
211
|
-
return transformer(latest);
|
|
212
|
-
});
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
function isDOMKeyframes(keyframes) {
|
|
216
|
-
return typeof keyframes === "object" && !Array.isArray(keyframes);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
function resolveSubjects(subject, keyframes, scope, selectorCache) {
|
|
220
|
-
if (typeof subject === "string" && isDOMKeyframes(keyframes)) {
|
|
221
|
-
return resolveElements(subject, scope, selectorCache);
|
|
222
|
-
}
|
|
223
|
-
else if (subject instanceof NodeList) {
|
|
224
|
-
return Array.from(subject);
|
|
225
|
-
}
|
|
226
|
-
else if (Array.isArray(subject)) {
|
|
227
|
-
return subject;
|
|
228
|
-
}
|
|
229
|
-
else {
|
|
230
|
-
return [subject];
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
function calculateRepeatDuration(duration, repeat, _repeatDelay) {
|
|
235
|
-
return duration * (repeat + 1);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
/**
|
|
239
|
-
* Given a absolute or relative time definition and current/prev time state of the sequence,
|
|
240
|
-
* calculate an absolute time for the next keyframes.
|
|
241
|
-
*/
|
|
242
|
-
function calcNextTime(current, next, prev, labels) {
|
|
243
|
-
if (typeof next === "number") {
|
|
244
|
-
return next;
|
|
245
|
-
}
|
|
246
|
-
else if (next.startsWith("-") || next.startsWith("+")) {
|
|
247
|
-
return Math.max(0, current + parseFloat(next));
|
|
248
|
-
}
|
|
249
|
-
else if (next === "<") {
|
|
250
|
-
return prev;
|
|
251
|
-
}
|
|
252
|
-
else if (next.startsWith("<")) {
|
|
253
|
-
return Math.max(0, prev + parseFloat(next.slice(1)));
|
|
254
|
-
}
|
|
255
|
-
else {
|
|
256
|
-
return labels.get(next) ?? current;
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
function eraseKeyframes(sequence, startTime, endTime) {
|
|
261
|
-
for (let i = 0; i < sequence.length; i++) {
|
|
262
|
-
const keyframe = sequence[i];
|
|
263
|
-
if (keyframe.at > startTime && keyframe.at < endTime) {
|
|
264
|
-
removeItem(sequence, keyframe);
|
|
265
|
-
// If we remove this item we have to push the pointer back one
|
|
266
|
-
i--;
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
function addKeyframes(sequence, keyframes, easing, offset, startTime, endTime) {
|
|
271
|
-
/**
|
|
272
|
-
* Erase every existing value between currentTime and targetTime,
|
|
273
|
-
* this will essentially splice this timeline into any currently
|
|
274
|
-
* defined ones.
|
|
275
|
-
*/
|
|
276
|
-
eraseKeyframes(sequence, startTime, endTime);
|
|
277
|
-
for (let i = 0; i < keyframes.length; i++) {
|
|
278
|
-
sequence.push({
|
|
279
|
-
value: keyframes[i],
|
|
280
|
-
at: mixNumber(startTime, endTime, offset[i]),
|
|
281
|
-
easing: getEasingForSegment(easing, i),
|
|
282
|
-
});
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
* Take an array of times that represent repeated keyframes. For instance
|
|
288
|
-
* if we have original times of [0, 0.5, 1] then our repeated times will
|
|
289
|
-
* be [0, 0.5, 1, 1, 1.5, 2]. Loop over the times and scale them back
|
|
290
|
-
* down to a 0-1 scale.
|
|
291
|
-
*/
|
|
292
|
-
function normalizeTimes(times, repeat) {
|
|
293
|
-
for (let i = 0; i < times.length; i++) {
|
|
294
|
-
times[i] = times[i] / (repeat + 1);
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
function compareByTime(a, b) {
|
|
299
|
-
if (a.at === b.at) {
|
|
300
|
-
if (a.value === null)
|
|
301
|
-
return 1;
|
|
302
|
-
if (b.value === null)
|
|
303
|
-
return -1;
|
|
304
|
-
return 0;
|
|
305
|
-
}
|
|
306
|
-
else {
|
|
307
|
-
return a.at - b.at;
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
const defaultSegmentEasing = "easeInOut";
|
|
312
|
-
const MAX_REPEAT = 20;
|
|
313
|
-
function createAnimationsFromSequence(sequence, { defaultTransition = {}, ...sequenceTransition } = {}, scope, generators) {
|
|
314
|
-
const defaultDuration = defaultTransition.duration || 0.3;
|
|
315
|
-
const animationDefinitions = new Map();
|
|
316
|
-
const sequences = new Map();
|
|
317
|
-
const elementCache = {};
|
|
318
|
-
const timeLabels = new Map();
|
|
319
|
-
let prevTime = 0;
|
|
320
|
-
let currentTime = 0;
|
|
321
|
-
let totalDuration = 0;
|
|
322
|
-
/**
|
|
323
|
-
* Build the timeline by mapping over the sequence array and converting
|
|
324
|
-
* the definitions into keyframes and offsets with absolute time values.
|
|
325
|
-
* These will later get converted into relative offsets in a second pass.
|
|
326
|
-
*/
|
|
327
|
-
for (let i = 0; i < sequence.length; i++) {
|
|
328
|
-
const segment = sequence[i];
|
|
329
|
-
/**
|
|
330
|
-
* If this is a timeline label, mark it and skip the rest of this iteration.
|
|
331
|
-
*/
|
|
332
|
-
if (typeof segment === "string") {
|
|
333
|
-
timeLabels.set(segment, currentTime);
|
|
334
|
-
continue;
|
|
335
|
-
}
|
|
336
|
-
else if (!Array.isArray(segment)) {
|
|
337
|
-
timeLabels.set(segment.name, calcNextTime(currentTime, segment.at, prevTime, timeLabels));
|
|
338
|
-
continue;
|
|
339
|
-
}
|
|
340
|
-
let [subject, keyframes, transition = {}] = segment;
|
|
341
|
-
/**
|
|
342
|
-
* If a relative or absolute time value has been specified we need to resolve
|
|
343
|
-
* it in relation to the currentTime.
|
|
344
|
-
*/
|
|
345
|
-
if (transition.at !== undefined) {
|
|
346
|
-
currentTime = calcNextTime(currentTime, transition.at, prevTime, timeLabels);
|
|
347
|
-
}
|
|
348
|
-
/**
|
|
349
|
-
* Keep track of the maximum duration in this definition. This will be
|
|
350
|
-
* applied to currentTime once the definition has been parsed.
|
|
351
|
-
*/
|
|
352
|
-
let maxDuration = 0;
|
|
353
|
-
const resolveValueSequence = (valueKeyframes, valueTransition, valueSequence, elementIndex = 0, numSubjects = 0) => {
|
|
354
|
-
const valueKeyframesAsList = keyframesAsList(valueKeyframes);
|
|
355
|
-
const { delay = 0, times = defaultOffset(valueKeyframesAsList), type = "keyframes", repeat, repeatType, repeatDelay = 0, ...remainingTransition } = valueTransition;
|
|
356
|
-
let { ease = defaultTransition.ease || "easeOut", duration } = valueTransition;
|
|
357
|
-
/**
|
|
358
|
-
* Resolve stagger() if defined.
|
|
359
|
-
*/
|
|
360
|
-
const calculatedDelay = typeof delay === "function"
|
|
361
|
-
? delay(elementIndex, numSubjects)
|
|
362
|
-
: delay;
|
|
363
|
-
/**
|
|
364
|
-
* If this animation should and can use a spring, generate a spring easing function.
|
|
365
|
-
*/
|
|
366
|
-
const numKeyframes = valueKeyframesAsList.length;
|
|
367
|
-
const createGenerator = isGenerator(type)
|
|
368
|
-
? type
|
|
369
|
-
: generators?.[type || "keyframes"];
|
|
370
|
-
if (numKeyframes <= 2 && createGenerator) {
|
|
371
|
-
/**
|
|
372
|
-
* As we're creating an easing function from a spring,
|
|
373
|
-
* ideally we want to generate it using the real distance
|
|
374
|
-
* between the two keyframes. However this isn't always
|
|
375
|
-
* possible - in these situations we use 0-100.
|
|
376
|
-
*/
|
|
377
|
-
let absoluteDelta = 100;
|
|
378
|
-
if (numKeyframes === 2 &&
|
|
379
|
-
isNumberKeyframesArray(valueKeyframesAsList)) {
|
|
380
|
-
const delta = valueKeyframesAsList[1] - valueKeyframesAsList[0];
|
|
381
|
-
absoluteDelta = Math.abs(delta);
|
|
382
|
-
}
|
|
383
|
-
const springTransition = { ...remainingTransition };
|
|
384
|
-
if (duration !== undefined) {
|
|
385
|
-
springTransition.duration = secondsToMilliseconds(duration);
|
|
386
|
-
}
|
|
387
|
-
const springEasing = createGeneratorEasing(springTransition, absoluteDelta, createGenerator);
|
|
388
|
-
ease = springEasing.ease;
|
|
389
|
-
duration = springEasing.duration;
|
|
390
|
-
}
|
|
391
|
-
duration ?? (duration = defaultDuration);
|
|
392
|
-
const startTime = currentTime + calculatedDelay;
|
|
393
|
-
/**
|
|
394
|
-
* If there's only one time offset of 0, fill in a second with length 1
|
|
395
|
-
*/
|
|
396
|
-
if (times.length === 1 && times[0] === 0) {
|
|
397
|
-
times[1] = 1;
|
|
398
|
-
}
|
|
399
|
-
/**
|
|
400
|
-
* Fill out if offset if fewer offsets than keyframes
|
|
401
|
-
*/
|
|
402
|
-
const remainder = times.length - valueKeyframesAsList.length;
|
|
403
|
-
remainder > 0 && fillOffset(times, remainder);
|
|
404
|
-
/**
|
|
405
|
-
* If only one value has been set, ie [1], push a null to the start of
|
|
406
|
-
* the keyframe array. This will let us mark a keyframe at this point
|
|
407
|
-
* that will later be hydrated with the previous value.
|
|
408
|
-
*/
|
|
409
|
-
valueKeyframesAsList.length === 1 &&
|
|
410
|
-
valueKeyframesAsList.unshift(null);
|
|
411
|
-
/**
|
|
412
|
-
* Handle repeat options
|
|
413
|
-
*/
|
|
414
|
-
if (repeat) {
|
|
415
|
-
invariant(repeat < MAX_REPEAT, "Repeat count too high, must be less than 20", "repeat-count-high");
|
|
416
|
-
duration = calculateRepeatDuration(duration, repeat);
|
|
417
|
-
const originalKeyframes = [...valueKeyframesAsList];
|
|
418
|
-
const originalTimes = [...times];
|
|
419
|
-
ease = Array.isArray(ease) ? [...ease] : [ease];
|
|
420
|
-
const originalEase = [...ease];
|
|
421
|
-
for (let repeatIndex = 0; repeatIndex < repeat; repeatIndex++) {
|
|
422
|
-
valueKeyframesAsList.push(...originalKeyframes);
|
|
423
|
-
for (let keyframeIndex = 0; keyframeIndex < originalKeyframes.length; keyframeIndex++) {
|
|
424
|
-
times.push(originalTimes[keyframeIndex] + (repeatIndex + 1));
|
|
425
|
-
ease.push(keyframeIndex === 0
|
|
426
|
-
? "linear"
|
|
427
|
-
: getEasingForSegment(originalEase, keyframeIndex - 1));
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
normalizeTimes(times, repeat);
|
|
431
|
-
}
|
|
432
|
-
const targetTime = startTime + duration;
|
|
433
|
-
/**
|
|
434
|
-
* Add keyframes, mapping offsets to absolute time.
|
|
435
|
-
*/
|
|
436
|
-
addKeyframes(valueSequence, valueKeyframesAsList, ease, times, startTime, targetTime);
|
|
437
|
-
maxDuration = Math.max(calculatedDelay + duration, maxDuration);
|
|
438
|
-
totalDuration = Math.max(targetTime, totalDuration);
|
|
439
|
-
};
|
|
440
|
-
if (isMotionValue(subject)) {
|
|
441
|
-
const subjectSequence = getSubjectSequence(subject, sequences);
|
|
442
|
-
resolveValueSequence(keyframes, transition, getValueSequence("default", subjectSequence));
|
|
443
|
-
}
|
|
444
|
-
else {
|
|
445
|
-
const subjects = resolveSubjects(subject, keyframes, scope, elementCache);
|
|
446
|
-
const numSubjects = subjects.length;
|
|
447
|
-
/**
|
|
448
|
-
* For every element in this segment, process the defined values.
|
|
449
|
-
*/
|
|
450
|
-
for (let subjectIndex = 0; subjectIndex < numSubjects; subjectIndex++) {
|
|
451
|
-
/**
|
|
452
|
-
* Cast necessary, but we know these are of this type
|
|
453
|
-
*/
|
|
454
|
-
keyframes = keyframes;
|
|
455
|
-
transition = transition;
|
|
456
|
-
const thisSubject = subjects[subjectIndex];
|
|
457
|
-
const subjectSequence = getSubjectSequence(thisSubject, sequences);
|
|
458
|
-
for (const key in keyframes) {
|
|
459
|
-
resolveValueSequence(keyframes[key], getValueTransition(transition, key), getValueSequence(key, subjectSequence), subjectIndex, numSubjects);
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
prevTime = currentTime;
|
|
464
|
-
currentTime += maxDuration;
|
|
465
|
-
}
|
|
466
|
-
/**
|
|
467
|
-
* For every element and value combination create a new animation.
|
|
468
|
-
*/
|
|
469
|
-
sequences.forEach((valueSequences, element) => {
|
|
470
|
-
for (const key in valueSequences) {
|
|
471
|
-
const valueSequence = valueSequences[key];
|
|
472
|
-
/**
|
|
473
|
-
* Arrange all the keyframes in ascending time order.
|
|
474
|
-
*/
|
|
475
|
-
valueSequence.sort(compareByTime);
|
|
476
|
-
const keyframes = [];
|
|
477
|
-
const valueOffset = [];
|
|
478
|
-
const valueEasing = [];
|
|
479
|
-
/**
|
|
480
|
-
* For each keyframe, translate absolute times into
|
|
481
|
-
* relative offsets based on the total duration of the timeline.
|
|
482
|
-
*/
|
|
483
|
-
for (let i = 0; i < valueSequence.length; i++) {
|
|
484
|
-
const { at, value, easing } = valueSequence[i];
|
|
485
|
-
keyframes.push(value);
|
|
486
|
-
valueOffset.push(progress(0, totalDuration, at));
|
|
487
|
-
valueEasing.push(easing || "easeOut");
|
|
488
|
-
}
|
|
489
|
-
/**
|
|
490
|
-
* If the first keyframe doesn't land on offset: 0
|
|
491
|
-
* provide one by duplicating the initial keyframe. This ensures
|
|
492
|
-
* it snaps to the first keyframe when the animation starts.
|
|
493
|
-
*/
|
|
494
|
-
if (valueOffset[0] !== 0) {
|
|
495
|
-
valueOffset.unshift(0);
|
|
496
|
-
keyframes.unshift(keyframes[0]);
|
|
497
|
-
valueEasing.unshift(defaultSegmentEasing);
|
|
498
|
-
}
|
|
499
|
-
/**
|
|
500
|
-
* If the last keyframe doesn't land on offset: 1
|
|
501
|
-
* provide one with a null wildcard value. This will ensure it
|
|
502
|
-
* stays static until the end of the animation.
|
|
503
|
-
*/
|
|
504
|
-
if (valueOffset[valueOffset.length - 1] !== 1) {
|
|
505
|
-
valueOffset.push(1);
|
|
506
|
-
keyframes.push(null);
|
|
507
|
-
}
|
|
508
|
-
if (!animationDefinitions.has(element)) {
|
|
509
|
-
animationDefinitions.set(element, {
|
|
510
|
-
keyframes: {},
|
|
511
|
-
transition: {},
|
|
512
|
-
});
|
|
513
|
-
}
|
|
514
|
-
const definition = animationDefinitions.get(element);
|
|
515
|
-
definition.keyframes[key] = keyframes;
|
|
516
|
-
definition.transition[key] = {
|
|
517
|
-
...defaultTransition,
|
|
518
|
-
duration: totalDuration,
|
|
519
|
-
ease: valueEasing,
|
|
520
|
-
times: valueOffset,
|
|
521
|
-
...sequenceTransition,
|
|
522
|
-
};
|
|
523
|
-
}
|
|
524
|
-
});
|
|
525
|
-
return animationDefinitions;
|
|
526
|
-
}
|
|
527
|
-
function getSubjectSequence(subject, sequences) {
|
|
528
|
-
!sequences.has(subject) && sequences.set(subject, {});
|
|
529
|
-
return sequences.get(subject);
|
|
530
|
-
}
|
|
531
|
-
function getValueSequence(name, sequences) {
|
|
532
|
-
if (!sequences[name])
|
|
533
|
-
sequences[name] = [];
|
|
534
|
-
return sequences[name];
|
|
535
|
-
}
|
|
536
|
-
function keyframesAsList(keyframes) {
|
|
537
|
-
return Array.isArray(keyframes) ? keyframes : [keyframes];
|
|
538
|
-
}
|
|
539
|
-
function getValueTransition(transition, key) {
|
|
540
|
-
return transition && transition[key]
|
|
541
|
-
? {
|
|
542
|
-
...transition,
|
|
543
|
-
...transition[key],
|
|
544
|
-
}
|
|
545
|
-
: { ...transition };
|
|
546
|
-
}
|
|
547
|
-
const isNumber = (keyframe) => typeof keyframe === "number";
|
|
548
|
-
const isNumberKeyframesArray = (keyframes) => keyframes.every(isNumber);
|
|
549
|
-
|
|
550
|
-
function isObjectKey(key, object) {
|
|
551
|
-
return key in object;
|
|
552
|
-
}
|
|
553
|
-
class ObjectVisualElement extends VisualElement {
|
|
554
|
-
constructor() {
|
|
555
|
-
super(...arguments);
|
|
556
|
-
this.type = "object";
|
|
557
|
-
}
|
|
558
|
-
readValueFromInstance(instance, key) {
|
|
559
|
-
if (isObjectKey(key, instance)) {
|
|
560
|
-
const value = instance[key];
|
|
561
|
-
if (typeof value === "string" || typeof value === "number") {
|
|
562
|
-
return value;
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
return undefined;
|
|
566
|
-
}
|
|
567
|
-
getBaseTargetFromProps() {
|
|
568
|
-
return undefined;
|
|
569
|
-
}
|
|
570
|
-
removeValueFromRenderState(key, renderState) {
|
|
571
|
-
delete renderState.output[key];
|
|
572
|
-
}
|
|
573
|
-
measureInstanceViewportBox() {
|
|
574
|
-
return createBox();
|
|
575
|
-
}
|
|
576
|
-
build(renderState, latestValues) {
|
|
577
|
-
Object.assign(renderState.output, latestValues);
|
|
578
|
-
}
|
|
579
|
-
renderInstance(instance, { output }) {
|
|
580
|
-
Object.assign(instance, output);
|
|
581
|
-
}
|
|
582
|
-
sortInstanceNodePosition() {
|
|
583
|
-
return 0;
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
function createDOMVisualElement(element) {
|
|
588
|
-
const options = {
|
|
589
|
-
presenceContext: null,
|
|
590
|
-
props: {},
|
|
591
|
-
visualState: {
|
|
592
|
-
renderState: {
|
|
593
|
-
transform: {},
|
|
594
|
-
transformOrigin: {},
|
|
595
|
-
style: {},
|
|
596
|
-
vars: {},
|
|
597
|
-
attrs: {},
|
|
598
|
-
},
|
|
599
|
-
latestValues: {},
|
|
600
|
-
},
|
|
601
|
-
};
|
|
602
|
-
const node = isSVGElement(element) && !isSVGSVGElement(element)
|
|
603
|
-
? new SVGVisualElement(options)
|
|
604
|
-
: new HTMLVisualElement(options);
|
|
605
|
-
node.mount(element);
|
|
606
|
-
visualElementStore.set(element, node);
|
|
607
|
-
}
|
|
608
|
-
function createObjectVisualElement(subject) {
|
|
609
|
-
const options = {
|
|
610
|
-
presenceContext: null,
|
|
611
|
-
props: {},
|
|
612
|
-
visualState: {
|
|
613
|
-
renderState: {
|
|
614
|
-
output: {},
|
|
615
|
-
},
|
|
616
|
-
latestValues: {},
|
|
617
|
-
},
|
|
618
|
-
};
|
|
619
|
-
const node = new ObjectVisualElement(options);
|
|
620
|
-
node.mount(subject);
|
|
621
|
-
visualElementStore.set(subject, node);
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
function isSingleValue(subject, keyframes) {
|
|
625
|
-
return (isMotionValue(subject) ||
|
|
626
|
-
typeof subject === "number" ||
|
|
627
|
-
(typeof subject === "string" && !isDOMKeyframes(keyframes)));
|
|
628
|
-
}
|
|
629
|
-
/**
|
|
630
|
-
* Implementation
|
|
631
|
-
*/
|
|
632
|
-
function animateSubject(subject, keyframes, options, scope) {
|
|
633
|
-
const animations = [];
|
|
634
|
-
if (isSingleValue(subject, keyframes)) {
|
|
635
|
-
animations.push(animateSingleValue(subject, isDOMKeyframes(keyframes)
|
|
636
|
-
? keyframes.default || keyframes
|
|
637
|
-
: keyframes, options ? options.default || options : options));
|
|
638
|
-
}
|
|
639
|
-
else {
|
|
640
|
-
const subjects = resolveSubjects(subject, keyframes, scope);
|
|
641
|
-
const numSubjects = subjects.length;
|
|
642
|
-
invariant(Boolean(numSubjects), "No valid elements provided.", "no-valid-elements");
|
|
643
|
-
for (let i = 0; i < numSubjects; i++) {
|
|
644
|
-
const thisSubject = subjects[i];
|
|
645
|
-
invariant(thisSubject !== null, "You're trying to perform an animation on null. Ensure that selectors are correctly finding elements and refs are correctly hydrated.", "animate-null");
|
|
646
|
-
const createVisualElement = thisSubject instanceof Element
|
|
647
|
-
? createDOMVisualElement
|
|
648
|
-
: createObjectVisualElement;
|
|
649
|
-
if (!visualElementStore.has(thisSubject)) {
|
|
650
|
-
createVisualElement(thisSubject);
|
|
651
|
-
}
|
|
652
|
-
const visualElement = visualElementStore.get(thisSubject);
|
|
653
|
-
const transition = { ...options };
|
|
654
|
-
/**
|
|
655
|
-
* Resolve stagger function if provided.
|
|
656
|
-
*/
|
|
657
|
-
if ("delay" in transition &&
|
|
658
|
-
typeof transition.delay === "function") {
|
|
659
|
-
transition.delay = transition.delay(i, numSubjects);
|
|
660
|
-
}
|
|
661
|
-
animations.push(...animateTarget(visualElement, { ...keyframes, transition }, {}));
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
|
-
return animations;
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
function animateSequence(sequence, options, scope) {
|
|
668
|
-
const animations = [];
|
|
669
|
-
const animationDefinitions = createAnimationsFromSequence(sequence, options, scope, { spring });
|
|
670
|
-
animationDefinitions.forEach(({ keyframes, transition }, subject) => {
|
|
671
|
-
animations.push(...animateSubject(subject, keyframes, transition));
|
|
672
|
-
});
|
|
673
|
-
return animations;
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
function isSequence(value) {
|
|
677
|
-
return Array.isArray(value) && value.some(Array.isArray);
|
|
678
|
-
}
|
|
679
|
-
/**
|
|
680
|
-
* Creates an animation function that is optionally scoped
|
|
681
|
-
* to a specific element.
|
|
682
|
-
*/
|
|
683
|
-
function createScopedAnimate(scope) {
|
|
684
|
-
/**
|
|
685
|
-
* Implementation
|
|
686
|
-
*/
|
|
687
|
-
function scopedAnimate(subjectOrSequence, optionsOrKeyframes, options) {
|
|
688
|
-
let animations = [];
|
|
689
|
-
if (isSequence(subjectOrSequence)) {
|
|
690
|
-
animations = animateSequence(subjectOrSequence, optionsOrKeyframes, scope);
|
|
691
|
-
}
|
|
692
|
-
else {
|
|
693
|
-
animations = animateSubject(subjectOrSequence, optionsOrKeyframes, options, scope);
|
|
694
|
-
}
|
|
695
|
-
const animation = new GroupAnimationWithThen(animations);
|
|
696
|
-
return animation;
|
|
697
|
-
}
|
|
698
|
-
return scopedAnimate;
|
|
699
|
-
}
|
|
700
|
-
const animate = createScopedAnimate();
|
|
701
|
-
|
|
702
|
-
function polygonArea(polygon) {
|
|
703
|
-
var i = -1,
|
|
704
|
-
n = polygon.length,
|
|
705
|
-
a,
|
|
706
|
-
b = polygon[n - 1],
|
|
707
|
-
area = 0;
|
|
708
|
-
|
|
709
|
-
while (++i < n) {
|
|
710
|
-
a = b;
|
|
711
|
-
b = polygon[i];
|
|
712
|
-
area += a[1] * b[0] - a[0] * b[1];
|
|
713
|
-
}
|
|
714
|
-
|
|
715
|
-
return area / 2;
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
function polygonLength(polygon) {
|
|
719
|
-
var i = -1,
|
|
720
|
-
n = polygon.length,
|
|
721
|
-
b = polygon[n - 1],
|
|
722
|
-
xa,
|
|
723
|
-
ya,
|
|
724
|
-
xb = b[0],
|
|
725
|
-
yb = b[1],
|
|
726
|
-
perimeter = 0;
|
|
727
|
-
|
|
728
|
-
while (++i < n) {
|
|
729
|
-
xa = xb;
|
|
730
|
-
ya = yb;
|
|
731
|
-
b = polygon[i];
|
|
732
|
-
xb = b[0];
|
|
733
|
-
yb = b[1];
|
|
734
|
-
xa -= xb;
|
|
735
|
-
ya -= yb;
|
|
736
|
-
perimeter += Math.sqrt(xa * xa + ya * ya);
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
return perimeter;
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
var path_parse;
|
|
743
|
-
var hasRequiredPath_parse;
|
|
744
|
-
|
|
745
|
-
function requirePath_parse () {
|
|
746
|
-
if (hasRequiredPath_parse) return path_parse;
|
|
747
|
-
hasRequiredPath_parse = 1;
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
var paramCounts = { a: 7, c: 6, h: 1, l: 2, m: 2, r: 4, q: 4, s: 4, t: 2, v: 1, z: 0 };
|
|
751
|
-
|
|
752
|
-
var SPECIAL_SPACES = [
|
|
753
|
-
0x1680, 0x180E, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006,
|
|
754
|
-
0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF
|
|
755
|
-
];
|
|
756
|
-
|
|
757
|
-
function isSpace(ch) {
|
|
758
|
-
return (ch === 0x0A) || (ch === 0x0D) || (ch === 0x2028) || (ch === 0x2029) || // Line terminators
|
|
759
|
-
// White spaces
|
|
760
|
-
(ch === 0x20) || (ch === 0x09) || (ch === 0x0B) || (ch === 0x0C) || (ch === 0xA0) ||
|
|
761
|
-
(ch >= 0x1680 && SPECIAL_SPACES.indexOf(ch) >= 0);
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
function isCommand(code) {
|
|
765
|
-
/*eslint-disable no-bitwise*/
|
|
766
|
-
switch (code | 0x20) {
|
|
767
|
-
case 0x6D/* m */:
|
|
768
|
-
case 0x7A/* z */:
|
|
769
|
-
case 0x6C/* l */:
|
|
770
|
-
case 0x68/* h */:
|
|
771
|
-
case 0x76/* v */:
|
|
772
|
-
case 0x63/* c */:
|
|
773
|
-
case 0x73/* s */:
|
|
774
|
-
case 0x71/* q */:
|
|
775
|
-
case 0x74/* t */:
|
|
776
|
-
case 0x61/* a */:
|
|
777
|
-
case 0x72/* r */:
|
|
778
|
-
return true;
|
|
779
|
-
}
|
|
780
|
-
return false;
|
|
781
|
-
}
|
|
782
|
-
|
|
783
|
-
function isArc(code) {
|
|
784
|
-
return (code | 0x20) === 0x61;
|
|
785
|
-
}
|
|
786
|
-
|
|
787
|
-
function isDigit(code) {
|
|
788
|
-
return (code >= 48 && code <= 57); // 0..9
|
|
789
|
-
}
|
|
790
|
-
|
|
791
|
-
function isDigitStart(code) {
|
|
792
|
-
return (code >= 48 && code <= 57) || /* 0..9 */
|
|
793
|
-
code === 0x2B || /* + */
|
|
794
|
-
code === 0x2D || /* - */
|
|
795
|
-
code === 0x2E; /* . */
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
function State(path) {
|
|
800
|
-
this.index = 0;
|
|
801
|
-
this.path = path;
|
|
802
|
-
this.max = path.length;
|
|
803
|
-
this.result = [];
|
|
804
|
-
this.param = 0.0;
|
|
805
|
-
this.err = '';
|
|
806
|
-
this.segmentStart = 0;
|
|
807
|
-
this.data = [];
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
function skipSpaces(state) {
|
|
811
|
-
while (state.index < state.max && isSpace(state.path.charCodeAt(state.index))) {
|
|
812
|
-
state.index++;
|
|
813
|
-
}
|
|
814
|
-
}
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
function scanFlag(state) {
|
|
818
|
-
var ch = state.path.charCodeAt(state.index);
|
|
819
|
-
|
|
820
|
-
if (ch === 0x30/* 0 */) {
|
|
821
|
-
state.param = 0;
|
|
822
|
-
state.index++;
|
|
823
|
-
return;
|
|
824
|
-
}
|
|
825
|
-
|
|
826
|
-
if (ch === 0x31/* 1 */) {
|
|
827
|
-
state.param = 1;
|
|
828
|
-
state.index++;
|
|
829
|
-
return;
|
|
830
|
-
}
|
|
831
|
-
|
|
832
|
-
state.err = 'SvgPath: arc flag can be 0 or 1 only (at pos ' + state.index + ')';
|
|
833
|
-
}
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
function scanParam(state) {
|
|
837
|
-
var start = state.index,
|
|
838
|
-
index = start,
|
|
839
|
-
max = state.max,
|
|
840
|
-
zeroFirst = false,
|
|
841
|
-
hasCeiling = false,
|
|
842
|
-
hasDecimal = false,
|
|
843
|
-
hasDot = false,
|
|
844
|
-
ch;
|
|
845
|
-
|
|
846
|
-
if (index >= max) {
|
|
847
|
-
state.err = 'SvgPath: missed param (at pos ' + index + ')';
|
|
848
|
-
return;
|
|
849
|
-
}
|
|
850
|
-
ch = state.path.charCodeAt(index);
|
|
851
|
-
|
|
852
|
-
if (ch === 0x2B/* + */ || ch === 0x2D/* - */) {
|
|
853
|
-
index++;
|
|
854
|
-
ch = (index < max) ? state.path.charCodeAt(index) : 0;
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
// This logic is shamelessly borrowed from Esprima
|
|
858
|
-
// https://github.com/ariya/esprimas
|
|
859
|
-
//
|
|
860
|
-
if (!isDigit(ch) && ch !== 0x2E/* . */) {
|
|
861
|
-
state.err = 'SvgPath: param should start with 0..9 or `.` (at pos ' + index + ')';
|
|
862
|
-
return;
|
|
863
|
-
}
|
|
864
|
-
|
|
865
|
-
if (ch !== 0x2E/* . */) {
|
|
866
|
-
zeroFirst = (ch === 0x30/* 0 */);
|
|
867
|
-
index++;
|
|
868
|
-
|
|
869
|
-
ch = (index < max) ? state.path.charCodeAt(index) : 0;
|
|
870
|
-
|
|
871
|
-
if (zeroFirst && index < max) {
|
|
872
|
-
// decimal number starts with '0' such as '09' is illegal.
|
|
873
|
-
if (ch && isDigit(ch)) {
|
|
874
|
-
state.err = 'SvgPath: numbers started with `0` such as `09` are illegal (at pos ' + start + ')';
|
|
875
|
-
return;
|
|
876
|
-
}
|
|
877
|
-
}
|
|
878
|
-
|
|
879
|
-
while (index < max && isDigit(state.path.charCodeAt(index))) {
|
|
880
|
-
index++;
|
|
881
|
-
hasCeiling = true;
|
|
882
|
-
}
|
|
883
|
-
ch = (index < max) ? state.path.charCodeAt(index) : 0;
|
|
884
|
-
}
|
|
885
|
-
|
|
886
|
-
if (ch === 0x2E/* . */) {
|
|
887
|
-
hasDot = true;
|
|
888
|
-
index++;
|
|
889
|
-
while (isDigit(state.path.charCodeAt(index))) {
|
|
890
|
-
index++;
|
|
891
|
-
hasDecimal = true;
|
|
892
|
-
}
|
|
893
|
-
ch = (index < max) ? state.path.charCodeAt(index) : 0;
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
if (ch === 0x65/* e */ || ch === 0x45/* E */) {
|
|
897
|
-
if (hasDot && !hasCeiling && !hasDecimal) {
|
|
898
|
-
state.err = 'SvgPath: invalid float exponent (at pos ' + index + ')';
|
|
899
|
-
return;
|
|
900
|
-
}
|
|
901
|
-
|
|
902
|
-
index++;
|
|
903
|
-
|
|
904
|
-
ch = (index < max) ? state.path.charCodeAt(index) : 0;
|
|
905
|
-
if (ch === 0x2B/* + */ || ch === 0x2D/* - */) {
|
|
906
|
-
index++;
|
|
907
|
-
}
|
|
908
|
-
if (index < max && isDigit(state.path.charCodeAt(index))) {
|
|
909
|
-
while (index < max && isDigit(state.path.charCodeAt(index))) {
|
|
910
|
-
index++;
|
|
911
|
-
}
|
|
912
|
-
} else {
|
|
913
|
-
state.err = 'SvgPath: invalid float exponent (at pos ' + index + ')';
|
|
914
|
-
return;
|
|
915
|
-
}
|
|
916
|
-
}
|
|
917
|
-
|
|
918
|
-
state.index = index;
|
|
919
|
-
state.param = parseFloat(state.path.slice(start, index)) + 0.0;
|
|
920
|
-
}
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
function finalizeSegment(state) {
|
|
924
|
-
var cmd, cmdLC;
|
|
925
|
-
|
|
926
|
-
// Process duplicated commands (without comand name)
|
|
927
|
-
|
|
928
|
-
// This logic is shamelessly borrowed from Raphael
|
|
929
|
-
// https://github.com/DmitryBaranovskiy/raphael/
|
|
930
|
-
//
|
|
931
|
-
cmd = state.path[state.segmentStart];
|
|
932
|
-
cmdLC = cmd.toLowerCase();
|
|
933
|
-
|
|
934
|
-
var params = state.data;
|
|
935
|
-
|
|
936
|
-
if (cmdLC === 'm' && params.length > 2) {
|
|
937
|
-
state.result.push([ cmd, params[0], params[1] ]);
|
|
938
|
-
params = params.slice(2);
|
|
939
|
-
cmdLC = 'l';
|
|
940
|
-
cmd = (cmd === 'm') ? 'l' : 'L';
|
|
941
|
-
}
|
|
942
|
-
|
|
943
|
-
if (cmdLC === 'r') {
|
|
944
|
-
state.result.push([ cmd ].concat(params));
|
|
945
|
-
} else {
|
|
946
|
-
|
|
947
|
-
while (params.length >= paramCounts[cmdLC]) {
|
|
948
|
-
state.result.push([ cmd ].concat(params.splice(0, paramCounts[cmdLC])));
|
|
949
|
-
if (!paramCounts[cmdLC]) {
|
|
950
|
-
break;
|
|
951
|
-
}
|
|
952
|
-
}
|
|
953
|
-
}
|
|
954
|
-
}
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
function scanSegment(state) {
|
|
958
|
-
var max = state.max,
|
|
959
|
-
cmdCode, is_arc, comma_found, need_params, i;
|
|
960
|
-
|
|
961
|
-
state.segmentStart = state.index;
|
|
962
|
-
cmdCode = state.path.charCodeAt(state.index);
|
|
963
|
-
is_arc = isArc(cmdCode);
|
|
964
|
-
|
|
965
|
-
if (!isCommand(cmdCode)) {
|
|
966
|
-
state.err = 'SvgPath: bad command ' + state.path[state.index] + ' (at pos ' + state.index + ')';
|
|
967
|
-
return;
|
|
968
|
-
}
|
|
969
|
-
|
|
970
|
-
need_params = paramCounts[state.path[state.index].toLowerCase()];
|
|
971
|
-
|
|
972
|
-
state.index++;
|
|
973
|
-
skipSpaces(state);
|
|
974
|
-
|
|
975
|
-
state.data = [];
|
|
976
|
-
|
|
977
|
-
if (!need_params) {
|
|
978
|
-
// Z
|
|
979
|
-
finalizeSegment(state);
|
|
980
|
-
return;
|
|
981
|
-
}
|
|
982
|
-
|
|
983
|
-
comma_found = false;
|
|
984
|
-
|
|
985
|
-
for (;;) {
|
|
986
|
-
for (i = need_params; i > 0; i--) {
|
|
987
|
-
if (is_arc && (i === 3 || i === 4)) scanFlag(state);
|
|
988
|
-
else scanParam(state);
|
|
989
|
-
|
|
990
|
-
if (state.err.length) {
|
|
991
|
-
finalizeSegment(state);
|
|
992
|
-
return;
|
|
993
|
-
}
|
|
994
|
-
state.data.push(state.param);
|
|
995
|
-
|
|
996
|
-
skipSpaces(state);
|
|
997
|
-
comma_found = false;
|
|
998
|
-
|
|
999
|
-
if (state.index < max && state.path.charCodeAt(state.index) === 0x2C/* , */) {
|
|
1000
|
-
state.index++;
|
|
1001
|
-
skipSpaces(state);
|
|
1002
|
-
comma_found = true;
|
|
1003
|
-
}
|
|
1004
|
-
}
|
|
1005
|
-
|
|
1006
|
-
// after ',' param is mandatory
|
|
1007
|
-
if (comma_found) {
|
|
1008
|
-
continue;
|
|
1009
|
-
}
|
|
1010
|
-
|
|
1011
|
-
if (state.index >= state.max) {
|
|
1012
|
-
break;
|
|
1013
|
-
}
|
|
1014
|
-
|
|
1015
|
-
// Stop on next segment
|
|
1016
|
-
if (!isDigitStart(state.path.charCodeAt(state.index))) {
|
|
1017
|
-
break;
|
|
1018
|
-
}
|
|
1019
|
-
}
|
|
1020
|
-
|
|
1021
|
-
finalizeSegment(state);
|
|
1022
|
-
}
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
/* Returns array of segments:
|
|
1026
|
-
*
|
|
1027
|
-
* [
|
|
1028
|
-
* [ command, coord1, coord2, ... ]
|
|
1029
|
-
* ]
|
|
1030
|
-
*/
|
|
1031
|
-
path_parse = function pathParse(svgPath) {
|
|
1032
|
-
var state = new State(svgPath);
|
|
1033
|
-
var max = state.max;
|
|
1034
|
-
|
|
1035
|
-
skipSpaces(state);
|
|
1036
|
-
|
|
1037
|
-
while (state.index < max && !state.err.length) {
|
|
1038
|
-
scanSegment(state);
|
|
1039
|
-
}
|
|
1040
|
-
|
|
1041
|
-
if (state.result.length) {
|
|
1042
|
-
if ('mM'.indexOf(state.result[0][0]) < 0) {
|
|
1043
|
-
state.err = 'SvgPath: string should start with `M` or `m`';
|
|
1044
|
-
state.result = [];
|
|
1045
|
-
} else {
|
|
1046
|
-
state.result[0][0] = 'M';
|
|
1047
|
-
}
|
|
1048
|
-
}
|
|
1049
|
-
|
|
1050
|
-
return {
|
|
1051
|
-
err: state.err,
|
|
1052
|
-
segments: state.result
|
|
1053
|
-
};
|
|
1054
|
-
};
|
|
1055
|
-
return path_parse;
|
|
1056
|
-
}
|
|
1057
|
-
|
|
1058
|
-
var matrix;
|
|
1059
|
-
var hasRequiredMatrix;
|
|
1060
|
-
|
|
1061
|
-
function requireMatrix () {
|
|
1062
|
-
if (hasRequiredMatrix) return matrix;
|
|
1063
|
-
hasRequiredMatrix = 1;
|
|
1064
|
-
|
|
1065
|
-
// combine 2 matrixes
|
|
1066
|
-
// m1, m2 - [a, b, c, d, e, g]
|
|
1067
|
-
//
|
|
1068
|
-
function combine(m1, m2) {
|
|
1069
|
-
return [
|
|
1070
|
-
m1[0] * m2[0] + m1[2] * m2[1],
|
|
1071
|
-
m1[1] * m2[0] + m1[3] * m2[1],
|
|
1072
|
-
m1[0] * m2[2] + m1[2] * m2[3],
|
|
1073
|
-
m1[1] * m2[2] + m1[3] * m2[3],
|
|
1074
|
-
m1[0] * m2[4] + m1[2] * m2[5] + m1[4],
|
|
1075
|
-
m1[1] * m2[4] + m1[3] * m2[5] + m1[5]
|
|
1076
|
-
];
|
|
1077
|
-
}
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
function Matrix() {
|
|
1081
|
-
if (!(this instanceof Matrix)) { return new Matrix(); }
|
|
1082
|
-
this.queue = []; // list of matrixes to apply
|
|
1083
|
-
this.cache = null; // combined matrix cache
|
|
1084
|
-
}
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
Matrix.prototype.matrix = function (m) {
|
|
1088
|
-
if (m[0] === 1 && m[1] === 0 && m[2] === 0 && m[3] === 1 && m[4] === 0 && m[5] === 0) {
|
|
1089
|
-
return this;
|
|
1090
|
-
}
|
|
1091
|
-
this.cache = null;
|
|
1092
|
-
this.queue.push(m);
|
|
1093
|
-
return this;
|
|
1094
|
-
};
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
Matrix.prototype.translate = function (tx, ty) {
|
|
1098
|
-
if (tx !== 0 || ty !== 0) {
|
|
1099
|
-
this.cache = null;
|
|
1100
|
-
this.queue.push([ 1, 0, 0, 1, tx, ty ]);
|
|
1101
|
-
}
|
|
1102
|
-
return this;
|
|
1103
|
-
};
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
Matrix.prototype.scale = function (sx, sy) {
|
|
1107
|
-
if (sx !== 1 || sy !== 1) {
|
|
1108
|
-
this.cache = null;
|
|
1109
|
-
this.queue.push([ sx, 0, 0, sy, 0, 0 ]);
|
|
1110
|
-
}
|
|
1111
|
-
return this;
|
|
1112
|
-
};
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
Matrix.prototype.rotate = function (angle, rx, ry) {
|
|
1116
|
-
var rad, cos, sin;
|
|
1117
|
-
|
|
1118
|
-
if (angle !== 0) {
|
|
1119
|
-
this.translate(rx, ry);
|
|
1120
|
-
|
|
1121
|
-
rad = angle * Math.PI / 180;
|
|
1122
|
-
cos = Math.cos(rad);
|
|
1123
|
-
sin = Math.sin(rad);
|
|
1124
|
-
|
|
1125
|
-
this.queue.push([ cos, sin, -sin, cos, 0, 0 ]);
|
|
1126
|
-
this.cache = null;
|
|
1127
|
-
|
|
1128
|
-
this.translate(-rx, -ry);
|
|
1129
|
-
}
|
|
1130
|
-
return this;
|
|
1131
|
-
};
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
Matrix.prototype.skewX = function (angle) {
|
|
1135
|
-
if (angle !== 0) {
|
|
1136
|
-
this.cache = null;
|
|
1137
|
-
this.queue.push([ 1, 0, Math.tan(angle * Math.PI / 180), 1, 0, 0 ]);
|
|
1138
|
-
}
|
|
1139
|
-
return this;
|
|
1140
|
-
};
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
Matrix.prototype.skewY = function (angle) {
|
|
1144
|
-
if (angle !== 0) {
|
|
1145
|
-
this.cache = null;
|
|
1146
|
-
this.queue.push([ 1, Math.tan(angle * Math.PI / 180), 0, 1, 0, 0 ]);
|
|
1147
|
-
}
|
|
1148
|
-
return this;
|
|
1149
|
-
};
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
// Flatten queue
|
|
1153
|
-
//
|
|
1154
|
-
Matrix.prototype.toArray = function () {
|
|
1155
|
-
if (this.cache) {
|
|
1156
|
-
return this.cache;
|
|
1157
|
-
}
|
|
1158
|
-
|
|
1159
|
-
if (!this.queue.length) {
|
|
1160
|
-
this.cache = [ 1, 0, 0, 1, 0, 0 ];
|
|
1161
|
-
return this.cache;
|
|
1162
|
-
}
|
|
1163
|
-
|
|
1164
|
-
this.cache = this.queue[0];
|
|
1165
|
-
|
|
1166
|
-
if (this.queue.length === 1) {
|
|
1167
|
-
return this.cache;
|
|
1168
|
-
}
|
|
1169
|
-
|
|
1170
|
-
for (var i = 1; i < this.queue.length; i++) {
|
|
1171
|
-
this.cache = combine(this.cache, this.queue[i]);
|
|
1172
|
-
}
|
|
1173
|
-
|
|
1174
|
-
return this.cache;
|
|
1175
|
-
};
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
// Apply list of matrixes to (x,y) point.
|
|
1179
|
-
// If `isRelative` set, `translate` component of matrix will be skipped
|
|
1180
|
-
//
|
|
1181
|
-
Matrix.prototype.calc = function (x, y, isRelative) {
|
|
1182
|
-
var m;
|
|
1183
|
-
|
|
1184
|
-
// Don't change point on empty transforms queue
|
|
1185
|
-
if (!this.queue.length) { return [ x, y ]; }
|
|
1186
|
-
|
|
1187
|
-
// Calculate final matrix, if not exists
|
|
1188
|
-
//
|
|
1189
|
-
// NB. if you deside to apply transforms to point one-by-one,
|
|
1190
|
-
// they should be taken in reverse order
|
|
1191
|
-
|
|
1192
|
-
if (!this.cache) {
|
|
1193
|
-
this.cache = this.toArray();
|
|
1194
|
-
}
|
|
1195
|
-
|
|
1196
|
-
m = this.cache;
|
|
1197
|
-
|
|
1198
|
-
// Apply matrix to point
|
|
1199
|
-
return [
|
|
1200
|
-
x * m[0] + y * m[2] + (isRelative ? 0 : m[4]),
|
|
1201
|
-
x * m[1] + y * m[3] + (isRelative ? 0 : m[5])
|
|
1202
|
-
];
|
|
1203
|
-
};
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
matrix = Matrix;
|
|
1207
|
-
return matrix;
|
|
1208
|
-
}
|
|
1209
|
-
|
|
1210
|
-
var transform_parse;
|
|
1211
|
-
var hasRequiredTransform_parse;
|
|
1212
|
-
|
|
1213
|
-
function requireTransform_parse () {
|
|
1214
|
-
if (hasRequiredTransform_parse) return transform_parse;
|
|
1215
|
-
hasRequiredTransform_parse = 1;
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
var Matrix = requireMatrix();
|
|
1219
|
-
|
|
1220
|
-
var operations = {
|
|
1221
|
-
matrix: true,
|
|
1222
|
-
scale: true,
|
|
1223
|
-
rotate: true,
|
|
1224
|
-
translate: true,
|
|
1225
|
-
skewX: true,
|
|
1226
|
-
skewY: true
|
|
1227
|
-
};
|
|
1228
|
-
|
|
1229
|
-
var CMD_SPLIT_RE = /\s*(matrix|translate|scale|rotate|skewX|skewY)\s*\(\s*(.+?)\s*\)[\s,]*/;
|
|
1230
|
-
var PARAMS_SPLIT_RE = /[\s,]+/;
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
transform_parse = function transformParse(transformString) {
|
|
1234
|
-
var matrix = new Matrix();
|
|
1235
|
-
var cmd, params;
|
|
1236
|
-
|
|
1237
|
-
// Split value into ['', 'translate', '10 50', '', 'scale', '2', '', 'rotate', '-45', '']
|
|
1238
|
-
transformString.split(CMD_SPLIT_RE).forEach(function (item) {
|
|
1239
|
-
|
|
1240
|
-
// Skip empty elements
|
|
1241
|
-
if (!item.length) { return; }
|
|
1242
|
-
|
|
1243
|
-
// remember operation
|
|
1244
|
-
if (typeof operations[item] !== 'undefined') {
|
|
1245
|
-
cmd = item;
|
|
1246
|
-
return;
|
|
1247
|
-
}
|
|
1248
|
-
|
|
1249
|
-
// extract params & att operation to matrix
|
|
1250
|
-
params = item.split(PARAMS_SPLIT_RE).map(function (i) {
|
|
1251
|
-
return +i || 0;
|
|
1252
|
-
});
|
|
1253
|
-
|
|
1254
|
-
// If params count is not correct - ignore command
|
|
1255
|
-
switch (cmd) {
|
|
1256
|
-
case 'matrix':
|
|
1257
|
-
if (params.length === 6) {
|
|
1258
|
-
matrix.matrix(params);
|
|
1259
|
-
}
|
|
1260
|
-
return;
|
|
1261
|
-
|
|
1262
|
-
case 'scale':
|
|
1263
|
-
if (params.length === 1) {
|
|
1264
|
-
matrix.scale(params[0], params[0]);
|
|
1265
|
-
} else if (params.length === 2) {
|
|
1266
|
-
matrix.scale(params[0], params[1]);
|
|
1267
|
-
}
|
|
1268
|
-
return;
|
|
1269
|
-
|
|
1270
|
-
case 'rotate':
|
|
1271
|
-
if (params.length === 1) {
|
|
1272
|
-
matrix.rotate(params[0], 0, 0);
|
|
1273
|
-
} else if (params.length === 3) {
|
|
1274
|
-
matrix.rotate(params[0], params[1], params[2]);
|
|
1275
|
-
}
|
|
1276
|
-
return;
|
|
1277
|
-
|
|
1278
|
-
case 'translate':
|
|
1279
|
-
if (params.length === 1) {
|
|
1280
|
-
matrix.translate(params[0], 0);
|
|
1281
|
-
} else if (params.length === 2) {
|
|
1282
|
-
matrix.translate(params[0], params[1]);
|
|
1283
|
-
}
|
|
1284
|
-
return;
|
|
1285
|
-
|
|
1286
|
-
case 'skewX':
|
|
1287
|
-
if (params.length === 1) {
|
|
1288
|
-
matrix.skewX(params[0]);
|
|
1289
|
-
}
|
|
1290
|
-
return;
|
|
1291
|
-
|
|
1292
|
-
case 'skewY':
|
|
1293
|
-
if (params.length === 1) {
|
|
1294
|
-
matrix.skewY(params[0]);
|
|
1295
|
-
}
|
|
1296
|
-
return;
|
|
1297
|
-
}
|
|
1298
|
-
});
|
|
1299
|
-
|
|
1300
|
-
return matrix;
|
|
1301
|
-
};
|
|
1302
|
-
return transform_parse;
|
|
1303
|
-
}
|
|
1304
|
-
|
|
1305
|
-
var a2c$1;
|
|
1306
|
-
var hasRequiredA2c;
|
|
1307
|
-
|
|
1308
|
-
function requireA2c () {
|
|
1309
|
-
if (hasRequiredA2c) return a2c$1;
|
|
1310
|
-
hasRequiredA2c = 1;
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
var TAU = Math.PI * 2;
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
/* eslint-disable space-infix-ops */
|
|
1317
|
-
|
|
1318
|
-
// Calculate an angle between two unit vectors
|
|
1319
|
-
//
|
|
1320
|
-
// Since we measure angle between radii of circular arcs,
|
|
1321
|
-
// we can use simplified math (without length normalization)
|
|
1322
|
-
//
|
|
1323
|
-
function unit_vector_angle(ux, uy, vx, vy) {
|
|
1324
|
-
var sign = (ux * vy - uy * vx < 0) ? -1 : 1;
|
|
1325
|
-
var dot = ux * vx + uy * vy;
|
|
1326
|
-
|
|
1327
|
-
// Add this to work with arbitrary vectors:
|
|
1328
|
-
// dot /= Math.sqrt(ux * ux + uy * uy) * Math.sqrt(vx * vx + vy * vy);
|
|
1329
|
-
|
|
1330
|
-
// rounding errors, e.g. -1.0000000000000002 can screw up this
|
|
1331
|
-
if (dot > 1.0) { dot = 1.0; }
|
|
1332
|
-
if (dot < -1) { dot = -1; }
|
|
1333
|
-
|
|
1334
|
-
return sign * Math.acos(dot);
|
|
1335
|
-
}
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
// Convert from endpoint to center parameterization,
|
|
1339
|
-
// see http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
|
|
1340
|
-
//
|
|
1341
|
-
// Return [cx, cy, theta1, delta_theta]
|
|
1342
|
-
//
|
|
1343
|
-
function get_arc_center(x1, y1, x2, y2, fa, fs, rx, ry, sin_phi, cos_phi) {
|
|
1344
|
-
// Step 1.
|
|
1345
|
-
//
|
|
1346
|
-
// Moving an ellipse so origin will be the middlepoint between our two
|
|
1347
|
-
// points. After that, rotate it to line up ellipse axes with coordinate
|
|
1348
|
-
// axes.
|
|
1349
|
-
//
|
|
1350
|
-
var x1p = cos_phi*(x1-x2)/2 + sin_phi*(y1-y2)/2;
|
|
1351
|
-
var y1p = -sin_phi*(x1-x2)/2 + cos_phi*(y1-y2)/2;
|
|
1352
|
-
|
|
1353
|
-
var rx_sq = rx * rx;
|
|
1354
|
-
var ry_sq = ry * ry;
|
|
1355
|
-
var x1p_sq = x1p * x1p;
|
|
1356
|
-
var y1p_sq = y1p * y1p;
|
|
1357
|
-
|
|
1358
|
-
// Step 2.
|
|
1359
|
-
//
|
|
1360
|
-
// Compute coordinates of the centre of this ellipse (cx', cy')
|
|
1361
|
-
// in the new coordinate system.
|
|
1362
|
-
//
|
|
1363
|
-
var radicant = (rx_sq * ry_sq) - (rx_sq * y1p_sq) - (ry_sq * x1p_sq);
|
|
1364
|
-
|
|
1365
|
-
if (radicant < 0) {
|
|
1366
|
-
// due to rounding errors it might be e.g. -1.3877787807814457e-17
|
|
1367
|
-
radicant = 0;
|
|
1368
|
-
}
|
|
1369
|
-
|
|
1370
|
-
radicant /= (rx_sq * y1p_sq) + (ry_sq * x1p_sq);
|
|
1371
|
-
radicant = Math.sqrt(radicant) * (fa === fs ? -1 : 1);
|
|
1372
|
-
|
|
1373
|
-
var cxp = radicant * rx/ry * y1p;
|
|
1374
|
-
var cyp = radicant * -ry/rx * x1p;
|
|
1375
|
-
|
|
1376
|
-
// Step 3.
|
|
1377
|
-
//
|
|
1378
|
-
// Transform back to get centre coordinates (cx, cy) in the original
|
|
1379
|
-
// coordinate system.
|
|
1380
|
-
//
|
|
1381
|
-
var cx = cos_phi*cxp - sin_phi*cyp + (x1+x2)/2;
|
|
1382
|
-
var cy = sin_phi*cxp + cos_phi*cyp + (y1+y2)/2;
|
|
1383
|
-
|
|
1384
|
-
// Step 4.
|
|
1385
|
-
//
|
|
1386
|
-
// Compute angles (theta1, delta_theta).
|
|
1387
|
-
//
|
|
1388
|
-
var v1x = (x1p - cxp) / rx;
|
|
1389
|
-
var v1y = (y1p - cyp) / ry;
|
|
1390
|
-
var v2x = (-x1p - cxp) / rx;
|
|
1391
|
-
var v2y = (-y1p - cyp) / ry;
|
|
1392
|
-
|
|
1393
|
-
var theta1 = unit_vector_angle(1, 0, v1x, v1y);
|
|
1394
|
-
var delta_theta = unit_vector_angle(v1x, v1y, v2x, v2y);
|
|
1395
|
-
|
|
1396
|
-
if (fs === 0 && delta_theta > 0) {
|
|
1397
|
-
delta_theta -= TAU;
|
|
1398
|
-
}
|
|
1399
|
-
if (fs === 1 && delta_theta < 0) {
|
|
1400
|
-
delta_theta += TAU;
|
|
1401
|
-
}
|
|
1402
|
-
|
|
1403
|
-
return [ cx, cy, theta1, delta_theta ];
|
|
1404
|
-
}
|
|
1405
|
-
|
|
1406
|
-
//
|
|
1407
|
-
// Approximate one unit arc segment with bézier curves,
|
|
1408
|
-
// see http://math.stackexchange.com/questions/873224
|
|
1409
|
-
//
|
|
1410
|
-
function approximate_unit_arc(theta1, delta_theta) {
|
|
1411
|
-
var alpha = 4/3 * Math.tan(delta_theta/4);
|
|
1412
|
-
|
|
1413
|
-
var x1 = Math.cos(theta1);
|
|
1414
|
-
var y1 = Math.sin(theta1);
|
|
1415
|
-
var x2 = Math.cos(theta1 + delta_theta);
|
|
1416
|
-
var y2 = Math.sin(theta1 + delta_theta);
|
|
1417
|
-
|
|
1418
|
-
return [ x1, y1, x1 - y1*alpha, y1 + x1*alpha, x2 + y2*alpha, y2 - x2*alpha, x2, y2 ];
|
|
1419
|
-
}
|
|
1420
|
-
|
|
1421
|
-
a2c$1 = function a2c(x1, y1, x2, y2, fa, fs, rx, ry, phi) {
|
|
1422
|
-
var sin_phi = Math.sin(phi * TAU / 360);
|
|
1423
|
-
var cos_phi = Math.cos(phi * TAU / 360);
|
|
1424
|
-
|
|
1425
|
-
// Make sure radii are valid
|
|
1426
|
-
//
|
|
1427
|
-
var x1p = cos_phi*(x1-x2)/2 + sin_phi*(y1-y2)/2;
|
|
1428
|
-
var y1p = -sin_phi*(x1-x2)/2 + cos_phi*(y1-y2)/2;
|
|
1429
|
-
|
|
1430
|
-
if (x1p === 0 && y1p === 0) {
|
|
1431
|
-
// we're asked to draw line to itself
|
|
1432
|
-
return [];
|
|
1433
|
-
}
|
|
1434
|
-
|
|
1435
|
-
if (rx === 0 || ry === 0) {
|
|
1436
|
-
// one of the radii is zero
|
|
1437
|
-
return [];
|
|
1438
|
-
}
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
// Compensate out-of-range radii
|
|
1442
|
-
//
|
|
1443
|
-
rx = Math.abs(rx);
|
|
1444
|
-
ry = Math.abs(ry);
|
|
1445
|
-
|
|
1446
|
-
var lambda = (x1p * x1p) / (rx * rx) + (y1p * y1p) / (ry * ry);
|
|
1447
|
-
if (lambda > 1) {
|
|
1448
|
-
rx *= Math.sqrt(lambda);
|
|
1449
|
-
ry *= Math.sqrt(lambda);
|
|
1450
|
-
}
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
// Get center parameters (cx, cy, theta1, delta_theta)
|
|
1454
|
-
//
|
|
1455
|
-
var cc = get_arc_center(x1, y1, x2, y2, fa, fs, rx, ry, sin_phi, cos_phi);
|
|
1456
|
-
|
|
1457
|
-
var result = [];
|
|
1458
|
-
var theta1 = cc[2];
|
|
1459
|
-
var delta_theta = cc[3];
|
|
1460
|
-
|
|
1461
|
-
// Split an arc to multiple segments, so each segment
|
|
1462
|
-
// will be less than τ/4 (= 90°)
|
|
1463
|
-
//
|
|
1464
|
-
var segments = Math.max(Math.ceil(Math.abs(delta_theta) / (TAU / 4)), 1);
|
|
1465
|
-
delta_theta /= segments;
|
|
1466
|
-
|
|
1467
|
-
for (var i = 0; i < segments; i++) {
|
|
1468
|
-
result.push(approximate_unit_arc(theta1, delta_theta));
|
|
1469
|
-
theta1 += delta_theta;
|
|
1470
|
-
}
|
|
1471
|
-
|
|
1472
|
-
// We have a bezier approximation of a unit circle,
|
|
1473
|
-
// now need to transform back to the original ellipse
|
|
1474
|
-
//
|
|
1475
|
-
return result.map(function (curve) {
|
|
1476
|
-
for (var i = 0; i < curve.length; i += 2) {
|
|
1477
|
-
var x = curve[i + 0];
|
|
1478
|
-
var y = curve[i + 1];
|
|
1479
|
-
|
|
1480
|
-
// scale
|
|
1481
|
-
x *= rx;
|
|
1482
|
-
y *= ry;
|
|
1483
|
-
|
|
1484
|
-
// rotate
|
|
1485
|
-
var xp = cos_phi*x - sin_phi*y;
|
|
1486
|
-
var yp = sin_phi*x + cos_phi*y;
|
|
1487
|
-
|
|
1488
|
-
// translate
|
|
1489
|
-
curve[i + 0] = xp + cc[0];
|
|
1490
|
-
curve[i + 1] = yp + cc[1];
|
|
1491
|
-
}
|
|
1492
|
-
|
|
1493
|
-
return curve;
|
|
1494
|
-
});
|
|
1495
|
-
};
|
|
1496
|
-
return a2c$1;
|
|
1497
|
-
}
|
|
1498
|
-
|
|
1499
|
-
var ellipse;
|
|
1500
|
-
var hasRequiredEllipse;
|
|
1501
|
-
|
|
1502
|
-
function requireEllipse () {
|
|
1503
|
-
if (hasRequiredEllipse) return ellipse;
|
|
1504
|
-
hasRequiredEllipse = 1;
|
|
1505
|
-
|
|
1506
|
-
/* eslint-disable space-infix-ops */
|
|
1507
|
-
|
|
1508
|
-
// The precision used to consider an ellipse as a circle
|
|
1509
|
-
//
|
|
1510
|
-
var epsilon = 0.0000000001;
|
|
1511
|
-
|
|
1512
|
-
// To convert degree in radians
|
|
1513
|
-
//
|
|
1514
|
-
var torad = Math.PI / 180;
|
|
1515
|
-
|
|
1516
|
-
// Class constructor :
|
|
1517
|
-
// an ellipse centred at 0 with radii rx,ry and x - axis - angle ax.
|
|
1518
|
-
//
|
|
1519
|
-
function Ellipse(rx, ry, ax) {
|
|
1520
|
-
if (!(this instanceof Ellipse)) { return new Ellipse(rx, ry, ax); }
|
|
1521
|
-
this.rx = rx;
|
|
1522
|
-
this.ry = ry;
|
|
1523
|
-
this.ax = ax;
|
|
1524
|
-
}
|
|
1525
|
-
|
|
1526
|
-
// Apply a linear transform m to the ellipse
|
|
1527
|
-
// m is an array representing a matrix :
|
|
1528
|
-
// - -
|
|
1529
|
-
// | m[0] m[2] |
|
|
1530
|
-
// | m[1] m[3] |
|
|
1531
|
-
// - -
|
|
1532
|
-
//
|
|
1533
|
-
Ellipse.prototype.transform = function (m) {
|
|
1534
|
-
// We consider the current ellipse as image of the unit circle
|
|
1535
|
-
// by first scale(rx,ry) and then rotate(ax) ...
|
|
1536
|
-
// So we apply ma = m x rotate(ax) x scale(rx,ry) to the unit circle.
|
|
1537
|
-
var c = Math.cos(this.ax * torad), s = Math.sin(this.ax * torad);
|
|
1538
|
-
var ma = [
|
|
1539
|
-
this.rx * (m[0]*c + m[2]*s),
|
|
1540
|
-
this.rx * (m[1]*c + m[3]*s),
|
|
1541
|
-
this.ry * (-m[0]*s + m[2]*c),
|
|
1542
|
-
this.ry * (-m[1]*s + m[3]*c)
|
|
1543
|
-
];
|
|
1544
|
-
|
|
1545
|
-
// ma * transpose(ma) = [ J L ]
|
|
1546
|
-
// [ L K ]
|
|
1547
|
-
// L is calculated later (if the image is not a circle)
|
|
1548
|
-
var J = ma[0]*ma[0] + ma[2]*ma[2],
|
|
1549
|
-
K = ma[1]*ma[1] + ma[3]*ma[3];
|
|
1550
|
-
|
|
1551
|
-
// the discriminant of the characteristic polynomial of ma * transpose(ma)
|
|
1552
|
-
var D = ((ma[0]-ma[3])*(ma[0]-ma[3]) + (ma[2]+ma[1])*(ma[2]+ma[1])) *
|
|
1553
|
-
((ma[0]+ma[3])*(ma[0]+ma[3]) + (ma[2]-ma[1])*(ma[2]-ma[1]));
|
|
1554
|
-
|
|
1555
|
-
// the "mean eigenvalue"
|
|
1556
|
-
var JK = (J + K) / 2;
|
|
1557
|
-
|
|
1558
|
-
// check if the image is (almost) a circle
|
|
1559
|
-
if (D < epsilon * JK) {
|
|
1560
|
-
// if it is
|
|
1561
|
-
this.rx = this.ry = Math.sqrt(JK);
|
|
1562
|
-
this.ax = 0;
|
|
1563
|
-
return this;
|
|
1564
|
-
}
|
|
1565
|
-
|
|
1566
|
-
// if it is not a circle
|
|
1567
|
-
var L = ma[0]*ma[1] + ma[2]*ma[3];
|
|
1568
|
-
|
|
1569
|
-
D = Math.sqrt(D);
|
|
1570
|
-
|
|
1571
|
-
// {l1,l2} = the two eigen values of ma * transpose(ma)
|
|
1572
|
-
var l1 = JK + D/2,
|
|
1573
|
-
l2 = JK - D/2;
|
|
1574
|
-
// the x - axis - rotation angle is the argument of the l1 - eigenvector
|
|
1575
|
-
/*eslint-disable indent*/
|
|
1576
|
-
this.ax = (Math.abs(L) < epsilon && Math.abs(l1 - K) < epsilon) ?
|
|
1577
|
-
90
|
|
1578
|
-
:
|
|
1579
|
-
Math.atan(Math.abs(L) > Math.abs(l1 - K) ?
|
|
1580
|
-
(l1 - J) / L
|
|
1581
|
-
:
|
|
1582
|
-
L / (l1 - K)
|
|
1583
|
-
) * 180 / Math.PI;
|
|
1584
|
-
/*eslint-enable indent*/
|
|
1585
|
-
|
|
1586
|
-
// if ax > 0 => rx = sqrt(l1), ry = sqrt(l2), else exchange axes and ax += 90
|
|
1587
|
-
if (this.ax >= 0) {
|
|
1588
|
-
// if ax in [0,90]
|
|
1589
|
-
this.rx = Math.sqrt(l1);
|
|
1590
|
-
this.ry = Math.sqrt(l2);
|
|
1591
|
-
} else {
|
|
1592
|
-
// if ax in ]-90,0[ => exchange axes
|
|
1593
|
-
this.ax += 90;
|
|
1594
|
-
this.rx = Math.sqrt(l2);
|
|
1595
|
-
this.ry = Math.sqrt(l1);
|
|
1596
|
-
}
|
|
1597
|
-
|
|
1598
|
-
return this;
|
|
1599
|
-
};
|
|
1600
|
-
|
|
1601
|
-
// Check if the ellipse is (almost) degenerate, i.e. rx = 0 or ry = 0
|
|
1602
|
-
//
|
|
1603
|
-
Ellipse.prototype.isDegenerate = function () {
|
|
1604
|
-
return (this.rx < epsilon * this.ry || this.ry < epsilon * this.rx);
|
|
1605
|
-
};
|
|
1606
|
-
|
|
1607
|
-
ellipse = Ellipse;
|
|
1608
|
-
return ellipse;
|
|
1609
|
-
}
|
|
1610
|
-
|
|
1611
|
-
var svgpath$1;
|
|
1612
|
-
var hasRequiredSvgpath$1;
|
|
1613
|
-
|
|
1614
|
-
function requireSvgpath$1 () {
|
|
1615
|
-
if (hasRequiredSvgpath$1) return svgpath$1;
|
|
1616
|
-
hasRequiredSvgpath$1 = 1;
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
var pathParse = requirePath_parse();
|
|
1620
|
-
var transformParse = requireTransform_parse();
|
|
1621
|
-
var matrix = requireMatrix();
|
|
1622
|
-
var a2c = requireA2c();
|
|
1623
|
-
var ellipse = requireEllipse();
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
// Class constructor
|
|
1627
|
-
//
|
|
1628
|
-
function SvgPath(path) {
|
|
1629
|
-
if (!(this instanceof SvgPath)) { return new SvgPath(path); }
|
|
1630
|
-
|
|
1631
|
-
var pstate = pathParse(path);
|
|
1632
|
-
|
|
1633
|
-
// Array of path segments.
|
|
1634
|
-
// Each segment is array [command, param1, param2, ...]
|
|
1635
|
-
this.segments = pstate.segments;
|
|
1636
|
-
|
|
1637
|
-
// Error message on parse error.
|
|
1638
|
-
this.err = pstate.err;
|
|
1639
|
-
|
|
1640
|
-
// Transforms stack for lazy evaluation
|
|
1641
|
-
this.__stack = [];
|
|
1642
|
-
}
|
|
1643
|
-
|
|
1644
|
-
SvgPath.from = function (src) {
|
|
1645
|
-
if (typeof src === 'string') return new SvgPath(src);
|
|
1646
|
-
|
|
1647
|
-
if (src instanceof SvgPath) {
|
|
1648
|
-
// Create empty object
|
|
1649
|
-
var s = new SvgPath('');
|
|
1650
|
-
|
|
1651
|
-
// Clone properies
|
|
1652
|
-
s.err = src.err;
|
|
1653
|
-
s.segments = src.segments.map(function (sgm) { return sgm.slice(); });
|
|
1654
|
-
s.__stack = src.__stack.map(function (m) {
|
|
1655
|
-
return matrix().matrix(m.toArray());
|
|
1656
|
-
});
|
|
1657
|
-
|
|
1658
|
-
return s;
|
|
1659
|
-
}
|
|
1660
|
-
|
|
1661
|
-
throw new Error('SvgPath.from: invalid param type ' + src);
|
|
1662
|
-
};
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
SvgPath.prototype.__matrix = function (m) {
|
|
1666
|
-
var self = this, i;
|
|
1667
|
-
|
|
1668
|
-
// Quick leave for empty matrix
|
|
1669
|
-
if (!m.queue.length) { return; }
|
|
1670
|
-
|
|
1671
|
-
this.iterate(function (s, index, x, y) {
|
|
1672
|
-
var p, result, name, isRelative;
|
|
1673
|
-
|
|
1674
|
-
switch (s[0]) {
|
|
1675
|
-
|
|
1676
|
-
// Process 'assymetric' commands separately
|
|
1677
|
-
case 'v':
|
|
1678
|
-
p = m.calc(0, s[1], true);
|
|
1679
|
-
result = (p[0] === 0) ? [ 'v', p[1] ] : [ 'l', p[0], p[1] ];
|
|
1680
|
-
break;
|
|
1681
|
-
|
|
1682
|
-
case 'V':
|
|
1683
|
-
p = m.calc(x, s[1], false);
|
|
1684
|
-
result = (p[0] === m.calc(x, y, false)[0]) ? [ 'V', p[1] ] : [ 'L', p[0], p[1] ];
|
|
1685
|
-
break;
|
|
1686
|
-
|
|
1687
|
-
case 'h':
|
|
1688
|
-
p = m.calc(s[1], 0, true);
|
|
1689
|
-
result = (p[1] === 0) ? [ 'h', p[0] ] : [ 'l', p[0], p[1] ];
|
|
1690
|
-
break;
|
|
1691
|
-
|
|
1692
|
-
case 'H':
|
|
1693
|
-
p = m.calc(s[1], y, false);
|
|
1694
|
-
result = (p[1] === m.calc(x, y, false)[1]) ? [ 'H', p[0] ] : [ 'L', p[0], p[1] ];
|
|
1695
|
-
break;
|
|
1696
|
-
|
|
1697
|
-
case 'a':
|
|
1698
|
-
case 'A':
|
|
1699
|
-
// ARC is: ['A', rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y]
|
|
1700
|
-
|
|
1701
|
-
// Drop segment if arc is empty (end point === start point)
|
|
1702
|
-
/*if ((s[0] === 'A' && s[6] === x && s[7] === y) ||
|
|
1703
|
-
(s[0] === 'a' && s[6] === 0 && s[7] === 0)) {
|
|
1704
|
-
return [];
|
|
1705
|
-
}*/
|
|
1706
|
-
|
|
1707
|
-
// Transform rx, ry and the x-axis-rotation
|
|
1708
|
-
var ma = m.toArray();
|
|
1709
|
-
var e = ellipse(s[1], s[2], s[3]).transform(ma);
|
|
1710
|
-
|
|
1711
|
-
// flip sweep-flag if matrix is not orientation-preserving
|
|
1712
|
-
if (ma[0] * ma[3] - ma[1] * ma[2] < 0) {
|
|
1713
|
-
s[5] = s[5] ? '0' : '1';
|
|
1714
|
-
}
|
|
1715
|
-
|
|
1716
|
-
// Transform end point as usual (without translation for relative notation)
|
|
1717
|
-
p = m.calc(s[6], s[7], s[0] === 'a');
|
|
1718
|
-
|
|
1719
|
-
// Empty arcs can be ignored by renderer, but should not be dropped
|
|
1720
|
-
// to avoid collisions with `S A S` and so on. Replace with empty line.
|
|
1721
|
-
if ((s[0] === 'A' && s[6] === x && s[7] === y) ||
|
|
1722
|
-
(s[0] === 'a' && s[6] === 0 && s[7] === 0)) {
|
|
1723
|
-
result = [ s[0] === 'a' ? 'l' : 'L', p[0], p[1] ];
|
|
1724
|
-
break;
|
|
1725
|
-
}
|
|
1726
|
-
|
|
1727
|
-
// if the resulting ellipse is (almost) a segment ...
|
|
1728
|
-
if (e.isDegenerate()) {
|
|
1729
|
-
// replace the arc by a line
|
|
1730
|
-
result = [ s[0] === 'a' ? 'l' : 'L', p[0], p[1] ];
|
|
1731
|
-
} else {
|
|
1732
|
-
// if it is a real ellipse
|
|
1733
|
-
// s[0], s[4] and s[5] are not modified
|
|
1734
|
-
result = [ s[0], e.rx, e.ry, e.ax, s[4], s[5], p[0], p[1] ];
|
|
1735
|
-
}
|
|
1736
|
-
|
|
1737
|
-
break;
|
|
1738
|
-
|
|
1739
|
-
case 'm':
|
|
1740
|
-
// Edge case. The very first `m` should be processed as absolute, if happens.
|
|
1741
|
-
// Make sense for coord shift transforms.
|
|
1742
|
-
isRelative = index > 0;
|
|
1743
|
-
|
|
1744
|
-
p = m.calc(s[1], s[2], isRelative);
|
|
1745
|
-
result = [ 'm', p[0], p[1] ];
|
|
1746
|
-
break;
|
|
1747
|
-
|
|
1748
|
-
default:
|
|
1749
|
-
name = s[0];
|
|
1750
|
-
result = [ name ];
|
|
1751
|
-
isRelative = (name.toLowerCase() === name);
|
|
1752
|
-
|
|
1753
|
-
// Apply transformations to the segment
|
|
1754
|
-
for (i = 1; i < s.length; i += 2) {
|
|
1755
|
-
p = m.calc(s[i], s[i + 1], isRelative);
|
|
1756
|
-
result.push(p[0], p[1]);
|
|
1757
|
-
}
|
|
1758
|
-
}
|
|
1759
|
-
|
|
1760
|
-
self.segments[index] = result;
|
|
1761
|
-
}, true);
|
|
1762
|
-
};
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
// Apply stacked commands
|
|
1766
|
-
//
|
|
1767
|
-
SvgPath.prototype.__evaluateStack = function () {
|
|
1768
|
-
var m, i;
|
|
1769
|
-
|
|
1770
|
-
if (!this.__stack.length) { return; }
|
|
1771
|
-
|
|
1772
|
-
if (this.__stack.length === 1) {
|
|
1773
|
-
this.__matrix(this.__stack[0]);
|
|
1774
|
-
this.__stack = [];
|
|
1775
|
-
return;
|
|
1776
|
-
}
|
|
1777
|
-
|
|
1778
|
-
m = matrix();
|
|
1779
|
-
i = this.__stack.length;
|
|
1780
|
-
|
|
1781
|
-
while (--i >= 0) {
|
|
1782
|
-
m.matrix(this.__stack[i].toArray());
|
|
1783
|
-
}
|
|
1784
|
-
|
|
1785
|
-
this.__matrix(m);
|
|
1786
|
-
this.__stack = [];
|
|
1787
|
-
};
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
// Convert processed SVG Path back to string
|
|
1791
|
-
//
|
|
1792
|
-
SvgPath.prototype.toString = function () {
|
|
1793
|
-
var result = '', prevCmd = '', cmdSkipped = false;
|
|
1794
|
-
|
|
1795
|
-
this.__evaluateStack();
|
|
1796
|
-
|
|
1797
|
-
for (var i = 0, len = this.segments.length; i < len; i++) {
|
|
1798
|
-
var segment = this.segments[i];
|
|
1799
|
-
var cmd = segment[0];
|
|
1800
|
-
|
|
1801
|
-
// Command not repeating => store
|
|
1802
|
-
if (cmd !== prevCmd || cmd === 'm' || cmd === 'M') {
|
|
1803
|
-
// workaround for FontForge SVG importing bug, keep space between "z m".
|
|
1804
|
-
if (cmd === 'm' && prevCmd === 'z') result += ' ';
|
|
1805
|
-
result += cmd;
|
|
1806
|
-
|
|
1807
|
-
cmdSkipped = false;
|
|
1808
|
-
} else {
|
|
1809
|
-
cmdSkipped = true;
|
|
1810
|
-
}
|
|
1811
|
-
|
|
1812
|
-
// Store segment params
|
|
1813
|
-
for (var pos = 1; pos < segment.length; pos++) {
|
|
1814
|
-
var val = segment[pos];
|
|
1815
|
-
// Space can be skipped
|
|
1816
|
-
// 1. After command (always)
|
|
1817
|
-
// 2. For negative value (with '-' at start)
|
|
1818
|
-
if (pos === 1) {
|
|
1819
|
-
if (cmdSkipped && val >= 0) result += ' ';
|
|
1820
|
-
} else if (val >= 0) result += ' ';
|
|
1821
|
-
|
|
1822
|
-
result += val;
|
|
1823
|
-
}
|
|
1824
|
-
|
|
1825
|
-
prevCmd = cmd;
|
|
1826
|
-
}
|
|
1827
|
-
|
|
1828
|
-
return result;
|
|
1829
|
-
};
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
// Translate path to (x [, y])
|
|
1833
|
-
//
|
|
1834
|
-
SvgPath.prototype.translate = function (x, y) {
|
|
1835
|
-
this.__stack.push(matrix().translate(x, y || 0));
|
|
1836
|
-
return this;
|
|
1837
|
-
};
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
// Scale path to (sx [, sy])
|
|
1841
|
-
// sy = sx if not defined
|
|
1842
|
-
//
|
|
1843
|
-
SvgPath.prototype.scale = function (sx, sy) {
|
|
1844
|
-
this.__stack.push(matrix().scale(sx, (!sy && (sy !== 0)) ? sx : sy));
|
|
1845
|
-
return this;
|
|
1846
|
-
};
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
// Rotate path around point (sx [, sy])
|
|
1850
|
-
// sy = sx if not defined
|
|
1851
|
-
//
|
|
1852
|
-
SvgPath.prototype.rotate = function (angle, rx, ry) {
|
|
1853
|
-
this.__stack.push(matrix().rotate(angle, rx || 0, ry || 0));
|
|
1854
|
-
return this;
|
|
1855
|
-
};
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
// Skew path along the X axis by `degrees` angle
|
|
1859
|
-
//
|
|
1860
|
-
SvgPath.prototype.skewX = function (degrees) {
|
|
1861
|
-
this.__stack.push(matrix().skewX(degrees));
|
|
1862
|
-
return this;
|
|
1863
|
-
};
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
// Skew path along the Y axis by `degrees` angle
|
|
1867
|
-
//
|
|
1868
|
-
SvgPath.prototype.skewY = function (degrees) {
|
|
1869
|
-
this.__stack.push(matrix().skewY(degrees));
|
|
1870
|
-
return this;
|
|
1871
|
-
};
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
// Apply matrix transform (array of 6 elements)
|
|
1875
|
-
//
|
|
1876
|
-
SvgPath.prototype.matrix = function (m) {
|
|
1877
|
-
this.__stack.push(matrix().matrix(m));
|
|
1878
|
-
return this;
|
|
1879
|
-
};
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
// Transform path according to "transform" attr of SVG spec
|
|
1883
|
-
//
|
|
1884
|
-
SvgPath.prototype.transform = function (transformString) {
|
|
1885
|
-
if (!transformString.trim()) {
|
|
1886
|
-
return this;
|
|
1887
|
-
}
|
|
1888
|
-
this.__stack.push(transformParse(transformString));
|
|
1889
|
-
return this;
|
|
1890
|
-
};
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
// Round coords with given decimal precition.
|
|
1894
|
-
// 0 by default (to integers)
|
|
1895
|
-
//
|
|
1896
|
-
SvgPath.prototype.round = function (d) {
|
|
1897
|
-
var contourStartDeltaX = 0, contourStartDeltaY = 0, deltaX = 0, deltaY = 0, l;
|
|
1898
|
-
|
|
1899
|
-
d = d || 0;
|
|
1900
|
-
|
|
1901
|
-
this.__evaluateStack();
|
|
1902
|
-
|
|
1903
|
-
this.segments.forEach(function (s) {
|
|
1904
|
-
var isRelative = (s[0].toLowerCase() === s[0]);
|
|
1905
|
-
|
|
1906
|
-
switch (s[0]) {
|
|
1907
|
-
case 'H':
|
|
1908
|
-
case 'h':
|
|
1909
|
-
if (isRelative) { s[1] += deltaX; }
|
|
1910
|
-
deltaX = s[1] - s[1].toFixed(d);
|
|
1911
|
-
s[1] = +s[1].toFixed(d);
|
|
1912
|
-
return;
|
|
1913
|
-
|
|
1914
|
-
case 'V':
|
|
1915
|
-
case 'v':
|
|
1916
|
-
if (isRelative) { s[1] += deltaY; }
|
|
1917
|
-
deltaY = s[1] - s[1].toFixed(d);
|
|
1918
|
-
s[1] = +s[1].toFixed(d);
|
|
1919
|
-
return;
|
|
1920
|
-
|
|
1921
|
-
case 'Z':
|
|
1922
|
-
case 'z':
|
|
1923
|
-
deltaX = contourStartDeltaX;
|
|
1924
|
-
deltaY = contourStartDeltaY;
|
|
1925
|
-
return;
|
|
1926
|
-
|
|
1927
|
-
case 'M':
|
|
1928
|
-
case 'm':
|
|
1929
|
-
if (isRelative) {
|
|
1930
|
-
s[1] += deltaX;
|
|
1931
|
-
s[2] += deltaY;
|
|
1932
|
-
}
|
|
1933
|
-
|
|
1934
|
-
deltaX = s[1] - s[1].toFixed(d);
|
|
1935
|
-
deltaY = s[2] - s[2].toFixed(d);
|
|
1936
|
-
|
|
1937
|
-
contourStartDeltaX = deltaX;
|
|
1938
|
-
contourStartDeltaY = deltaY;
|
|
1939
|
-
|
|
1940
|
-
s[1] = +s[1].toFixed(d);
|
|
1941
|
-
s[2] = +s[2].toFixed(d);
|
|
1942
|
-
return;
|
|
1943
|
-
|
|
1944
|
-
case 'A':
|
|
1945
|
-
case 'a':
|
|
1946
|
-
// [cmd, rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y]
|
|
1947
|
-
if (isRelative) {
|
|
1948
|
-
s[6] += deltaX;
|
|
1949
|
-
s[7] += deltaY;
|
|
1950
|
-
}
|
|
1951
|
-
|
|
1952
|
-
deltaX = s[6] - s[6].toFixed(d);
|
|
1953
|
-
deltaY = s[7] - s[7].toFixed(d);
|
|
1954
|
-
|
|
1955
|
-
s[1] = +s[1].toFixed(d);
|
|
1956
|
-
s[2] = +s[2].toFixed(d);
|
|
1957
|
-
s[3] = +s[3].toFixed(d + 2); // better precision for rotation
|
|
1958
|
-
s[6] = +s[6].toFixed(d);
|
|
1959
|
-
s[7] = +s[7].toFixed(d);
|
|
1960
|
-
return;
|
|
1961
|
-
|
|
1962
|
-
default:
|
|
1963
|
-
// a c l q s t
|
|
1964
|
-
l = s.length;
|
|
1965
|
-
|
|
1966
|
-
if (isRelative) {
|
|
1967
|
-
s[l - 2] += deltaX;
|
|
1968
|
-
s[l - 1] += deltaY;
|
|
1969
|
-
}
|
|
1970
|
-
|
|
1971
|
-
deltaX = s[l - 2] - s[l - 2].toFixed(d);
|
|
1972
|
-
deltaY = s[l - 1] - s[l - 1].toFixed(d);
|
|
1973
|
-
|
|
1974
|
-
s.forEach(function (val, i) {
|
|
1975
|
-
if (!i) { return; }
|
|
1976
|
-
s[i] = +s[i].toFixed(d);
|
|
1977
|
-
});
|
|
1978
|
-
return;
|
|
1979
|
-
}
|
|
1980
|
-
});
|
|
1981
|
-
|
|
1982
|
-
return this;
|
|
1983
|
-
};
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
// Apply iterator function to all segments. If function returns result,
|
|
1987
|
-
// current segment will be replaced to array of returned segments.
|
|
1988
|
-
// If empty array is returned, current regment will be deleted.
|
|
1989
|
-
//
|
|
1990
|
-
SvgPath.prototype.iterate = function (iterator, keepLazyStack) {
|
|
1991
|
-
var segments = this.segments,
|
|
1992
|
-
replacements = {},
|
|
1993
|
-
needReplace = false,
|
|
1994
|
-
lastX = 0,
|
|
1995
|
-
lastY = 0,
|
|
1996
|
-
countourStartX = 0,
|
|
1997
|
-
countourStartY = 0;
|
|
1998
|
-
var i, j, newSegments;
|
|
1999
|
-
|
|
2000
|
-
if (!keepLazyStack) {
|
|
2001
|
-
this.__evaluateStack();
|
|
2002
|
-
}
|
|
2003
|
-
|
|
2004
|
-
segments.forEach(function (s, index) {
|
|
2005
|
-
|
|
2006
|
-
var res = iterator(s, index, lastX, lastY);
|
|
2007
|
-
|
|
2008
|
-
if (Array.isArray(res)) {
|
|
2009
|
-
replacements[index] = res;
|
|
2010
|
-
needReplace = true;
|
|
2011
|
-
}
|
|
2012
|
-
|
|
2013
|
-
var isRelative = (s[0] === s[0].toLowerCase());
|
|
2014
|
-
|
|
2015
|
-
// calculate absolute X and Y
|
|
2016
|
-
switch (s[0]) {
|
|
2017
|
-
case 'm':
|
|
2018
|
-
case 'M':
|
|
2019
|
-
lastX = s[1] + (isRelative ? lastX : 0);
|
|
2020
|
-
lastY = s[2] + (isRelative ? lastY : 0);
|
|
2021
|
-
countourStartX = lastX;
|
|
2022
|
-
countourStartY = lastY;
|
|
2023
|
-
return;
|
|
2024
|
-
|
|
2025
|
-
case 'h':
|
|
2026
|
-
case 'H':
|
|
2027
|
-
lastX = s[1] + (isRelative ? lastX : 0);
|
|
2028
|
-
return;
|
|
2029
|
-
|
|
2030
|
-
case 'v':
|
|
2031
|
-
case 'V':
|
|
2032
|
-
lastY = s[1] + (isRelative ? lastY : 0);
|
|
2033
|
-
return;
|
|
2034
|
-
|
|
2035
|
-
case 'z':
|
|
2036
|
-
case 'Z':
|
|
2037
|
-
// That make sence for multiple contours
|
|
2038
|
-
lastX = countourStartX;
|
|
2039
|
-
lastY = countourStartY;
|
|
2040
|
-
return;
|
|
2041
|
-
|
|
2042
|
-
default:
|
|
2043
|
-
lastX = s[s.length - 2] + (isRelative ? lastX : 0);
|
|
2044
|
-
lastY = s[s.length - 1] + (isRelative ? lastY : 0);
|
|
2045
|
-
}
|
|
2046
|
-
});
|
|
2047
|
-
|
|
2048
|
-
// Replace segments if iterator return results
|
|
2049
|
-
|
|
2050
|
-
if (!needReplace) { return this; }
|
|
2051
|
-
|
|
2052
|
-
newSegments = [];
|
|
2053
|
-
|
|
2054
|
-
for (i = 0; i < segments.length; i++) {
|
|
2055
|
-
if (typeof replacements[i] !== 'undefined') {
|
|
2056
|
-
for (j = 0; j < replacements[i].length; j++) {
|
|
2057
|
-
newSegments.push(replacements[i][j]);
|
|
2058
|
-
}
|
|
2059
|
-
} else {
|
|
2060
|
-
newSegments.push(segments[i]);
|
|
2061
|
-
}
|
|
2062
|
-
}
|
|
2063
|
-
|
|
2064
|
-
this.segments = newSegments;
|
|
2065
|
-
|
|
2066
|
-
return this;
|
|
2067
|
-
};
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
// Converts segments from relative to absolute
|
|
2071
|
-
//
|
|
2072
|
-
SvgPath.prototype.abs = function () {
|
|
2073
|
-
|
|
2074
|
-
this.iterate(function (s, index, x, y) {
|
|
2075
|
-
var name = s[0],
|
|
2076
|
-
nameUC = name.toUpperCase(),
|
|
2077
|
-
i;
|
|
2078
|
-
|
|
2079
|
-
// Skip absolute commands
|
|
2080
|
-
if (name === nameUC) { return; }
|
|
2081
|
-
|
|
2082
|
-
s[0] = nameUC;
|
|
2083
|
-
|
|
2084
|
-
switch (name) {
|
|
2085
|
-
case 'v':
|
|
2086
|
-
// v has shifted coords parity
|
|
2087
|
-
s[1] += y;
|
|
2088
|
-
return;
|
|
2089
|
-
|
|
2090
|
-
case 'a':
|
|
2091
|
-
// ARC is: ['A', rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y]
|
|
2092
|
-
// touch x, y only
|
|
2093
|
-
s[6] += x;
|
|
2094
|
-
s[7] += y;
|
|
2095
|
-
return;
|
|
2096
|
-
|
|
2097
|
-
default:
|
|
2098
|
-
for (i = 1; i < s.length; i++) {
|
|
2099
|
-
s[i] += i % 2 ? x : y; // odd values are X, even - Y
|
|
2100
|
-
}
|
|
2101
|
-
}
|
|
2102
|
-
}, true);
|
|
2103
|
-
|
|
2104
|
-
return this;
|
|
2105
|
-
};
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
// Converts segments from absolute to relative
|
|
2109
|
-
//
|
|
2110
|
-
SvgPath.prototype.rel = function () {
|
|
2111
|
-
|
|
2112
|
-
this.iterate(function (s, index, x, y) {
|
|
2113
|
-
var name = s[0],
|
|
2114
|
-
nameLC = name.toLowerCase(),
|
|
2115
|
-
i;
|
|
2116
|
-
|
|
2117
|
-
// Skip relative commands
|
|
2118
|
-
if (name === nameLC) { return; }
|
|
2119
|
-
|
|
2120
|
-
// Don't touch the first M to avoid potential confusions.
|
|
2121
|
-
if (index === 0 && name === 'M') { return; }
|
|
2122
|
-
|
|
2123
|
-
s[0] = nameLC;
|
|
2124
|
-
|
|
2125
|
-
switch (name) {
|
|
2126
|
-
case 'V':
|
|
2127
|
-
// V has shifted coords parity
|
|
2128
|
-
s[1] -= y;
|
|
2129
|
-
return;
|
|
2130
|
-
|
|
2131
|
-
case 'A':
|
|
2132
|
-
// ARC is: ['A', rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y]
|
|
2133
|
-
// touch x, y only
|
|
2134
|
-
s[6] -= x;
|
|
2135
|
-
s[7] -= y;
|
|
2136
|
-
return;
|
|
2137
|
-
|
|
2138
|
-
default:
|
|
2139
|
-
for (i = 1; i < s.length; i++) {
|
|
2140
|
-
s[i] -= i % 2 ? x : y; // odd values are X, even - Y
|
|
2141
|
-
}
|
|
2142
|
-
}
|
|
2143
|
-
}, true);
|
|
2144
|
-
|
|
2145
|
-
return this;
|
|
2146
|
-
};
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
// Converts arcs to cubic bézier curves
|
|
2150
|
-
//
|
|
2151
|
-
SvgPath.prototype.unarc = function () {
|
|
2152
|
-
this.iterate(function (s, index, x, y) {
|
|
2153
|
-
var new_segments, nextX, nextY, result = [], name = s[0];
|
|
2154
|
-
|
|
2155
|
-
// Skip anything except arcs
|
|
2156
|
-
if (name !== 'A' && name !== 'a') { return null; }
|
|
2157
|
-
|
|
2158
|
-
if (name === 'a') {
|
|
2159
|
-
// convert relative arc coordinates to absolute
|
|
2160
|
-
nextX = x + s[6];
|
|
2161
|
-
nextY = y + s[7];
|
|
2162
|
-
} else {
|
|
2163
|
-
nextX = s[6];
|
|
2164
|
-
nextY = s[7];
|
|
2165
|
-
}
|
|
2166
|
-
|
|
2167
|
-
new_segments = a2c(x, y, nextX, nextY, s[4], s[5], s[1], s[2], s[3]);
|
|
2168
|
-
|
|
2169
|
-
// Degenerated arcs can be ignored by renderer, but should not be dropped
|
|
2170
|
-
// to avoid collisions with `S A S` and so on. Replace with empty line.
|
|
2171
|
-
if (new_segments.length === 0) {
|
|
2172
|
-
return [ [ s[0] === 'a' ? 'l' : 'L', s[6], s[7] ] ];
|
|
2173
|
-
}
|
|
2174
|
-
|
|
2175
|
-
new_segments.forEach(function (s) {
|
|
2176
|
-
result.push([ 'C', s[2], s[3], s[4], s[5], s[6], s[7] ]);
|
|
2177
|
-
});
|
|
2178
|
-
|
|
2179
|
-
return result;
|
|
2180
|
-
});
|
|
2181
|
-
|
|
2182
|
-
return this;
|
|
2183
|
-
};
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
// Converts smooth curves (with missed control point) to generic curves
|
|
2187
|
-
//
|
|
2188
|
-
SvgPath.prototype.unshort = function () {
|
|
2189
|
-
var segments = this.segments;
|
|
2190
|
-
var prevControlX, prevControlY, prevSegment;
|
|
2191
|
-
var curControlX, curControlY;
|
|
2192
|
-
|
|
2193
|
-
// TODO: add lazy evaluation flag when relative commands supported
|
|
2194
|
-
|
|
2195
|
-
this.iterate(function (s, idx, x, y) {
|
|
2196
|
-
var name = s[0], nameUC = name.toUpperCase(), isRelative;
|
|
2197
|
-
|
|
2198
|
-
// First command MUST be M|m, it's safe to skip.
|
|
2199
|
-
// Protect from access to [-1] for sure.
|
|
2200
|
-
if (!idx) { return; }
|
|
2201
|
-
|
|
2202
|
-
if (nameUC === 'T') { // quadratic curve
|
|
2203
|
-
isRelative = (name === 't');
|
|
2204
|
-
|
|
2205
|
-
prevSegment = segments[idx - 1];
|
|
2206
|
-
|
|
2207
|
-
if (prevSegment[0] === 'Q') {
|
|
2208
|
-
prevControlX = prevSegment[1] - x;
|
|
2209
|
-
prevControlY = prevSegment[2] - y;
|
|
2210
|
-
} else if (prevSegment[0] === 'q') {
|
|
2211
|
-
prevControlX = prevSegment[1] - prevSegment[3];
|
|
2212
|
-
prevControlY = prevSegment[2] - prevSegment[4];
|
|
2213
|
-
} else {
|
|
2214
|
-
prevControlX = 0;
|
|
2215
|
-
prevControlY = 0;
|
|
2216
|
-
}
|
|
2217
|
-
|
|
2218
|
-
curControlX = -prevControlX;
|
|
2219
|
-
curControlY = -prevControlY;
|
|
2220
|
-
|
|
2221
|
-
if (!isRelative) {
|
|
2222
|
-
curControlX += x;
|
|
2223
|
-
curControlY += y;
|
|
2224
|
-
}
|
|
2225
|
-
|
|
2226
|
-
segments[idx] = [
|
|
2227
|
-
isRelative ? 'q' : 'Q',
|
|
2228
|
-
curControlX, curControlY,
|
|
2229
|
-
s[1], s[2]
|
|
2230
|
-
];
|
|
2231
|
-
|
|
2232
|
-
} else if (nameUC === 'S') { // cubic curve
|
|
2233
|
-
isRelative = (name === 's');
|
|
2234
|
-
|
|
2235
|
-
prevSegment = segments[idx - 1];
|
|
2236
|
-
|
|
2237
|
-
if (prevSegment[0] === 'C') {
|
|
2238
|
-
prevControlX = prevSegment[3] - x;
|
|
2239
|
-
prevControlY = prevSegment[4] - y;
|
|
2240
|
-
} else if (prevSegment[0] === 'c') {
|
|
2241
|
-
prevControlX = prevSegment[3] - prevSegment[5];
|
|
2242
|
-
prevControlY = prevSegment[4] - prevSegment[6];
|
|
2243
|
-
} else {
|
|
2244
|
-
prevControlX = 0;
|
|
2245
|
-
prevControlY = 0;
|
|
2246
|
-
}
|
|
2247
|
-
|
|
2248
|
-
curControlX = -prevControlX;
|
|
2249
|
-
curControlY = -prevControlY;
|
|
2250
|
-
|
|
2251
|
-
if (!isRelative) {
|
|
2252
|
-
curControlX += x;
|
|
2253
|
-
curControlY += y;
|
|
2254
|
-
}
|
|
2255
|
-
|
|
2256
|
-
segments[idx] = [
|
|
2257
|
-
isRelative ? 'c' : 'C',
|
|
2258
|
-
curControlX, curControlY,
|
|
2259
|
-
s[1], s[2], s[3], s[4]
|
|
2260
|
-
];
|
|
2261
|
-
}
|
|
2262
|
-
});
|
|
2263
|
-
|
|
2264
|
-
return this;
|
|
2265
|
-
};
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
svgpath$1 = SvgPath;
|
|
2269
|
-
return svgpath$1;
|
|
2270
|
-
}
|
|
2271
|
-
|
|
2272
|
-
var svgpath;
|
|
2273
|
-
var hasRequiredSvgpath;
|
|
2274
|
-
|
|
2275
|
-
function requireSvgpath () {
|
|
2276
|
-
if (hasRequiredSvgpath) return svgpath;
|
|
2277
|
-
hasRequiredSvgpath = 1;
|
|
2278
|
-
|
|
2279
|
-
svgpath = requireSvgpath$1();
|
|
2280
|
-
return svgpath;
|
|
2281
|
-
}
|
|
2282
|
-
|
|
2283
|
-
var svgpathExports = requireSvgpath();
|
|
2284
|
-
const Path = /*@__PURE__*/getDefaultExportFromCjs(svgpathExports);
|
|
2285
|
-
|
|
2286
|
-
//Parses an SVG path into an object.
|
|
2287
|
-
//Taken from https://github.com/jkroso/parse-svg-path
|
|
2288
|
-
//Re-written so it can be used with rollup
|
|
2289
|
-
var length = {a: 7, c: 6, h: 1, l: 2, m: 2, q: 4, s: 4, t: 2, v: 1, z: 0};
|
|
2290
|
-
var segment = /([astvzqmhlc])([^astvzqmhlc]*)/ig;
|
|
2291
|
-
|
|
2292
|
-
function parse$1(path) {
|
|
2293
|
-
var data = [];
|
|
2294
|
-
path.replace(segment, function(_, command, args){
|
|
2295
|
-
var type = command.toLowerCase();
|
|
2296
|
-
args = parseValues(args);
|
|
2297
|
-
|
|
2298
|
-
// overloaded moveTo
|
|
2299
|
-
if (type === 'm' && args.length > 2) {
|
|
2300
|
-
data.push([command].concat(args.splice(0, 2)));
|
|
2301
|
-
type = 'l';
|
|
2302
|
-
command = command === 'm' ? 'l' : 'L';
|
|
2303
|
-
}
|
|
2304
|
-
|
|
2305
|
-
while (args.length >= 0) {
|
|
2306
|
-
if (args.length === length[type]) {
|
|
2307
|
-
args.unshift(command);
|
|
2308
|
-
return data.push(args);
|
|
2309
|
-
}
|
|
2310
|
-
if (args.length < length[type]) {
|
|
2311
|
-
throw new Error('malformed path data');
|
|
2312
|
-
}
|
|
2313
|
-
data.push([command].concat(args.splice(0, length[type])));
|
|
2314
|
-
}
|
|
2315
|
-
});
|
|
2316
|
-
return data;
|
|
2317
|
-
}
|
|
2318
|
-
|
|
2319
|
-
var number = /-?[0-9]*\.?[0-9]+(?:e[-+]?\d+)?/ig;
|
|
2320
|
-
|
|
2321
|
-
function parseValues(args) {
|
|
2322
|
-
var numbers = args.match(number);
|
|
2323
|
-
return numbers ? numbers.map(Number) : [];
|
|
2324
|
-
}
|
|
2325
|
-
|
|
2326
|
-
//Calculate Bezier curve length and positionAtLength
|
|
2327
|
-
//Algorithms taken from http://bl.ocks.org/hnakamur/e7efd0602bfc15f66fc5, https://gist.github.com/tunght13488/6744e77c242cc7a94859 and http://stackoverflow.com/questions/11854907/calculate-the-length-of-a-segment-of-a-quadratic-bezier
|
|
2328
|
-
|
|
2329
|
-
function Bezier(ax, ay, bx, by, cx, cy, dx, dy) {
|
|
2330
|
-
return new Bezier$1(ax, ay, bx, by, cx, cy, dx, dy);
|
|
2331
|
-
}
|
|
2332
|
-
|
|
2333
|
-
function Bezier$1(ax, ay, bx, by, cx, cy, dx, dy) {
|
|
2334
|
-
this.a = {x:ax, y:ay};
|
|
2335
|
-
this.b = {x:bx, y:by};
|
|
2336
|
-
this.c = {x:cx, y:cy};
|
|
2337
|
-
this.d = {x:dx, y:dy};
|
|
2338
|
-
|
|
2339
|
-
if(dx !== null && dx !== undefined && dy !== null && dy !== undefined){
|
|
2340
|
-
this.getArcLength = getCubicArcLength;
|
|
2341
|
-
this.getPoint = cubicPoint;
|
|
2342
|
-
this.getDerivative = cubicDerivative;
|
|
2343
|
-
} else {
|
|
2344
|
-
this.getArcLength = getQuadraticArcLength;
|
|
2345
|
-
this.getPoint = quadraticPoint;
|
|
2346
|
-
this.getDerivative = quadraticDerivative;
|
|
2347
|
-
}
|
|
2348
|
-
|
|
2349
|
-
this.init();
|
|
2350
|
-
}
|
|
2351
|
-
|
|
2352
|
-
Bezier$1.prototype = {
|
|
2353
|
-
constructor: Bezier$1,
|
|
2354
|
-
init: function() {
|
|
2355
|
-
|
|
2356
|
-
this.length = this.getArcLength([this.a.x, this.b.x, this.c.x, this.d.x],
|
|
2357
|
-
[this.a.y, this.b.y, this.c.y, this.d.y]);
|
|
2358
|
-
},
|
|
2359
|
-
|
|
2360
|
-
getTotalLength: function() {
|
|
2361
|
-
return this.length;
|
|
2362
|
-
},
|
|
2363
|
-
getPointAtLength: function(length) {
|
|
2364
|
-
var t = t2length(length, this.length, this.getArcLength,
|
|
2365
|
-
[this.a.x, this.b.x, this.c.x, this.d.x],
|
|
2366
|
-
[this.a.y, this.b.y, this.c.y, this.d.y]);
|
|
2367
|
-
|
|
2368
|
-
return this.getPoint([this.a.x, this.b.x, this.c.x, this.d.x],
|
|
2369
|
-
[this.a.y, this.b.y, this.c.y, this.d.y],
|
|
2370
|
-
t);
|
|
2371
|
-
},
|
|
2372
|
-
getTangentAtLength: function(length){
|
|
2373
|
-
var t = t2length(length, this.length, this.getArcLength,
|
|
2374
|
-
[this.a.x, this.b.x, this.c.x, this.d.x],
|
|
2375
|
-
[this.a.y, this.b.y, this.c.y, this.d.y]);
|
|
2376
|
-
|
|
2377
|
-
var derivative = this.getDerivative([this.a.x, this.b.x, this.c.x, this.d.x],
|
|
2378
|
-
[this.a.y, this.b.y, this.c.y, this.d.y], t);
|
|
2379
|
-
var mdl = Math.sqrt(derivative.x * derivative.x + derivative.y * derivative.y);
|
|
2380
|
-
var tangent;
|
|
2381
|
-
if (mdl > 0){
|
|
2382
|
-
tangent = {x: derivative.x/mdl, y: derivative.y/mdl};
|
|
2383
|
-
} else {
|
|
2384
|
-
tangent = {x: 0, y: 0};
|
|
2385
|
-
}
|
|
2386
|
-
return tangent;
|
|
2387
|
-
},
|
|
2388
|
-
getPropertiesAtLength: function(length){
|
|
2389
|
-
var t = t2length(length, this.length, this.getArcLength,
|
|
2390
|
-
[this.a.x, this.b.x, this.c.x, this.d.x],
|
|
2391
|
-
[this.a.y, this.b.y, this.c.y, this.d.y]);
|
|
2392
|
-
|
|
2393
|
-
var derivative = this.getDerivative([this.a.x, this.b.x, this.c.x, this.d.x],
|
|
2394
|
-
[this.a.y, this.b.y, this.c.y, this.d.y], t);
|
|
2395
|
-
var mdl = Math.sqrt(derivative.x * derivative.x + derivative.y * derivative.y);
|
|
2396
|
-
var tangent;
|
|
2397
|
-
if (mdl > 0){
|
|
2398
|
-
tangent = {x: derivative.x/mdl, y: derivative.y/mdl};
|
|
2399
|
-
} else {
|
|
2400
|
-
tangent = {x: 0, y: 0};
|
|
2401
|
-
}
|
|
2402
|
-
var point = this.getPoint([this.a.x, this.b.x, this.c.x, this.d.x],
|
|
2403
|
-
[this.a.y, this.b.y, this.c.y, this.d.y],
|
|
2404
|
-
t);
|
|
2405
|
-
return {x: point.x, y: point.y, tangentX: tangent.x, tangentY: tangent.y};
|
|
2406
|
-
}
|
|
2407
|
-
};
|
|
2408
|
-
|
|
2409
|
-
function quadraticDerivative(xs, ys, t){
|
|
2410
|
-
return {x: (1 - t) * 2*(xs[1] - xs[0]) +t * 2*(xs[2] - xs[1]),
|
|
2411
|
-
y: (1 - t) * 2*(ys[1] - ys[0]) +t * 2*(ys[2] - ys[1])
|
|
2412
|
-
};
|
|
2413
|
-
}
|
|
2414
|
-
|
|
2415
|
-
function cubicDerivative(xs, ys, t){
|
|
2416
|
-
var derivative = quadraticPoint(
|
|
2417
|
-
[3*(xs[1] - xs[0]), 3*(xs[2] - xs[1]), 3*(xs[3] - xs[2])],
|
|
2418
|
-
[3*(ys[1] - ys[0]), 3*(ys[2] - ys[1]), 3*(ys[3] - ys[2])],
|
|
2419
|
-
t);
|
|
2420
|
-
return derivative;
|
|
2421
|
-
}
|
|
2422
|
-
|
|
2423
|
-
function t2length(length, total_length, func, xs, ys){
|
|
2424
|
-
var error = 1;
|
|
2425
|
-
var t = length/total_length;
|
|
2426
|
-
var step = (length - func(xs, ys, t))/total_length;
|
|
2427
|
-
|
|
2428
|
-
while (error > 0.001){
|
|
2429
|
-
var increasedTLength = func(xs, ys, t + step);
|
|
2430
|
-
var decreasedTLength = func(xs, ys, t - step);
|
|
2431
|
-
var increasedTError = Math.abs(length - increasedTLength)/total_length;
|
|
2432
|
-
var decreasedTError = Math.abs(length - decreasedTLength)/total_length;
|
|
2433
|
-
if (increasedTError < error) {
|
|
2434
|
-
error = increasedTError;
|
|
2435
|
-
t += step;
|
|
2436
|
-
} else if (decreasedTError < error) {
|
|
2437
|
-
error = decreasedTError;
|
|
2438
|
-
t -= step;
|
|
2439
|
-
} else {
|
|
2440
|
-
step /= 2;
|
|
2441
|
-
}
|
|
2442
|
-
}
|
|
2443
|
-
|
|
2444
|
-
return t;
|
|
2445
|
-
}
|
|
2446
|
-
|
|
2447
|
-
function quadraticPoint(xs, ys, t){
|
|
2448
|
-
var x = (1 - t) * (1 - t) * xs[0] + 2 * (1 - t) * t * xs[1] + t * t * xs[2];
|
|
2449
|
-
var y = (1 - t) * (1 - t) * ys[0] + 2 * (1 - t) * t * ys[1] + t * t * ys[2];
|
|
2450
|
-
return {x: x, y: y};
|
|
2451
|
-
}
|
|
2452
|
-
|
|
2453
|
-
function cubicPoint(xs, ys, t){
|
|
2454
|
-
var x = (1 - t) * (1 - t) * (1 - t) * xs[0] + 3 * (1 - t) * (1 - t) * t * xs[1] +
|
|
2455
|
-
3 * (1 - t) * t * t * xs[2] + t * t * t * xs[3];
|
|
2456
|
-
var y = (1 - t) * (1 - t) * (1 - t) * ys[0] + 3 * (1 - t) * (1 - t) * t * ys[1] +
|
|
2457
|
-
3 * (1 - t) * t * t * ys[2] + t * t * t * ys[3];
|
|
2458
|
-
|
|
2459
|
-
return {x: x, y: y};
|
|
2460
|
-
}
|
|
2461
|
-
|
|
2462
|
-
function getQuadraticArcLength(xs, ys, t) {
|
|
2463
|
-
if (t === undefined) {
|
|
2464
|
-
t = 1;
|
|
2465
|
-
}
|
|
2466
|
-
var ax = xs[0] - 2 * xs[1] + xs[2];
|
|
2467
|
-
var ay = ys[0] - 2 * ys[1] + ys[2];
|
|
2468
|
-
var bx = 2 * xs[1] - 2 * xs[0];
|
|
2469
|
-
var by = 2 * ys[1] - 2 * ys[0];
|
|
2470
|
-
|
|
2471
|
-
var A = 4 * (ax * ax + ay * ay);
|
|
2472
|
-
var B = 4 * (ax * bx + ay * by);
|
|
2473
|
-
var C = bx * bx + by * by;
|
|
2474
|
-
|
|
2475
|
-
if(A === 0){
|
|
2476
|
-
return t * Math.sqrt(Math.pow(xs[2] - xs[0], 2) + Math.pow(ys[2] - ys[0], 2));
|
|
2477
|
-
}
|
|
2478
|
-
var b = B/(2*A);
|
|
2479
|
-
var c = C/A;
|
|
2480
|
-
var u = t + b;
|
|
2481
|
-
var k = c - b*b;
|
|
2482
|
-
|
|
2483
|
-
return (Math.sqrt(A)/2)*(
|
|
2484
|
-
u*Math.sqrt(u*u+k)-b*Math.sqrt(b*b+k)+
|
|
2485
|
-
k*Math.log(Math.abs(
|
|
2486
|
-
(u+Math.sqrt(u*u+k))/(b+Math.sqrt(b*b+k))
|
|
2487
|
-
))
|
|
2488
|
-
);
|
|
2489
|
-
|
|
2490
|
-
}
|
|
2491
|
-
|
|
2492
|
-
// Legendre-Gauss abscissae (xi values, defined at i=n as the roots of the nth order Legendre polynomial Pn(x))
|
|
2493
|
-
var tValues = [
|
|
2494
|
-
[],
|
|
2495
|
-
[],
|
|
2496
|
-
[-0.5773502691896257,0.5773502691896257645091487805019574556476],
|
|
2497
|
-
[0,-0.7745966692414834,0.7745966692414833770358530799564799221665],
|
|
2498
|
-
[-0.33998104358485626,0.3399810435848562648026657591032446872005,-0.8611363115940526,0.8611363115940525752239464888928095050957],
|
|
2499
|
-
[0,-0.5384693101056831,0.5384693101056830910363144207002088049672,-0.906179845938664,0.9061798459386639927976268782993929651256],
|
|
2500
|
-
[0.6612093864662645136613995950199053470064,-0.6612093864662645,-0.2386191860831969,0.2386191860831969086305017216807119354186,-0.932469514203152,0.9324695142031520278123015544939946091347],
|
|
2501
|
-
[0, 0.4058451513773971669066064120769614633473,-0.4058451513773972,-0.7415311855993945,0.7415311855993944398638647732807884070741,-0.9491079123427585,0.9491079123427585245261896840478512624007],
|
|
2502
|
-
[-0.1834346424956498,0.1834346424956498049394761423601839806667,-0.525532409916329,0.5255324099163289858177390491892463490419,-0.7966664774136267,0.7966664774136267395915539364758304368371,-0.9602898564975363,0.9602898564975362316835608685694729904282],
|
|
2503
|
-
[0,-0.8360311073266358,0.8360311073266357942994297880697348765441,-0.9681602395076261,0.9681602395076260898355762029036728700494,-0.3242534234038089,0.3242534234038089290385380146433366085719,-0.6133714327005904,0.6133714327005903973087020393414741847857],
|
|
2504
|
-
[-0.14887433898163122,0.1488743389816312108848260011297199846175,-0.4333953941292472,0.4333953941292471907992659431657841622000,-0.6794095682990244,0.6794095682990244062343273651148735757692,-0.8650633666889845,0.8650633666889845107320966884234930485275,-0.9739065285171717,0.9739065285171717200779640120844520534282],
|
|
2505
|
-
[0,-0.26954315595234496,0.2695431559523449723315319854008615246796,-0.5190961292068118,0.5190961292068118159257256694586095544802,-0.7301520055740494,0.7301520055740493240934162520311534580496,-0.8870625997680953,0.8870625997680952990751577693039272666316,-0.978228658146057,0.9782286581460569928039380011228573907714],
|
|
2506
|
-
[-0.1252334085114689,0.1252334085114689154724413694638531299833,-0.3678314989981802,0.3678314989981801937526915366437175612563,-0.5873179542866175,0.5873179542866174472967024189405342803690,-0.7699026741943047,0.7699026741943046870368938332128180759849,-0.9041172563704749,0.9041172563704748566784658661190961925375,-0.9815606342467192,0.9815606342467192506905490901492808229601],
|
|
2507
|
-
[0,-0.2304583159551348,0.2304583159551347940655281210979888352115,-0.44849275103644687,0.4484927510364468528779128521276398678019,-0.6423493394403402,0.6423493394403402206439846069955156500716,-0.8015780907333099,0.8015780907333099127942064895828598903056,-0.9175983992229779,0.9175983992229779652065478365007195123904,-0.9841830547185881,0.9841830547185881494728294488071096110649],
|
|
2508
|
-
[-0.10805494870734367,0.1080549487073436620662446502198347476119,-0.31911236892788974,0.3191123689278897604356718241684754668342,-0.5152486363581541,0.5152486363581540919652907185511886623088,-0.6872929048116855,0.6872929048116854701480198030193341375384,-0.827201315069765,0.8272013150697649931897947426503949610397,-0.9284348836635735,0.9284348836635735173363911393778742644770,-0.9862838086968123,0.9862838086968123388415972667040528016760],
|
|
2509
|
-
[0,-0.20119409399743451,0.2011940939974345223006283033945962078128,-0.3941513470775634,0.3941513470775633698972073709810454683627,-0.5709721726085388,0.5709721726085388475372267372539106412383,-0.7244177313601701,0.7244177313601700474161860546139380096308,-0.8482065834104272,0.8482065834104272162006483207742168513662,-0.937273392400706,0.9372733924007059043077589477102094712439,-0.9879925180204854,0.9879925180204854284895657185866125811469],
|
|
2510
|
-
[-0.09501250983763744,0.0950125098376374401853193354249580631303,-0.2816035507792589,0.2816035507792589132304605014604961064860,-0.45801677765722737,0.4580167776572273863424194429835775735400,-0.6178762444026438,0.6178762444026437484466717640487910189918,-0.755404408355003,0.7554044083550030338951011948474422683538,-0.8656312023878318,0.8656312023878317438804678977123931323873,-0.9445750230732326,0.9445750230732325760779884155346083450911,-0.9894009349916499,0.9894009349916499325961541734503326274262],
|
|
2511
|
-
[0,-0.17848418149584785,0.1784841814958478558506774936540655574754,-0.3512317634538763,0.3512317634538763152971855170953460050405,-0.5126905370864769,0.5126905370864769678862465686295518745829,-0.6576711592166907,0.6576711592166907658503022166430023351478,-0.7815140038968014,0.7815140038968014069252300555204760502239,-0.8802391537269859,0.8802391537269859021229556944881556926234,-0.9506755217687678,0.9506755217687677612227169578958030214433,-0.9905754753144174,0.9905754753144173356754340199406652765077],
|
|
2512
|
-
[-0.0847750130417353,0.0847750130417353012422618529357838117333,-0.2518862256915055,0.2518862256915055095889728548779112301628,-0.41175116146284263,0.4117511614628426460359317938330516370789,-0.5597708310739475,0.5597708310739475346078715485253291369276,-0.6916870430603532,0.6916870430603532078748910812888483894522,-0.8037049589725231,0.8037049589725231156824174550145907971032,-0.8926024664975557,0.8926024664975557392060605911271455154078,-0.9558239495713977,0.9558239495713977551811958929297763099728,-0.9915651684209309,0.9915651684209309467300160047061507702525],
|
|
2513
|
-
[0,-0.16035864564022537,0.1603586456402253758680961157407435495048,-0.31656409996362983,0.3165640999636298319901173288498449178922,-0.46457074137596094,0.4645707413759609457172671481041023679762,-0.600545304661681,0.6005453046616810234696381649462392798683,-0.7209661773352294,0.7209661773352293786170958608237816296571,-0.8227146565371428,0.8227146565371428249789224867127139017745,-0.9031559036148179,0.9031559036148179016426609285323124878093,-0.96020815213483,0.9602081521348300308527788406876515266150,-0.9924068438435844,0.9924068438435844031890176702532604935893],
|
|
2514
|
-
[-0.07652652113349734,0.0765265211334973337546404093988382110047,-0.22778585114164507,0.2277858511416450780804961953685746247430,-0.37370608871541955,0.3737060887154195606725481770249272373957,-0.5108670019508271,0.5108670019508270980043640509552509984254,-0.636053680726515,0.6360536807265150254528366962262859367433,-0.7463319064601508,0.7463319064601507926143050703556415903107,-0.8391169718222188,0.8391169718222188233945290617015206853296,-0.912234428251326,0.9122344282513259058677524412032981130491,-0.9639719272779138,0.9639719272779137912676661311972772219120,-0.9931285991850949,0.9931285991850949247861223884713202782226],
|
|
2515
|
-
[0,-0.1455618541608951,0.1455618541608950909370309823386863301163,-0.2880213168024011,0.2880213168024010966007925160646003199090,-0.4243421202074388,0.4243421202074387835736688885437880520964,-0.5516188358872198,0.5516188358872198070590187967243132866220,-0.6671388041974123,0.6671388041974123193059666699903391625970,-0.7684399634756779,0.7684399634756779086158778513062280348209,-0.8533633645833173,0.8533633645833172836472506385875676702761,-0.9200993341504008,0.9200993341504008287901871337149688941591,-0.9672268385663063,0.9672268385663062943166222149076951614246,-0.9937521706203895,0.9937521706203895002602420359379409291933],
|
|
2516
|
-
[-0.06973927331972223,0.0697392733197222212138417961186280818222,-0.20786042668822127,0.2078604266882212854788465339195457342156,-0.34193582089208424,0.3419358208920842251581474204273796195591,-0.469355837986757,0.4693558379867570264063307109664063460953,-0.5876404035069116,0.5876404035069115929588769276386473488776,-0.6944872631866827,0.6944872631866827800506898357622567712673,-0.7878168059792081,0.7878168059792081620042779554083515213881,-0.8658125777203002,0.8658125777203001365364256370193787290847,-0.926956772187174,0.9269567721871740005206929392590531966353,-0.9700604978354287,0.9700604978354287271239509867652687108059,-0.9942945854823992,0.9942945854823992920730314211612989803930],
|
|
2517
|
-
[0,-0.1332568242984661,0.1332568242984661109317426822417661370104,-0.26413568097034495,0.2641356809703449305338695382833096029790,-0.3903010380302908,0.3903010380302908314214888728806054585780,-0.5095014778460075,0.5095014778460075496897930478668464305448,-0.6196098757636461,0.6196098757636461563850973116495956533871,-0.7186613631319502,0.7186613631319501944616244837486188483299,-0.8048884016188399,0.8048884016188398921511184069967785579414,-0.8767523582704416,0.8767523582704416673781568859341456716389,-0.9329710868260161,0.9329710868260161023491969890384229782357,-0.9725424712181152,0.9725424712181152319560240768207773751816,-0.9947693349975522,0.9947693349975521235239257154455743605736],
|
|
2518
|
-
[-0.06405689286260563,0.0640568928626056260850430826247450385909,-0.1911188674736163,0.1911188674736163091586398207570696318404,-0.3150426796961634,0.3150426796961633743867932913198102407864,-0.4337935076260451,0.4337935076260451384870842319133497124524,-0.5454214713888396,0.5454214713888395356583756172183723700107,-0.6480936519369755,0.6480936519369755692524957869107476266696,-0.7401241915785544,0.7401241915785543642438281030999784255232,-0.820001985973903,0.8200019859739029219539498726697452080761,-0.8864155270044011,0.8864155270044010342131543419821967550873,-0.9382745520027328,0.9382745520027327585236490017087214496548,-0.9747285559713095,0.9747285559713094981983919930081690617411,-0.9951872199970213,0.9951872199970213601799974097007368118745]
|
|
2519
|
-
];
|
|
2520
|
-
|
|
2521
|
-
// Legendre-Gauss weights (wi values, defined by a function linked to in the Bezier primer article)
|
|
2522
|
-
var cValues = [
|
|
2523
|
-
[],[],
|
|
2524
|
-
[1.0,1.0],
|
|
2525
|
-
[0.8888888888888888888888888888888888888888,0.5555555555555555555555555555555555555555,0.5555555555555555555555555555555555555555],
|
|
2526
|
-
[0.6521451548625461426269360507780005927646,0.6521451548625461426269360507780005927646,0.3478548451374538573730639492219994072353,0.3478548451374538573730639492219994072353],
|
|
2527
|
-
[0.5688888888888888888888888888888888888888,0.4786286704993664680412915148356381929122,0.4786286704993664680412915148356381929122,0.2369268850561890875142640407199173626432,0.2369268850561890875142640407199173626432],
|
|
2528
|
-
[0.3607615730481386075698335138377161116615,0.3607615730481386075698335138377161116615,0.4679139345726910473898703439895509948116,0.4679139345726910473898703439895509948116,0.1713244923791703450402961421727328935268,0.1713244923791703450402961421727328935268],
|
|
2529
|
-
[0.4179591836734693877551020408163265306122,0.3818300505051189449503697754889751338783,0.3818300505051189449503697754889751338783,0.2797053914892766679014677714237795824869,0.2797053914892766679014677714237795824869,0.1294849661688696932706114326790820183285,0.1294849661688696932706114326790820183285],
|
|
2530
|
-
[0.3626837833783619829651504492771956121941,0.3626837833783619829651504492771956121941,0.3137066458778872873379622019866013132603,0.3137066458778872873379622019866013132603,0.2223810344533744705443559944262408844301,0.2223810344533744705443559944262408844301,0.1012285362903762591525313543099621901153,0.1012285362903762591525313543099621901153],
|
|
2531
|
-
[0.3302393550012597631645250692869740488788,0.1806481606948574040584720312429128095143,0.1806481606948574040584720312429128095143,0.0812743883615744119718921581105236506756,0.0812743883615744119718921581105236506756,0.3123470770400028400686304065844436655987,0.3123470770400028400686304065844436655987,0.2606106964029354623187428694186328497718,0.2606106964029354623187428694186328497718],
|
|
2532
|
-
[0.2955242247147528701738929946513383294210,0.2955242247147528701738929946513383294210,0.2692667193099963550912269215694693528597,0.2692667193099963550912269215694693528597,0.2190863625159820439955349342281631924587,0.2190863625159820439955349342281631924587,0.1494513491505805931457763396576973324025,0.1494513491505805931457763396576973324025,0.0666713443086881375935688098933317928578,0.0666713443086881375935688098933317928578],
|
|
2533
|
-
[0.2729250867779006307144835283363421891560,0.2628045445102466621806888698905091953727,0.2628045445102466621806888698905091953727,0.2331937645919904799185237048431751394317,0.2331937645919904799185237048431751394317,0.1862902109277342514260976414316558916912,0.1862902109277342514260976414316558916912,0.1255803694649046246346942992239401001976,0.1255803694649046246346942992239401001976,0.0556685671161736664827537204425485787285,0.0556685671161736664827537204425485787285],
|
|
2534
|
-
[0.2491470458134027850005624360429512108304,0.2491470458134027850005624360429512108304,0.2334925365383548087608498989248780562594,0.2334925365383548087608498989248780562594,0.2031674267230659217490644558097983765065,0.2031674267230659217490644558097983765065,0.1600783285433462263346525295433590718720,0.1600783285433462263346525295433590718720,0.1069393259953184309602547181939962242145,0.1069393259953184309602547181939962242145,0.0471753363865118271946159614850170603170,0.0471753363865118271946159614850170603170],
|
|
2535
|
-
[0.2325515532308739101945895152688359481566,0.2262831802628972384120901860397766184347,0.2262831802628972384120901860397766184347,0.2078160475368885023125232193060527633865,0.2078160475368885023125232193060527633865,0.1781459807619457382800466919960979955128,0.1781459807619457382800466919960979955128,0.1388735102197872384636017768688714676218,0.1388735102197872384636017768688714676218,0.0921214998377284479144217759537971209236,0.0921214998377284479144217759537971209236,0.0404840047653158795200215922009860600419,0.0404840047653158795200215922009860600419],
|
|
2536
|
-
[0.2152638534631577901958764433162600352749,0.2152638534631577901958764433162600352749,0.2051984637212956039659240656612180557103,0.2051984637212956039659240656612180557103,0.1855383974779378137417165901251570362489,0.1855383974779378137417165901251570362489,0.1572031671581935345696019386238421566056,0.1572031671581935345696019386238421566056,0.1215185706879031846894148090724766259566,0.1215185706879031846894148090724766259566,0.0801580871597602098056332770628543095836,0.0801580871597602098056332770628543095836,0.0351194603317518630318328761381917806197,0.0351194603317518630318328761381917806197],
|
|
2537
|
-
[0.2025782419255612728806201999675193148386,0.1984314853271115764561183264438393248186,0.1984314853271115764561183264438393248186,0.1861610000155622110268005618664228245062,0.1861610000155622110268005618664228245062,0.1662692058169939335532008604812088111309,0.1662692058169939335532008604812088111309,0.1395706779261543144478047945110283225208,0.1395706779261543144478047945110283225208,0.1071592204671719350118695466858693034155,0.1071592204671719350118695466858693034155,0.0703660474881081247092674164506673384667,0.0703660474881081247092674164506673384667,0.0307532419961172683546283935772044177217,0.0307532419961172683546283935772044177217],
|
|
2538
|
-
[0.1894506104550684962853967232082831051469,0.1894506104550684962853967232082831051469,0.1826034150449235888667636679692199393835,0.1826034150449235888667636679692199393835,0.1691565193950025381893120790303599622116,0.1691565193950025381893120790303599622116,0.1495959888165767320815017305474785489704,0.1495959888165767320815017305474785489704,0.1246289712555338720524762821920164201448,0.1246289712555338720524762821920164201448,0.0951585116824927848099251076022462263552,0.0951585116824927848099251076022462263552,0.0622535239386478928628438369943776942749,0.0622535239386478928628438369943776942749,0.0271524594117540948517805724560181035122,0.0271524594117540948517805724560181035122],
|
|
2539
|
-
[0.1794464703562065254582656442618856214487,0.1765627053669926463252709901131972391509,0.1765627053669926463252709901131972391509,0.1680041021564500445099706637883231550211,0.1680041021564500445099706637883231550211,0.1540457610768102880814315948019586119404,0.1540457610768102880814315948019586119404,0.1351363684685254732863199817023501973721,0.1351363684685254732863199817023501973721,0.1118838471934039710947883856263559267358,0.1118838471934039710947883856263559267358,0.0850361483171791808835353701910620738504,0.0850361483171791808835353701910620738504,0.0554595293739872011294401653582446605128,0.0554595293739872011294401653582446605128,0.0241483028685479319601100262875653246916,0.0241483028685479319601100262875653246916],
|
|
2540
|
-
[0.1691423829631435918406564701349866103341,0.1691423829631435918406564701349866103341,0.1642764837458327229860537764659275904123,0.1642764837458327229860537764659275904123,0.1546846751262652449254180038363747721932,0.1546846751262652449254180038363747721932,0.1406429146706506512047313037519472280955,0.1406429146706506512047313037519472280955,0.1225552067114784601845191268002015552281,0.1225552067114784601845191268002015552281,0.1009420441062871655628139849248346070628,0.1009420441062871655628139849248346070628,0.0764257302548890565291296776166365256053,0.0764257302548890565291296776166365256053,0.0497145488949697964533349462026386416808,0.0497145488949697964533349462026386416808,0.0216160135264833103133427102664524693876,0.0216160135264833103133427102664524693876],
|
|
2541
|
-
[0.1610544498487836959791636253209167350399,0.1589688433939543476499564394650472016787,0.1589688433939543476499564394650472016787,0.1527660420658596667788554008976629984610,0.1527660420658596667788554008976629984610,0.1426067021736066117757461094419029724756,0.1426067021736066117757461094419029724756,0.1287539625393362276755157848568771170558,0.1287539625393362276755157848568771170558,0.1115666455473339947160239016817659974813,0.1115666455473339947160239016817659974813,0.0914900216224499994644620941238396526609,0.0914900216224499994644620941238396526609,0.0690445427376412265807082580060130449618,0.0690445427376412265807082580060130449618,0.0448142267656996003328381574019942119517,0.0448142267656996003328381574019942119517,0.0194617882297264770363120414644384357529,0.0194617882297264770363120414644384357529],
|
|
2542
|
-
[0.1527533871307258506980843319550975934919,0.1527533871307258506980843319550975934919,0.1491729864726037467878287370019694366926,0.1491729864726037467878287370019694366926,0.1420961093183820513292983250671649330345,0.1420961093183820513292983250671649330345,0.1316886384491766268984944997481631349161,0.1316886384491766268984944997481631349161,0.1181945319615184173123773777113822870050,0.1181945319615184173123773777113822870050,0.1019301198172404350367501354803498761666,0.1019301198172404350367501354803498761666,0.0832767415767047487247581432220462061001,0.0832767415767047487247581432220462061001,0.0626720483341090635695065351870416063516,0.0626720483341090635695065351870416063516,0.0406014298003869413310399522749321098790,0.0406014298003869413310399522749321098790,0.0176140071391521183118619623518528163621,0.0176140071391521183118619623518528163621],
|
|
2543
|
-
[0.1460811336496904271919851476833711882448,0.1445244039899700590638271665537525436099,0.1445244039899700590638271665537525436099,0.1398873947910731547221334238675831108927,0.1398873947910731547221334238675831108927,0.1322689386333374617810525744967756043290,0.1322689386333374617810525744967756043290,0.1218314160537285341953671771257335983563,0.1218314160537285341953671771257335983563,0.1087972991671483776634745780701056420336,0.1087972991671483776634745780701056420336,0.0934444234560338615532897411139320884835,0.0934444234560338615532897411139320884835,0.0761001136283793020170516533001831792261,0.0761001136283793020170516533001831792261,0.0571344254268572082836358264724479574912,0.0571344254268572082836358264724479574912,0.0369537897708524937999506682993296661889,0.0369537897708524937999506682993296661889,0.0160172282577743333242246168584710152658,0.0160172282577743333242246168584710152658],
|
|
2544
|
-
[0.1392518728556319933754102483418099578739,0.1392518728556319933754102483418099578739,0.1365414983460151713525738312315173965863,0.1365414983460151713525738312315173965863,0.1311735047870623707329649925303074458757,0.1311735047870623707329649925303074458757,0.1232523768105124242855609861548144719594,0.1232523768105124242855609861548144719594,0.1129322960805392183934006074217843191142,0.1129322960805392183934006074217843191142,0.1004141444428809649320788378305362823508,0.1004141444428809649320788378305362823508,0.0859416062170677274144436813727028661891,0.0859416062170677274144436813727028661891,0.0697964684245204880949614189302176573987,0.0697964684245204880949614189302176573987,0.0522933351526832859403120512732112561121,0.0522933351526832859403120512732112561121,0.0337749015848141547933022468659129013491,0.0337749015848141547933022468659129013491,0.0146279952982722006849910980471854451902,0.0146279952982722006849910980471854451902],
|
|
2545
|
-
[0.1336545721861061753514571105458443385831,0.1324620394046966173716424647033169258050,0.1324620394046966173716424647033169258050,0.1289057221880821499785953393997936532597,0.1289057221880821499785953393997936532597,0.1230490843067295304675784006720096548158,0.1230490843067295304675784006720096548158,0.1149966402224113649416435129339613014914,0.1149966402224113649416435129339613014914,0.1048920914645414100740861850147438548584,0.1048920914645414100740861850147438548584,0.0929157660600351474770186173697646486034,0.0929157660600351474770186173697646486034,0.0792814117767189549228925247420432269137,0.0792814117767189549228925247420432269137,0.0642324214085258521271696151589109980391,0.0642324214085258521271696151589109980391,0.0480376717310846685716410716320339965612,0.0480376717310846685716410716320339965612,0.0309880058569794443106942196418845053837,0.0309880058569794443106942196418845053837,0.0134118594871417720813094934586150649766,0.0134118594871417720813094934586150649766],
|
|
2546
|
-
[0.1279381953467521569740561652246953718517,0.1279381953467521569740561652246953718517,0.1258374563468282961213753825111836887264,0.1258374563468282961213753825111836887264,0.1216704729278033912044631534762624256070,0.1216704729278033912044631534762624256070,0.1155056680537256013533444839067835598622,0.1155056680537256013533444839067835598622,0.1074442701159656347825773424466062227946,0.1074442701159656347825773424466062227946,0.0976186521041138882698806644642471544279,0.0976186521041138882698806644642471544279,0.0861901615319532759171852029837426671850,0.0861901615319532759171852029837426671850,0.0733464814110803057340336152531165181193,0.0733464814110803057340336152531165181193,0.0592985849154367807463677585001085845412,0.0592985849154367807463677585001085845412,0.0442774388174198061686027482113382288593,0.0442774388174198061686027482113382288593,0.0285313886289336631813078159518782864491,0.0285313886289336631813078159518782864491,0.0123412297999871995468056670700372915759,0.0123412297999871995468056670700372915759]
|
|
2547
|
-
];
|
|
2548
|
-
|
|
2549
|
-
// LUT for binomial coefficient arrays per curve order 'n'
|
|
2550
|
-
var binomialCoefficients = [[1], [1, 1], [1, 2, 1], [1, 3, 3, 1]];
|
|
2551
|
-
|
|
2552
|
-
// Look up what the binomial coefficient is for pair {n,k}
|
|
2553
|
-
function binomials(n, k) {
|
|
2554
|
-
return binomialCoefficients[n][k];
|
|
2555
|
-
}
|
|
2556
|
-
|
|
2557
|
-
/**
|
|
2558
|
-
* Compute the curve derivative (hodograph) at t.
|
|
2559
|
-
*/
|
|
2560
|
-
function getDerivative(derivative, t, vs) {
|
|
2561
|
-
// the derivative of any 't'-less function is zero.
|
|
2562
|
-
var n = vs.length - 1,
|
|
2563
|
-
_vs,
|
|
2564
|
-
value,
|
|
2565
|
-
k;
|
|
2566
|
-
if (n === 0) {
|
|
2567
|
-
return 0;
|
|
2568
|
-
}
|
|
2569
|
-
|
|
2570
|
-
// direct values? compute!
|
|
2571
|
-
if (derivative === 0) {
|
|
2572
|
-
value = 0;
|
|
2573
|
-
for (k = 0; k <= n; k++) {
|
|
2574
|
-
value += binomials(n, k) * Math.pow(1 - t, n - k) * Math.pow(t, k) * vs[k];
|
|
2575
|
-
}
|
|
2576
|
-
return value;
|
|
2577
|
-
} else {
|
|
2578
|
-
// Still some derivative? go down one order, then try
|
|
2579
|
-
// for the lower order curve's.
|
|
2580
|
-
_vs = new Array(n);
|
|
2581
|
-
for (k = 0; k < n; k++) {
|
|
2582
|
-
_vs[k] = n * (vs[k + 1] - vs[k]);
|
|
2583
|
-
}
|
|
2584
|
-
return getDerivative(derivative - 1, t, _vs);
|
|
2585
|
-
}
|
|
2586
|
-
}
|
|
2587
|
-
|
|
2588
|
-
function B(xs, ys, t) {
|
|
2589
|
-
var xbase = getDerivative(1, t, xs);
|
|
2590
|
-
var ybase = getDerivative(1, t, ys);
|
|
2591
|
-
var combined = xbase * xbase + ybase * ybase;
|
|
2592
|
-
return Math.sqrt(combined);
|
|
2593
|
-
}
|
|
2594
|
-
|
|
2595
|
-
function getCubicArcLength(xs, ys, t) {
|
|
2596
|
-
var z, sum, i, correctedT;
|
|
2597
|
-
|
|
2598
|
-
/*if (xs.length >= tValues.length) {
|
|
2599
|
-
throw new Error('too high n bezier');
|
|
2600
|
-
}*/
|
|
2601
|
-
|
|
2602
|
-
if (t === undefined) {
|
|
2603
|
-
t = 1;
|
|
2604
|
-
}
|
|
2605
|
-
var n = 20;
|
|
2606
|
-
|
|
2607
|
-
z = t / 2;
|
|
2608
|
-
sum = 0;
|
|
2609
|
-
for (i = 0; i < n; i++) {
|
|
2610
|
-
correctedT = z * tValues[n][i] + z;
|
|
2611
|
-
sum += cValues[n][i] * B(xs, ys, correctedT);
|
|
2612
|
-
}
|
|
2613
|
-
return z * sum;
|
|
2614
|
-
}
|
|
2615
|
-
|
|
2616
|
-
//This file is taken from the following project: https://github.com/fontello/svgpath
|
|
2617
|
-
// Convert an arc to a sequence of cubic bézier curves
|
|
2618
|
-
//
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
var TAU = Math.PI * 2;
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
/* eslint-disable space-infix-ops */
|
|
2625
|
-
|
|
2626
|
-
// Calculate an angle between two unit vectors
|
|
2627
|
-
//
|
|
2628
|
-
// Since we measure angle between radii of circular arcs,
|
|
2629
|
-
// we can use simplified math (without length normalization)
|
|
2630
|
-
//
|
|
2631
|
-
function unit_vector_angle(ux, uy, vx, vy) {
|
|
2632
|
-
var sign = (ux * vy - uy * vx < 0) ? -1 : 1;
|
|
2633
|
-
var dot = ux * vx + uy * vy;
|
|
2634
|
-
|
|
2635
|
-
// Add this to work with arbitrary vectors:
|
|
2636
|
-
// dot /= Math.sqrt(ux * ux + uy * uy) * Math.sqrt(vx * vx + vy * vy);
|
|
2637
|
-
|
|
2638
|
-
// rounding errors, e.g. -1.0000000000000002 can screw up this
|
|
2639
|
-
if (dot > 1.0) { dot = 1.0; }
|
|
2640
|
-
if (dot < -1) { dot = -1; }
|
|
2641
|
-
|
|
2642
|
-
return sign * Math.acos(dot);
|
|
2643
|
-
}
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
// Convert from endpoint to center parameterization,
|
|
2647
|
-
// see http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
|
|
2648
|
-
//
|
|
2649
|
-
// Return [cx, cy, theta1, delta_theta]
|
|
2650
|
-
//
|
|
2651
|
-
function get_arc_center(x1, y1, x2, y2, fa, fs, rx, ry, sin_phi, cos_phi) {
|
|
2652
|
-
// Step 1.
|
|
2653
|
-
//
|
|
2654
|
-
// Moving an ellipse so origin will be the middlepoint between our two
|
|
2655
|
-
// points. After that, rotate it to line up ellipse axes with coordinate
|
|
2656
|
-
// axes.
|
|
2657
|
-
//
|
|
2658
|
-
var x1p = cos_phi*(x1-x2)/2 + sin_phi*(y1-y2)/2;
|
|
2659
|
-
var y1p = -sin_phi*(x1-x2)/2 + cos_phi*(y1-y2)/2;
|
|
2660
|
-
|
|
2661
|
-
var rx_sq = rx * rx;
|
|
2662
|
-
var ry_sq = ry * ry;
|
|
2663
|
-
var x1p_sq = x1p * x1p;
|
|
2664
|
-
var y1p_sq = y1p * y1p;
|
|
2665
|
-
|
|
2666
|
-
// Step 2.
|
|
2667
|
-
//
|
|
2668
|
-
// Compute coordinates of the centre of this ellipse (cx', cy')
|
|
2669
|
-
// in the new coordinate system.
|
|
2670
|
-
//
|
|
2671
|
-
var radicant = (rx_sq * ry_sq) - (rx_sq * y1p_sq) - (ry_sq * x1p_sq);
|
|
2672
|
-
|
|
2673
|
-
if (radicant < 0) {
|
|
2674
|
-
// due to rounding errors it might be e.g. -1.3877787807814457e-17
|
|
2675
|
-
radicant = 0;
|
|
2676
|
-
}
|
|
2677
|
-
|
|
2678
|
-
radicant /= (rx_sq * y1p_sq) + (ry_sq * x1p_sq);
|
|
2679
|
-
radicant = Math.sqrt(radicant) * (fa === fs ? -1 : 1);
|
|
2680
|
-
|
|
2681
|
-
var cxp = radicant * rx/ry * y1p;
|
|
2682
|
-
var cyp = radicant * -ry/rx * x1p;
|
|
2683
|
-
|
|
2684
|
-
// Step 3.
|
|
2685
|
-
//
|
|
2686
|
-
// Transform back to get centre coordinates (cx, cy) in the original
|
|
2687
|
-
// coordinate system.
|
|
2688
|
-
//
|
|
2689
|
-
var cx = cos_phi*cxp - sin_phi*cyp + (x1+x2)/2;
|
|
2690
|
-
var cy = sin_phi*cxp + cos_phi*cyp + (y1+y2)/2;
|
|
2691
|
-
|
|
2692
|
-
// Step 4.
|
|
2693
|
-
//
|
|
2694
|
-
// Compute angles (theta1, delta_theta).
|
|
2695
|
-
//
|
|
2696
|
-
var v1x = (x1p - cxp) / rx;
|
|
2697
|
-
var v1y = (y1p - cyp) / ry;
|
|
2698
|
-
var v2x = (-x1p - cxp) / rx;
|
|
2699
|
-
var v2y = (-y1p - cyp) / ry;
|
|
2700
|
-
|
|
2701
|
-
var theta1 = unit_vector_angle(1, 0, v1x, v1y);
|
|
2702
|
-
var delta_theta = unit_vector_angle(v1x, v1y, v2x, v2y);
|
|
2703
|
-
|
|
2704
|
-
if (fs === 0 && delta_theta > 0) {
|
|
2705
|
-
delta_theta -= TAU;
|
|
2706
|
-
}
|
|
2707
|
-
if (fs === 1 && delta_theta < 0) {
|
|
2708
|
-
delta_theta += TAU;
|
|
2709
|
-
}
|
|
2710
|
-
|
|
2711
|
-
return [ cx, cy, theta1, delta_theta ];
|
|
2712
|
-
}
|
|
2713
|
-
|
|
2714
|
-
//
|
|
2715
|
-
// Approximate one unit arc segment with bézier curves,
|
|
2716
|
-
// see http://math.stackexchange.com/questions/873224
|
|
2717
|
-
//
|
|
2718
|
-
function approximate_unit_arc(theta1, delta_theta) {
|
|
2719
|
-
var alpha = 4/3 * Math.tan(delta_theta/4);
|
|
2720
|
-
|
|
2721
|
-
var x1 = Math.cos(theta1);
|
|
2722
|
-
var y1 = Math.sin(theta1);
|
|
2723
|
-
var x2 = Math.cos(theta1 + delta_theta);
|
|
2724
|
-
var y2 = Math.sin(theta1 + delta_theta);
|
|
2725
|
-
|
|
2726
|
-
return [ x1, y1, x1 - y1*alpha, y1 + x1*alpha, x2 + y2*alpha, y2 - x2*alpha, x2, y2 ];
|
|
2727
|
-
}
|
|
2728
|
-
|
|
2729
|
-
function a2c(x1, y1, rx, ry, phi, fa, fs, x2, y2) {
|
|
2730
|
-
var sin_phi = Math.sin(phi * TAU / 360);
|
|
2731
|
-
var cos_phi = Math.cos(phi * TAU / 360);
|
|
2732
|
-
|
|
2733
|
-
// Make sure radii are valid
|
|
2734
|
-
//
|
|
2735
|
-
var x1p = cos_phi*(x1-x2)/2 + sin_phi*(y1-y2)/2;
|
|
2736
|
-
var y1p = -sin_phi*(x1-x2)/2 + cos_phi*(y1-y2)/2;
|
|
2737
|
-
|
|
2738
|
-
if (x1p === 0 && y1p === 0) {
|
|
2739
|
-
// we're asked to draw line to itself
|
|
2740
|
-
return [];
|
|
2741
|
-
}
|
|
2742
|
-
|
|
2743
|
-
if (rx === 0 || ry === 0) {
|
|
2744
|
-
// one of the radii is zero
|
|
2745
|
-
return [];
|
|
2746
|
-
}
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
// Compensate out-of-range radii
|
|
2750
|
-
//
|
|
2751
|
-
rx = Math.abs(rx);
|
|
2752
|
-
ry = Math.abs(ry);
|
|
2753
|
-
|
|
2754
|
-
var lambda = (x1p * x1p) / (rx * rx) + (y1p * y1p) / (ry * ry);
|
|
2755
|
-
if (lambda > 1) {
|
|
2756
|
-
rx *= Math.sqrt(lambda);
|
|
2757
|
-
ry *= Math.sqrt(lambda);
|
|
2758
|
-
}
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
// Get center parameters (cx, cy, theta1, delta_theta)
|
|
2762
|
-
//
|
|
2763
|
-
var cc = get_arc_center(x1, y1, x2, y2, fa, fs, rx, ry, sin_phi, cos_phi);
|
|
2764
|
-
|
|
2765
|
-
var result = [];
|
|
2766
|
-
var theta1 = cc[2];
|
|
2767
|
-
var delta_theta = cc[3];
|
|
2768
|
-
|
|
2769
|
-
// Split an arc to multiple segments, so each segment
|
|
2770
|
-
// will be less than τ/4 (= 90°)
|
|
2771
|
-
//
|
|
2772
|
-
var segments = Math.max(Math.ceil(Math.abs(delta_theta) / (TAU / 4)), 1);
|
|
2773
|
-
delta_theta /= segments;
|
|
2774
|
-
|
|
2775
|
-
for (var i = 0; i < segments; i++) {
|
|
2776
|
-
result.push(approximate_unit_arc(theta1, delta_theta));
|
|
2777
|
-
theta1 += delta_theta;
|
|
2778
|
-
}
|
|
2779
|
-
|
|
2780
|
-
// We have a bezier approximation of a unit circle,
|
|
2781
|
-
// now need to transform back to the original ellipse
|
|
2782
|
-
//
|
|
2783
|
-
return result.map(function (curve) {
|
|
2784
|
-
for (var i = 0; i < curve.length; i += 2) {
|
|
2785
|
-
var x = curve[i + 0];
|
|
2786
|
-
var y = curve[i + 1];
|
|
2787
|
-
|
|
2788
|
-
// scale
|
|
2789
|
-
x *= rx;
|
|
2790
|
-
y *= ry;
|
|
2791
|
-
|
|
2792
|
-
// rotate
|
|
2793
|
-
var xp = cos_phi*x - sin_phi*y;
|
|
2794
|
-
var yp = sin_phi*x + cos_phi*y;
|
|
2795
|
-
|
|
2796
|
-
// translate
|
|
2797
|
-
curve[i + 0] = xp + cc[0];
|
|
2798
|
-
curve[i + 1] = yp + cc[1];
|
|
2799
|
-
}
|
|
2800
|
-
|
|
2801
|
-
return curve;
|
|
2802
|
-
});
|
|
2803
|
-
}
|
|
2804
|
-
|
|
2805
|
-
//Calculate ans Arc curve length and positionAtLength
|
|
2806
|
-
//Definitions taken from https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
function Arc(x0, y0, rx,ry, xAxisRotate, LargeArcFlag,SweepFlag, x,y) {
|
|
2810
|
-
return new Arc$1(x0, y0, rx,ry, xAxisRotate, LargeArcFlag,SweepFlag, x,y);
|
|
2811
|
-
}
|
|
2812
|
-
|
|
2813
|
-
function Arc$1(x0, y0,rx,ry, xAxisRotate, LargeArcFlag,SweepFlag,x,y) {
|
|
2814
|
-
var length = 0;
|
|
2815
|
-
var partialLengths = [];
|
|
2816
|
-
var curves = [];
|
|
2817
|
-
var res = a2c(x0, y0,rx,ry, xAxisRotate, LargeArcFlag,SweepFlag,x,y);
|
|
2818
|
-
res.forEach(function(d){
|
|
2819
|
-
var curve = new Bezier(d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7]);
|
|
2820
|
-
var curveLength = curve.getTotalLength();
|
|
2821
|
-
length += curveLength;
|
|
2822
|
-
partialLengths.push(curveLength);
|
|
2823
|
-
curves.push(curve);
|
|
2824
|
-
});
|
|
2825
|
-
this.length = length;
|
|
2826
|
-
this.partialLengths = partialLengths;
|
|
2827
|
-
this.curves = curves;
|
|
2828
|
-
}
|
|
2829
|
-
|
|
2830
|
-
Arc$1.prototype = {
|
|
2831
|
-
constructor: Arc$1,
|
|
2832
|
-
init: function() {
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
},
|
|
2836
|
-
|
|
2837
|
-
getTotalLength: function() {
|
|
2838
|
-
return this.length;
|
|
2839
|
-
},
|
|
2840
|
-
getPointAtLength: function(fractionLength) {
|
|
2841
|
-
|
|
2842
|
-
if(fractionLength < 0){
|
|
2843
|
-
fractionLength = 0;
|
|
2844
|
-
} else if(fractionLength > this.length){
|
|
2845
|
-
fractionLength = this.length;
|
|
2846
|
-
}
|
|
2847
|
-
var i = this.partialLengths.length - 1;
|
|
2848
|
-
|
|
2849
|
-
while(this.partialLengths[i] >= fractionLength && this.partialLengths[i] > 0){
|
|
2850
|
-
i--;
|
|
2851
|
-
}
|
|
2852
|
-
if(i<this.partialLengths.length-1){
|
|
2853
|
-
i++;
|
|
2854
|
-
}
|
|
2855
|
-
|
|
2856
|
-
var lengthOffset = 0;
|
|
2857
|
-
for(var j=0; j<i; j++){
|
|
2858
|
-
lengthOffset += this.partialLengths[j];
|
|
2859
|
-
}
|
|
2860
|
-
|
|
2861
|
-
return this.curves[i].getPointAtLength(fractionLength - lengthOffset);
|
|
2862
|
-
},
|
|
2863
|
-
getTangentAtLength: function(fractionLength) {
|
|
2864
|
-
if(fractionLength < 0){
|
|
2865
|
-
fractionLength = 0;
|
|
2866
|
-
} else if(fractionLength > this.length){
|
|
2867
|
-
fractionLength = this.length;
|
|
2868
|
-
}
|
|
2869
|
-
var i = this.partialLengths.length - 1;
|
|
2870
|
-
|
|
2871
|
-
while(this.partialLengths[i] >= fractionLength && this.partialLengths[i] > 0){
|
|
2872
|
-
i--;
|
|
2873
|
-
}
|
|
2874
|
-
if(i<this.partialLengths.length-1){
|
|
2875
|
-
i++;
|
|
2876
|
-
}
|
|
2877
|
-
|
|
2878
|
-
var lengthOffset = 0;
|
|
2879
|
-
for(var j=0; j<i; j++){
|
|
2880
|
-
lengthOffset += this.partialLengths[j];
|
|
2881
|
-
}
|
|
2882
|
-
|
|
2883
|
-
return this.curves[i].getTangentAtLength(fractionLength - lengthOffset);
|
|
2884
|
-
},
|
|
2885
|
-
getPropertiesAtLength: function(fractionLength){
|
|
2886
|
-
var tangent = this.getTangentAtLength(fractionLength);
|
|
2887
|
-
var point = this.getPointAtLength(fractionLength);
|
|
2888
|
-
return {x: point.x, y: point.y, tangentX: tangent.x, tangentY: tangent.y};
|
|
2889
|
-
}
|
|
2890
|
-
};
|
|
2891
|
-
|
|
2892
|
-
function LinearPosition(x0, x1, y0, y1) {
|
|
2893
|
-
return new LinearPosition$1(x0, x1, y0, y1);
|
|
2894
|
-
|
|
2895
|
-
}
|
|
2896
|
-
|
|
2897
|
-
function LinearPosition$1(x0, x1, y0, y1){
|
|
2898
|
-
this.x0 = x0;
|
|
2899
|
-
this.x1 = x1;
|
|
2900
|
-
this.y0 = y0;
|
|
2901
|
-
this.y1 = y1;
|
|
2902
|
-
}
|
|
2903
|
-
|
|
2904
|
-
LinearPosition$1.prototype.getTotalLength = function(){
|
|
2905
|
-
return Math.sqrt(Math.pow(this.x0 - this.x1, 2) +
|
|
2906
|
-
Math.pow(this.y0 - this.y1, 2));
|
|
2907
|
-
};
|
|
2908
|
-
|
|
2909
|
-
LinearPosition$1.prototype.getPointAtLength = function(pos){
|
|
2910
|
-
var fraction = pos/ (Math.sqrt(Math.pow(this.x0 - this.x1, 2) +
|
|
2911
|
-
Math.pow(this.y0 - this.y1, 2)));
|
|
2912
|
-
|
|
2913
|
-
var newDeltaX = (this.x1 - this.x0)*fraction;
|
|
2914
|
-
var newDeltaY = (this.y1 - this.y0)*fraction;
|
|
2915
|
-
return { x: this.x0 + newDeltaX, y: this.y0 + newDeltaY };
|
|
2916
|
-
};
|
|
2917
|
-
LinearPosition$1.prototype.getTangentAtLength = function(){
|
|
2918
|
-
var module = Math.sqrt((this.x1 - this.x0) * (this.x1 - this.x0) +
|
|
2919
|
-
(this.y1 - this.y0) * (this.y1 - this.y0));
|
|
2920
|
-
return { x: (this.x1 - this.x0)/module, y: (this.y1 - this.y0)/module };
|
|
2921
|
-
};
|
|
2922
|
-
LinearPosition$1.prototype.getPropertiesAtLength = function(pos){
|
|
2923
|
-
var point = this.getPointAtLength(pos);
|
|
2924
|
-
var tangent = this.getTangentAtLength();
|
|
2925
|
-
return {x: point.x, y: point.y, tangentX: tangent.x, tangentY: tangent.y};
|
|
2926
|
-
};
|
|
2927
|
-
|
|
2928
|
-
function svgPathProperties(svgString) {
|
|
2929
|
-
var length = 0;
|
|
2930
|
-
var partial_lengths = [];
|
|
2931
|
-
var functions = [];
|
|
2932
|
-
|
|
2933
|
-
function svgProperties(string){
|
|
2934
|
-
if(!string){return null;}
|
|
2935
|
-
var parsed = parse$1(string);
|
|
2936
|
-
var cur = [0, 0];
|
|
2937
|
-
var prev_point = [0, 0];
|
|
2938
|
-
var curve;
|
|
2939
|
-
var ringStart;
|
|
2940
|
-
for (var i = 0; i < parsed.length; i++){
|
|
2941
|
-
//moveTo
|
|
2942
|
-
if(parsed[i][0] === "M"){
|
|
2943
|
-
cur = [parsed[i][1], parsed[i][2]];
|
|
2944
|
-
ringStart = [cur[0], cur[1]];
|
|
2945
|
-
functions.push(null);
|
|
2946
|
-
} else if(parsed[i][0] === "m"){
|
|
2947
|
-
cur = [parsed[i][1] + cur[0], parsed[i][2] + cur[1]];
|
|
2948
|
-
ringStart = [cur[0], cur[1]];
|
|
2949
|
-
functions.push(null);
|
|
2950
|
-
}
|
|
2951
|
-
//lineTo
|
|
2952
|
-
else if(parsed[i][0] === "L"){
|
|
2953
|
-
length = length + Math.sqrt(Math.pow(cur[0] - parsed[i][1], 2) + Math.pow(cur[1] - parsed[i][2], 2));
|
|
2954
|
-
functions.push(new LinearPosition(cur[0], parsed[i][1], cur[1], parsed[i][2]));
|
|
2955
|
-
cur = [parsed[i][1], parsed[i][2]];
|
|
2956
|
-
} else if(parsed[i][0] === "l"){
|
|
2957
|
-
length = length + Math.sqrt(Math.pow(parsed[i][1], 2) + Math.pow(parsed[i][2], 2));
|
|
2958
|
-
functions.push(new LinearPosition(cur[0], parsed[i][1] + cur[0], cur[1], parsed[i][2] + cur[1]));
|
|
2959
|
-
cur = [parsed[i][1] + cur[0], parsed[i][2] + cur[1]];
|
|
2960
|
-
} else if(parsed[i][0] === "H"){
|
|
2961
|
-
length = length + Math.abs(cur[0] - parsed[i][1]);
|
|
2962
|
-
functions.push(new LinearPosition(cur[0], parsed[i][1], cur[1], cur[1]));
|
|
2963
|
-
cur[0] = parsed[i][1];
|
|
2964
|
-
} else if(parsed[i][0] === "h"){
|
|
2965
|
-
length = length + Math.abs(parsed[i][1]);
|
|
2966
|
-
functions.push(new LinearPosition(cur[0], cur[0] + parsed[i][1], cur[1], cur[1]));
|
|
2967
|
-
cur[0] = parsed[i][1] + cur[0];
|
|
2968
|
-
} else if(parsed[i][0] === "V"){
|
|
2969
|
-
length = length + Math.abs(cur[1] - parsed[i][1]);
|
|
2970
|
-
functions.push(new LinearPosition(cur[0], cur[0], cur[1], parsed[i][1]));
|
|
2971
|
-
cur[1] = parsed[i][1];
|
|
2972
|
-
} else if(parsed[i][0] === "v"){
|
|
2973
|
-
length = length + Math.abs(parsed[i][1]);
|
|
2974
|
-
functions.push(new LinearPosition(cur[0], cur[0], cur[1], cur[1] + parsed[i][1]));
|
|
2975
|
-
cur[1] = parsed[i][1] + cur[1];
|
|
2976
|
-
//Close path
|
|
2977
|
-
} else if(parsed[i][0] === "z" || parsed[i][0] === "Z"){
|
|
2978
|
-
length = length + Math.sqrt(Math.pow(ringStart[0] - cur[0], 2) + Math.pow(ringStart[1] - cur[1], 2));
|
|
2979
|
-
functions.push(new LinearPosition(cur[0], ringStart[0], cur[1], ringStart[1]));
|
|
2980
|
-
cur = [ringStart[0], ringStart[1]];
|
|
2981
|
-
}
|
|
2982
|
-
//Cubic Bezier curves
|
|
2983
|
-
else if(parsed[i][0] === "C"){
|
|
2984
|
-
curve = new Bezier(cur[0], cur[1] , parsed[i][1], parsed[i][2] , parsed[i][3], parsed[i][4] , parsed[i][5], parsed[i][6]);
|
|
2985
|
-
length = length + curve.getTotalLength();
|
|
2986
|
-
cur = [parsed[i][5], parsed[i][6]];
|
|
2987
|
-
functions.push(curve);
|
|
2988
|
-
} else if(parsed[i][0] === "c"){
|
|
2989
|
-
curve = new Bezier(cur[0], cur[1] , cur[0] + parsed[i][1], cur[1] + parsed[i][2] , cur[0] + parsed[i][3], cur[1] + parsed[i][4] , cur[0] + parsed[i][5], cur[1] + parsed[i][6]);
|
|
2990
|
-
length = length + curve.getTotalLength();
|
|
2991
|
-
cur = [parsed[i][5] + cur[0], parsed[i][6] + cur[1]];
|
|
2992
|
-
functions.push(curve);
|
|
2993
|
-
} else if(parsed[i][0] === "S"){
|
|
2994
|
-
if(i>0 && ["C","c","S","s"].indexOf(parsed[i-1][0]) > -1){
|
|
2995
|
-
curve = new Bezier(cur[0], cur[1] , 2*cur[0] - parsed[i-1][parsed[i-1].length - 4], 2*cur[1] - parsed[i-1][parsed[i-1].length - 3], parsed[i][1], parsed[i][2] , parsed[i][3], parsed[i][4]);
|
|
2996
|
-
} else {
|
|
2997
|
-
curve = new Bezier(cur[0], cur[1] , cur[0], cur[1], parsed[i][1], parsed[i][2] , parsed[i][3], parsed[i][4]);
|
|
2998
|
-
}
|
|
2999
|
-
length = length + curve.getTotalLength();
|
|
3000
|
-
cur = [parsed[i][3], parsed[i][4]];
|
|
3001
|
-
functions.push(curve);
|
|
3002
|
-
} else if(parsed[i][0] === "s"){ //240 225
|
|
3003
|
-
if(i>0 && ["C","c","S","s"].indexOf(parsed[i-1][0]) > -1){
|
|
3004
|
-
curve = new Bezier(cur[0], cur[1] , cur[0] + curve.d.x - curve.c.x, cur[1] + curve.d.y - curve.c.y, cur[0] + parsed[i][1], cur[1] + parsed[i][2] , cur[0] + parsed[i][3], cur[1] + parsed[i][4]);
|
|
3005
|
-
} else {
|
|
3006
|
-
curve = new Bezier(cur[0], cur[1] , cur[0], cur[1], cur[0] + parsed[i][1], cur[1] + parsed[i][2] , cur[0] + parsed[i][3], cur[1] + parsed[i][4]);
|
|
3007
|
-
}
|
|
3008
|
-
length = length + curve.getTotalLength();
|
|
3009
|
-
cur = [parsed[i][3] + cur[0], parsed[i][4] + cur[1]];
|
|
3010
|
-
functions.push(curve);
|
|
3011
|
-
}
|
|
3012
|
-
//Quadratic Bezier curves
|
|
3013
|
-
else if(parsed[i][0] === "Q"){
|
|
3014
|
-
if(cur[0] != parsed[i][1] && cur[1] != parsed[i][2]){
|
|
3015
|
-
curve = new Bezier(cur[0], cur[1] , parsed[i][1], parsed[i][2] , parsed[i][3], parsed[i][4]);
|
|
3016
|
-
} else {
|
|
3017
|
-
curve = new LinearPosition(parsed[i][1], parsed[i][3], parsed[i][2], parsed[i][4]);
|
|
3018
|
-
}
|
|
3019
|
-
length = length + curve.getTotalLength();
|
|
3020
|
-
functions.push(curve);
|
|
3021
|
-
cur = [parsed[i][3], parsed[i][4]];
|
|
3022
|
-
prev_point = [parsed[i][1], parsed[i][2]];
|
|
3023
|
-
|
|
3024
|
-
} else if(parsed[i][0] === "q"){
|
|
3025
|
-
if(!(parsed[i][1] == 0 && parsed[i][2] == 0)){
|
|
3026
|
-
curve = new Bezier(cur[0], cur[1] , cur[0] + parsed[i][1], cur[1] + parsed[i][2] , cur[0] + parsed[i][3], cur[1] + parsed[i][4]);
|
|
3027
|
-
} else {
|
|
3028
|
-
curve = new LinearPosition(cur[0] + parsed[i][1], cur[0] + parsed[i][3], cur[1] + parsed[i][2], cur[1] + parsed[i][4]);
|
|
3029
|
-
}
|
|
3030
|
-
length = length + curve.getTotalLength();
|
|
3031
|
-
prev_point = [cur[0] + parsed[i][1], cur[1] + parsed[i][2]];
|
|
3032
|
-
cur = [parsed[i][3] + cur[0], parsed[i][4] + cur[1]];
|
|
3033
|
-
functions.push(curve);
|
|
3034
|
-
} else if(parsed[i][0] === "T"){
|
|
3035
|
-
if(i>0 && ["Q","q","T","t"].indexOf(parsed[i-1][0]) > -1){
|
|
3036
|
-
curve = new Bezier(cur[0], cur[1] , 2 * cur[0] - prev_point[0] , 2 * cur[1] - prev_point[1] , parsed[i][1], parsed[i][2]);
|
|
3037
|
-
} else {
|
|
3038
|
-
curve = new LinearPosition(cur[0], parsed[i][1], cur[1], parsed[i][2]);
|
|
3039
|
-
}
|
|
3040
|
-
functions.push(curve);
|
|
3041
|
-
length = length + curve.getTotalLength();
|
|
3042
|
-
prev_point = [2 * cur[0] - prev_point[0] , 2 * cur[1] - prev_point[1]];
|
|
3043
|
-
cur = [parsed[i][1], parsed[i][2]];
|
|
3044
|
-
|
|
3045
|
-
} else if(parsed[i][0] === "t"){
|
|
3046
|
-
if(i>0 && ["Q","q","T","t"].indexOf(parsed[i-1][0]) > -1){
|
|
3047
|
-
curve = new Bezier(cur[0], cur[1] , 2 * cur[0] - prev_point[0] , 2 * cur[1] - prev_point[1] , cur[0] + parsed[i][1], cur[1] + parsed[i][2]);
|
|
3048
|
-
} else {
|
|
3049
|
-
curve = new LinearPosition(cur[0], cur[0] + parsed[i][1], cur[1], cur[1] + parsed[i][2]);
|
|
3050
|
-
}
|
|
3051
|
-
length = length + curve.getTotalLength();
|
|
3052
|
-
prev_point = [2 * cur[0] - prev_point[0] , 2 * cur[1] - prev_point[1]];
|
|
3053
|
-
cur = [parsed[i][1] + cur[0], parsed[i][2] + cur[0]];
|
|
3054
|
-
functions.push(curve);
|
|
3055
|
-
} else if(parsed[i][0] === "A"){
|
|
3056
|
-
curve = new Arc(cur[0], cur[1], parsed[i][1], parsed[i][2], parsed[i][3], parsed[i][4], parsed[i][5], parsed[i][6], parsed[i][7]);
|
|
3057
|
-
|
|
3058
|
-
length = length + curve.getTotalLength();
|
|
3059
|
-
cur = [parsed[i][6], parsed[i][7]];
|
|
3060
|
-
functions.push(curve);
|
|
3061
|
-
} else if(parsed[i][0] === "a"){
|
|
3062
|
-
curve = new Arc(cur[0], cur[1], parsed[i][1], parsed[i][2], parsed[i][3], parsed[i][4], parsed[i][5], cur[0] + parsed[i][6], cur[1] + parsed[i][7]);
|
|
3063
|
-
|
|
3064
|
-
length = length + curve.getTotalLength();
|
|
3065
|
-
cur = [cur[0] + parsed[i][6], cur[1] + parsed[i][7]];
|
|
3066
|
-
functions.push(curve);
|
|
3067
|
-
}
|
|
3068
|
-
partial_lengths.push(length);
|
|
3069
|
-
|
|
3070
|
-
}
|
|
3071
|
-
return svgProperties;
|
|
3072
|
-
}
|
|
3073
|
-
|
|
3074
|
-
svgProperties.getTotalLength = function(){
|
|
3075
|
-
return length;
|
|
3076
|
-
};
|
|
3077
|
-
|
|
3078
|
-
svgProperties.getPointAtLength = function(fractionLength){
|
|
3079
|
-
var fractionPart = getPartAtLength(fractionLength);
|
|
3080
|
-
return functions[fractionPart.i].getPointAtLength(fractionPart.fraction);
|
|
3081
|
-
};
|
|
3082
|
-
|
|
3083
|
-
svgProperties.getTangentAtLength = function(fractionLength){
|
|
3084
|
-
var fractionPart = getPartAtLength(fractionLength);
|
|
3085
|
-
return functions[fractionPart.i].getTangentAtLength(fractionPart.fraction);
|
|
3086
|
-
};
|
|
3087
|
-
|
|
3088
|
-
svgProperties.getPropertiesAtLength = function(fractionLength){
|
|
3089
|
-
var fractionPart = getPartAtLength(fractionLength);
|
|
3090
|
-
return functions[fractionPart.i].getPropertiesAtLength(fractionPart.fraction);
|
|
3091
|
-
};
|
|
3092
|
-
|
|
3093
|
-
var getPartAtLength = function(fractionLength){
|
|
3094
|
-
if(fractionLength < 0){
|
|
3095
|
-
fractionLength = 0;
|
|
3096
|
-
} else if(fractionLength > length){
|
|
3097
|
-
fractionLength = length;
|
|
3098
|
-
}
|
|
3099
|
-
|
|
3100
|
-
var i = partial_lengths.length - 1;
|
|
3101
|
-
|
|
3102
|
-
while(partial_lengths[i] >= fractionLength && partial_lengths[i] > 0){
|
|
3103
|
-
i--;
|
|
3104
|
-
}
|
|
3105
|
-
i++;
|
|
3106
|
-
return {fraction: fractionLength-partial_lengths[i-1], i: i};
|
|
3107
|
-
};
|
|
3108
|
-
|
|
3109
|
-
return svgProperties(svgString);
|
|
3110
|
-
}
|
|
3111
|
-
|
|
3112
|
-
function distance(a, b) {
|
|
3113
|
-
return Math.sqrt((a[0] - b[0]) * (a[0] - b[0]) + (a[1] - b[1]) * (a[1] - b[1]));
|
|
3114
|
-
}
|
|
3115
|
-
|
|
3116
|
-
function pointAlong(a, b, pct) {
|
|
3117
|
-
return [a[0] + (b[0] - a[0]) * pct, a[1] + (b[1] - a[1]) * pct];
|
|
3118
|
-
}
|
|
3119
|
-
|
|
3120
|
-
function samePoint(a, b) {
|
|
3121
|
-
return distance(a, b) < 1e-9;
|
|
3122
|
-
}
|
|
3123
|
-
|
|
3124
|
-
function interpolatePoints(a, b, string) {
|
|
3125
|
-
let interpolators = a.map((d, i) => interpolatePoint(d, b[i]));
|
|
3126
|
-
|
|
3127
|
-
return function(t) {
|
|
3128
|
-
let values = interpolators.map(fn => fn(t));
|
|
3129
|
-
return string ? toPathString(values) : values;
|
|
3130
|
-
};
|
|
3131
|
-
}
|
|
3132
|
-
|
|
3133
|
-
function interpolatePoint(a, b) {
|
|
3134
|
-
return function(t) {
|
|
3135
|
-
return a.map((d, i) => d + t * (b[i] - d));
|
|
3136
|
-
};
|
|
3137
|
-
}
|
|
3138
|
-
|
|
3139
|
-
function isFiniteNumber(number) {
|
|
3140
|
-
return typeof number === "number" && isFinite(number);
|
|
3141
|
-
}
|
|
3142
|
-
|
|
3143
|
-
const INVALID_INPUT = `All shapes must be supplied as arrays of [x, y] points or an SVG path string (https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d).
|
|
3144
|
-
Example valid ways of supplying a shape would be:
|
|
3145
|
-
[[0, 0], [10, 0], [10, 10]]
|
|
3146
|
-
"M0,0 L10,0 L10,10Z"
|
|
3147
|
-
`;
|
|
3148
|
-
|
|
3149
|
-
function parse(str) {
|
|
3150
|
-
return new Path(str).abs();
|
|
3151
|
-
}
|
|
3152
|
-
|
|
3153
|
-
function split(parsed) {
|
|
3154
|
-
return parsed
|
|
3155
|
-
.toString()
|
|
3156
|
-
.split("M")
|
|
3157
|
-
.map((d, i) => {
|
|
3158
|
-
d = d.trim();
|
|
3159
|
-
return i && d ? "M" + d : d;
|
|
3160
|
-
})
|
|
3161
|
-
.filter(d => d);
|
|
3162
|
-
}
|
|
3163
|
-
|
|
3164
|
-
function toPathString(ring) {
|
|
3165
|
-
return "M" + ring.join("L") + "Z";
|
|
3166
|
-
}
|
|
3167
|
-
|
|
3168
|
-
function pathStringToRing(str, maxSegmentLength) {
|
|
3169
|
-
let parsed = parse(str);
|
|
3170
|
-
|
|
3171
|
-
return exactRing(parsed) || approximateRing(parsed, maxSegmentLength);
|
|
3172
|
-
}
|
|
3173
|
-
|
|
3174
|
-
function exactRing(parsed) {
|
|
3175
|
-
let segments = parsed.segments || [],
|
|
3176
|
-
ring = [];
|
|
3177
|
-
|
|
3178
|
-
if (!segments.length || segments[0][0] !== "M") {
|
|
3179
|
-
return false;
|
|
3180
|
-
}
|
|
3181
|
-
|
|
3182
|
-
for (let i = 0; i < segments.length; i++) {
|
|
3183
|
-
let [command, x, y] = segments[i];
|
|
3184
|
-
if ((command === "M" && i) || command === "Z") {
|
|
3185
|
-
break;
|
|
3186
|
-
} else if (command === "M" || command === "L") {
|
|
3187
|
-
ring.push([x, y]);
|
|
3188
|
-
} else if (command === "H") {
|
|
3189
|
-
ring.push([x, ring[ring.length - 1][1]]);
|
|
3190
|
-
} else if (command === "V") {
|
|
3191
|
-
ring.push([ring[ring.length - 1][0], x]);
|
|
3192
|
-
} else {
|
|
3193
|
-
return false;
|
|
3194
|
-
}
|
|
3195
|
-
}
|
|
3196
|
-
|
|
3197
|
-
return ring.length ? { ring } : false;
|
|
3198
|
-
}
|
|
3199
|
-
|
|
3200
|
-
function approximateRing(parsed, maxSegmentLength) {
|
|
3201
|
-
let ringPath = split(parsed)[0],
|
|
3202
|
-
ring = [],
|
|
3203
|
-
len,
|
|
3204
|
-
m,
|
|
3205
|
-
numPoints = 3;
|
|
3206
|
-
|
|
3207
|
-
if (!ringPath) {
|
|
3208
|
-
throw new TypeError(INVALID_INPUT);
|
|
3209
|
-
}
|
|
3210
|
-
|
|
3211
|
-
m = measure(ringPath);
|
|
3212
|
-
len = m.getTotalLength();
|
|
3213
|
-
|
|
3214
|
-
if (maxSegmentLength && isFiniteNumber(maxSegmentLength) && maxSegmentLength > 0) {
|
|
3215
|
-
numPoints = Math.max(numPoints, Math.ceil(len / maxSegmentLength));
|
|
3216
|
-
}
|
|
3217
|
-
|
|
3218
|
-
for (let i = 0; i < numPoints; i++) {
|
|
3219
|
-
let p = m.getPointAtLength(len * i / numPoints);
|
|
3220
|
-
ring.push([p.x, p.y]);
|
|
3221
|
-
}
|
|
3222
|
-
|
|
3223
|
-
return {
|
|
3224
|
-
ring,
|
|
3225
|
-
skipBisect: true
|
|
3226
|
-
};
|
|
3227
|
-
}
|
|
3228
|
-
|
|
3229
|
-
function measure(d) {
|
|
3230
|
-
// Use native browser measurement if running in browser
|
|
3231
|
-
if (typeof window !== "undefined" && window && window.document) {
|
|
3232
|
-
try {
|
|
3233
|
-
let path = window.document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
3234
|
-
path.setAttributeNS(null, "d", d);
|
|
3235
|
-
return path;
|
|
3236
|
-
} catch (e) {}
|
|
3237
|
-
}
|
|
3238
|
-
// Fall back to svg-path-properties
|
|
3239
|
-
return svgPathProperties(d);
|
|
3240
|
-
}
|
|
3241
|
-
|
|
3242
|
-
function addPoints(ring, numPoints) {
|
|
3243
|
-
const desiredLength = ring.length + numPoints,
|
|
3244
|
-
step = polygonLength(ring) / numPoints;
|
|
3245
|
-
|
|
3246
|
-
let i = 0,
|
|
3247
|
-
cursor = 0,
|
|
3248
|
-
insertAt = step / 2;
|
|
3249
|
-
|
|
3250
|
-
while (ring.length < desiredLength) {
|
|
3251
|
-
let a = ring[i],
|
|
3252
|
-
b = ring[(i + 1) % ring.length],
|
|
3253
|
-
segment = distance(a, b);
|
|
3254
|
-
|
|
3255
|
-
if (insertAt <= cursor + segment) {
|
|
3256
|
-
ring.splice(i + 1, 0, segment ? pointAlong(a, b, (insertAt - cursor) / segment) : a.slice(0));
|
|
3257
|
-
insertAt += step;
|
|
3258
|
-
continue;
|
|
3259
|
-
}
|
|
3260
|
-
|
|
3261
|
-
cursor += segment;
|
|
3262
|
-
i++;
|
|
3263
|
-
}
|
|
3264
|
-
}
|
|
3265
|
-
|
|
3266
|
-
function bisect(ring, maxSegmentLength = Infinity) {
|
|
3267
|
-
for (let i = 0; i < ring.length; i++) {
|
|
3268
|
-
let a = ring[i],
|
|
3269
|
-
b = i === ring.length - 1 ? ring[0] : ring[i + 1];
|
|
3270
|
-
|
|
3271
|
-
// Could splice the whole set for a segment instead, but a bit messy
|
|
3272
|
-
while (distance(a, b) > maxSegmentLength) {
|
|
3273
|
-
b = pointAlong(a, b, 0.5);
|
|
3274
|
-
ring.splice(i + 1, 0, b);
|
|
3275
|
-
}
|
|
3276
|
-
}
|
|
3277
|
-
}
|
|
3278
|
-
|
|
3279
|
-
function normalizeRing(ring, maxSegmentLength) {
|
|
3280
|
-
let points, area, skipBisect;
|
|
3281
|
-
|
|
3282
|
-
if (typeof ring === "string") {
|
|
3283
|
-
let converted = pathStringToRing(ring, maxSegmentLength);
|
|
3284
|
-
ring = converted.ring;
|
|
3285
|
-
skipBisect = converted.skipBisect;
|
|
3286
|
-
} else if (!Array.isArray(ring)) {
|
|
3287
|
-
throw new TypeError(INVALID_INPUT);
|
|
3288
|
-
}
|
|
3289
|
-
|
|
3290
|
-
points = ring.slice(0);
|
|
3291
|
-
|
|
3292
|
-
if (!validRing(points)) {
|
|
3293
|
-
throw new TypeError(INVALID_INPUT);
|
|
3294
|
-
}
|
|
3295
|
-
|
|
3296
|
-
// TODO skip this test to avoid scale issues?
|
|
3297
|
-
// Chosen epsilon (1e-6) is problematic for small coordinate range
|
|
3298
|
-
if (points.length > 1 && samePoint(points[0], points[points.length - 1])) {
|
|
3299
|
-
points.pop();
|
|
3300
|
-
}
|
|
3301
|
-
|
|
3302
|
-
area = polygonArea(points);
|
|
3303
|
-
|
|
3304
|
-
// Make all rings clockwise
|
|
3305
|
-
if (area > 0) {
|
|
3306
|
-
points.reverse();
|
|
3307
|
-
}
|
|
3308
|
-
|
|
3309
|
-
if (
|
|
3310
|
-
!skipBisect &&
|
|
3311
|
-
maxSegmentLength &&
|
|
3312
|
-
isFiniteNumber(maxSegmentLength) &&
|
|
3313
|
-
maxSegmentLength > 0
|
|
3314
|
-
) {
|
|
3315
|
-
bisect(points, maxSegmentLength);
|
|
3316
|
-
}
|
|
3317
|
-
|
|
3318
|
-
return points;
|
|
3319
|
-
}
|
|
3320
|
-
|
|
3321
|
-
function validRing(ring) {
|
|
3322
|
-
return ring.every(function(point) {
|
|
3323
|
-
return (
|
|
3324
|
-
Array.isArray(point) &&
|
|
3325
|
-
point.length >= 2 &&
|
|
3326
|
-
isFiniteNumber(point[0]) &&
|
|
3327
|
-
isFiniteNumber(point[1])
|
|
3328
|
-
);
|
|
3329
|
-
});
|
|
3330
|
-
}
|
|
3331
|
-
|
|
3332
|
-
function rotate(ring, vs) {
|
|
3333
|
-
let len = ring.length,
|
|
3334
|
-
min = Infinity,
|
|
3335
|
-
bestOffset,
|
|
3336
|
-
sumOfSquares,
|
|
3337
|
-
spliced;
|
|
3338
|
-
|
|
3339
|
-
for (let offset = 0; offset < len; offset++) {
|
|
3340
|
-
sumOfSquares = 0;
|
|
3341
|
-
|
|
3342
|
-
vs.forEach(function(p, i){
|
|
3343
|
-
let d = distance(ring[(offset + i) % len], p);
|
|
3344
|
-
sumOfSquares += d * d;
|
|
3345
|
-
});
|
|
3346
|
-
|
|
3347
|
-
if (sumOfSquares < min) {
|
|
3348
|
-
min = sumOfSquares;
|
|
3349
|
-
bestOffset = offset;
|
|
3350
|
-
}
|
|
3351
|
-
}
|
|
3352
|
-
|
|
3353
|
-
if (bestOffset) {
|
|
3354
|
-
spliced = ring.splice(0, bestOffset);
|
|
3355
|
-
ring.splice(ring.length, 0, ...spliced);
|
|
3356
|
-
}
|
|
3357
|
-
}
|
|
3358
|
-
|
|
3359
|
-
function interpolate(fromShape, toShape, { maxSegmentLength = 10, string = true } = {}) {
|
|
3360
|
-
let fromRing = normalizeRing(fromShape, maxSegmentLength),
|
|
3361
|
-
toRing = normalizeRing(toShape, maxSegmentLength),
|
|
3362
|
-
interpolator = interpolateRing(fromRing, toRing, string);
|
|
3363
|
-
|
|
3364
|
-
// Extra optimization for near either end with path strings
|
|
3365
|
-
if (!string || (typeof fromShape !== "string" && typeof toShape !== "string")) {
|
|
3366
|
-
return interpolator;
|
|
3367
|
-
}
|
|
3368
|
-
|
|
3369
|
-
return t => {
|
|
3370
|
-
if (t < 1e-4 && typeof fromShape === "string") {
|
|
3371
|
-
return fromShape;
|
|
3372
|
-
}
|
|
3373
|
-
if (1 - t < 1e-4 && typeof toShape === "string") {
|
|
3374
|
-
return toShape;
|
|
3375
|
-
}
|
|
3376
|
-
return interpolator(t);
|
|
3377
|
-
};
|
|
3378
|
-
}
|
|
3379
|
-
|
|
3380
|
-
function interpolateRing(fromRing, toRing, string) {
|
|
3381
|
-
let diff;
|
|
3382
|
-
|
|
3383
|
-
diff = fromRing.length - toRing.length;
|
|
3384
|
-
|
|
3385
|
-
// TODO bisect and add points in one step?
|
|
3386
|
-
addPoints(fromRing, diff < 0 ? diff * -1 : 0);
|
|
3387
|
-
addPoints(toRing, diff > 0 ? diff : 0);
|
|
3388
|
-
|
|
3389
|
-
rotate(fromRing, toRing);
|
|
3390
|
-
|
|
3391
|
-
return interpolatePoints(fromRing, toRing, string);
|
|
3392
|
-
}
|
|
3393
|
-
|
|
3394
|
-
var earcut = {exports: {}};
|
|
3395
|
-
|
|
3396
|
-
var hasRequiredEarcut;
|
|
3397
|
-
|
|
3398
|
-
function requireEarcut () {
|
|
3399
|
-
if (hasRequiredEarcut) return earcut.exports;
|
|
3400
|
-
hasRequiredEarcut = 1;
|
|
3401
|
-
|
|
3402
|
-
earcut.exports = earcut$1;
|
|
3403
|
-
earcut.exports.default = earcut$1;
|
|
3404
|
-
|
|
3405
|
-
function earcut$1(data, holeIndices, dim) {
|
|
3406
|
-
|
|
3407
|
-
dim = dim || 2;
|
|
3408
|
-
|
|
3409
|
-
var hasHoles = holeIndices && holeIndices.length,
|
|
3410
|
-
outerLen = hasHoles ? holeIndices[0] * dim : data.length,
|
|
3411
|
-
outerNode = linkedList(data, 0, outerLen, dim, true),
|
|
3412
|
-
triangles = [];
|
|
3413
|
-
|
|
3414
|
-
if (!outerNode || outerNode.next === outerNode.prev) return triangles;
|
|
3415
|
-
|
|
3416
|
-
var minX, minY, maxX, maxY, x, y, invSize;
|
|
3417
|
-
|
|
3418
|
-
if (hasHoles) outerNode = eliminateHoles(data, holeIndices, outerNode, dim);
|
|
3419
|
-
|
|
3420
|
-
// if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox
|
|
3421
|
-
if (data.length > 80 * dim) {
|
|
3422
|
-
minX = maxX = data[0];
|
|
3423
|
-
minY = maxY = data[1];
|
|
3424
|
-
|
|
3425
|
-
for (var i = dim; i < outerLen; i += dim) {
|
|
3426
|
-
x = data[i];
|
|
3427
|
-
y = data[i + 1];
|
|
3428
|
-
if (x < minX) minX = x;
|
|
3429
|
-
if (y < minY) minY = y;
|
|
3430
|
-
if (x > maxX) maxX = x;
|
|
3431
|
-
if (y > maxY) maxY = y;
|
|
3432
|
-
}
|
|
3433
|
-
|
|
3434
|
-
// minX, minY and invSize are later used to transform coords into integers for z-order calculation
|
|
3435
|
-
invSize = Math.max(maxX - minX, maxY - minY);
|
|
3436
|
-
invSize = invSize !== 0 ? 32767 / invSize : 0;
|
|
3437
|
-
}
|
|
3438
|
-
|
|
3439
|
-
earcutLinked(outerNode, triangles, dim, minX, minY, invSize, 0);
|
|
3440
|
-
|
|
3441
|
-
return triangles;
|
|
3442
|
-
}
|
|
3443
|
-
|
|
3444
|
-
// create a circular doubly linked list from polygon points in the specified winding order
|
|
3445
|
-
function linkedList(data, start, end, dim, clockwise) {
|
|
3446
|
-
var i, last;
|
|
3447
|
-
|
|
3448
|
-
if (clockwise === (signedArea(data, start, end, dim) > 0)) {
|
|
3449
|
-
for (i = start; i < end; i += dim) last = insertNode(i, data[i], data[i + 1], last);
|
|
3450
|
-
} else {
|
|
3451
|
-
for (i = end - dim; i >= start; i -= dim) last = insertNode(i, data[i], data[i + 1], last);
|
|
3452
|
-
}
|
|
3453
|
-
|
|
3454
|
-
if (last && equals(last, last.next)) {
|
|
3455
|
-
removeNode(last);
|
|
3456
|
-
last = last.next;
|
|
3457
|
-
}
|
|
3458
|
-
|
|
3459
|
-
return last;
|
|
3460
|
-
}
|
|
3461
|
-
|
|
3462
|
-
// eliminate colinear or duplicate points
|
|
3463
|
-
function filterPoints(start, end) {
|
|
3464
|
-
if (!start) return start;
|
|
3465
|
-
if (!end) end = start;
|
|
3466
|
-
|
|
3467
|
-
var p = start,
|
|
3468
|
-
again;
|
|
3469
|
-
do {
|
|
3470
|
-
again = false;
|
|
3471
|
-
|
|
3472
|
-
if (!p.steiner && (equals(p, p.next) || area(p.prev, p, p.next) === 0)) {
|
|
3473
|
-
removeNode(p);
|
|
3474
|
-
p = end = p.prev;
|
|
3475
|
-
if (p === p.next) break;
|
|
3476
|
-
again = true;
|
|
3477
|
-
|
|
3478
|
-
} else {
|
|
3479
|
-
p = p.next;
|
|
3480
|
-
}
|
|
3481
|
-
} while (again || p !== end);
|
|
3482
|
-
|
|
3483
|
-
return end;
|
|
3484
|
-
}
|
|
3485
|
-
|
|
3486
|
-
// main ear slicing loop which triangulates a polygon (given as a linked list)
|
|
3487
|
-
function earcutLinked(ear, triangles, dim, minX, minY, invSize, pass) {
|
|
3488
|
-
if (!ear) return;
|
|
3489
|
-
|
|
3490
|
-
// interlink polygon nodes in z-order
|
|
3491
|
-
if (!pass && invSize) indexCurve(ear, minX, minY, invSize);
|
|
3492
|
-
|
|
3493
|
-
var stop = ear,
|
|
3494
|
-
prev, next;
|
|
3495
|
-
|
|
3496
|
-
// iterate through ears, slicing them one by one
|
|
3497
|
-
while (ear.prev !== ear.next) {
|
|
3498
|
-
prev = ear.prev;
|
|
3499
|
-
next = ear.next;
|
|
3500
|
-
|
|
3501
|
-
if (invSize ? isEarHashed(ear, minX, minY, invSize) : isEar(ear)) {
|
|
3502
|
-
// cut off the triangle
|
|
3503
|
-
triangles.push(prev.i / dim | 0);
|
|
3504
|
-
triangles.push(ear.i / dim | 0);
|
|
3505
|
-
triangles.push(next.i / dim | 0);
|
|
3506
|
-
|
|
3507
|
-
removeNode(ear);
|
|
3508
|
-
|
|
3509
|
-
// skipping the next vertex leads to less sliver triangles
|
|
3510
|
-
ear = next.next;
|
|
3511
|
-
stop = next.next;
|
|
3512
|
-
|
|
3513
|
-
continue;
|
|
3514
|
-
}
|
|
3515
|
-
|
|
3516
|
-
ear = next;
|
|
3517
|
-
|
|
3518
|
-
// if we looped through the whole remaining polygon and can't find any more ears
|
|
3519
|
-
if (ear === stop) {
|
|
3520
|
-
// try filtering points and slicing again
|
|
3521
|
-
if (!pass) {
|
|
3522
|
-
earcutLinked(filterPoints(ear), triangles, dim, minX, minY, invSize, 1);
|
|
3523
|
-
|
|
3524
|
-
// if this didn't work, try curing all small self-intersections locally
|
|
3525
|
-
} else if (pass === 1) {
|
|
3526
|
-
ear = cureLocalIntersections(filterPoints(ear), triangles, dim);
|
|
3527
|
-
earcutLinked(ear, triangles, dim, minX, minY, invSize, 2);
|
|
3528
|
-
|
|
3529
|
-
// as a last resort, try splitting the remaining polygon into two
|
|
3530
|
-
} else if (pass === 2) {
|
|
3531
|
-
splitEarcut(ear, triangles, dim, minX, minY, invSize);
|
|
3532
|
-
}
|
|
3533
|
-
|
|
3534
|
-
break;
|
|
3535
|
-
}
|
|
3536
|
-
}
|
|
3537
|
-
}
|
|
3538
|
-
|
|
3539
|
-
// check whether a polygon node forms a valid ear with adjacent nodes
|
|
3540
|
-
function isEar(ear) {
|
|
3541
|
-
var a = ear.prev,
|
|
3542
|
-
b = ear,
|
|
3543
|
-
c = ear.next;
|
|
3544
|
-
|
|
3545
|
-
if (area(a, b, c) >= 0) return false; // reflex, can't be an ear
|
|
3546
|
-
|
|
3547
|
-
// now make sure we don't have other points inside the potential ear
|
|
3548
|
-
var ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y;
|
|
3549
|
-
|
|
3550
|
-
// triangle bbox; min & max are calculated like this for speed
|
|
3551
|
-
var x0 = ax < bx ? (ax < cx ? ax : cx) : (bx < cx ? bx : cx),
|
|
3552
|
-
y0 = ay < by ? (ay < cy ? ay : cy) : (by < cy ? by : cy),
|
|
3553
|
-
x1 = ax > bx ? (ax > cx ? ax : cx) : (bx > cx ? bx : cx),
|
|
3554
|
-
y1 = ay > by ? (ay > cy ? ay : cy) : (by > cy ? by : cy);
|
|
3555
|
-
|
|
3556
|
-
var p = c.next;
|
|
3557
|
-
while (p !== a) {
|
|
3558
|
-
if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 &&
|
|
3559
|
-
pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) &&
|
|
3560
|
-
area(p.prev, p, p.next) >= 0) return false;
|
|
3561
|
-
p = p.next;
|
|
3562
|
-
}
|
|
3563
|
-
|
|
3564
|
-
return true;
|
|
3565
|
-
}
|
|
3566
|
-
|
|
3567
|
-
function isEarHashed(ear, minX, minY, invSize) {
|
|
3568
|
-
var a = ear.prev,
|
|
3569
|
-
b = ear,
|
|
3570
|
-
c = ear.next;
|
|
3571
|
-
|
|
3572
|
-
if (area(a, b, c) >= 0) return false; // reflex, can't be an ear
|
|
3573
|
-
|
|
3574
|
-
var ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y;
|
|
3575
|
-
|
|
3576
|
-
// triangle bbox; min & max are calculated like this for speed
|
|
3577
|
-
var x0 = ax < bx ? (ax < cx ? ax : cx) : (bx < cx ? bx : cx),
|
|
3578
|
-
y0 = ay < by ? (ay < cy ? ay : cy) : (by < cy ? by : cy),
|
|
3579
|
-
x1 = ax > bx ? (ax > cx ? ax : cx) : (bx > cx ? bx : cx),
|
|
3580
|
-
y1 = ay > by ? (ay > cy ? ay : cy) : (by > cy ? by : cy);
|
|
3581
|
-
|
|
3582
|
-
// z-order range for the current triangle bbox;
|
|
3583
|
-
var minZ = zOrder(x0, y0, minX, minY, invSize),
|
|
3584
|
-
maxZ = zOrder(x1, y1, minX, minY, invSize);
|
|
3585
|
-
|
|
3586
|
-
var p = ear.prevZ,
|
|
3587
|
-
n = ear.nextZ;
|
|
3588
|
-
|
|
3589
|
-
// look for points inside the triangle in both directions
|
|
3590
|
-
while (p && p.z >= minZ && n && n.z <= maxZ) {
|
|
3591
|
-
if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c &&
|
|
3592
|
-
pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
|
|
3593
|
-
p = p.prevZ;
|
|
3594
|
-
|
|
3595
|
-
if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c &&
|
|
3596
|
-
pointInTriangle(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false;
|
|
3597
|
-
n = n.nextZ;
|
|
3598
|
-
}
|
|
3599
|
-
|
|
3600
|
-
// look for remaining points in decreasing z-order
|
|
3601
|
-
while (p && p.z >= minZ) {
|
|
3602
|
-
if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c &&
|
|
3603
|
-
pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
|
|
3604
|
-
p = p.prevZ;
|
|
3605
|
-
}
|
|
3606
|
-
|
|
3607
|
-
// look for remaining points in increasing z-order
|
|
3608
|
-
while (n && n.z <= maxZ) {
|
|
3609
|
-
if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c &&
|
|
3610
|
-
pointInTriangle(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false;
|
|
3611
|
-
n = n.nextZ;
|
|
3612
|
-
}
|
|
3613
|
-
|
|
3614
|
-
return true;
|
|
3615
|
-
}
|
|
3616
|
-
|
|
3617
|
-
// go through all polygon nodes and cure small local self-intersections
|
|
3618
|
-
function cureLocalIntersections(start, triangles, dim) {
|
|
3619
|
-
var p = start;
|
|
3620
|
-
do {
|
|
3621
|
-
var a = p.prev,
|
|
3622
|
-
b = p.next.next;
|
|
3623
|
-
|
|
3624
|
-
if (!equals(a, b) && intersects(a, p, p.next, b) && locallyInside(a, b) && locallyInside(b, a)) {
|
|
3625
|
-
|
|
3626
|
-
triangles.push(a.i / dim | 0);
|
|
3627
|
-
triangles.push(p.i / dim | 0);
|
|
3628
|
-
triangles.push(b.i / dim | 0);
|
|
3629
|
-
|
|
3630
|
-
// remove two nodes involved
|
|
3631
|
-
removeNode(p);
|
|
3632
|
-
removeNode(p.next);
|
|
3633
|
-
|
|
3634
|
-
p = start = b;
|
|
3635
|
-
}
|
|
3636
|
-
p = p.next;
|
|
3637
|
-
} while (p !== start);
|
|
3638
|
-
|
|
3639
|
-
return filterPoints(p);
|
|
3640
|
-
}
|
|
3641
|
-
|
|
3642
|
-
// try splitting polygon into two and triangulate them independently
|
|
3643
|
-
function splitEarcut(start, triangles, dim, minX, minY, invSize) {
|
|
3644
|
-
// look for a valid diagonal that divides the polygon into two
|
|
3645
|
-
var a = start;
|
|
3646
|
-
do {
|
|
3647
|
-
var b = a.next.next;
|
|
3648
|
-
while (b !== a.prev) {
|
|
3649
|
-
if (a.i !== b.i && isValidDiagonal(a, b)) {
|
|
3650
|
-
// split the polygon in two by the diagonal
|
|
3651
|
-
var c = splitPolygon(a, b);
|
|
3652
|
-
|
|
3653
|
-
// filter colinear points around the cuts
|
|
3654
|
-
a = filterPoints(a, a.next);
|
|
3655
|
-
c = filterPoints(c, c.next);
|
|
3656
|
-
|
|
3657
|
-
// run earcut on each half
|
|
3658
|
-
earcutLinked(a, triangles, dim, minX, minY, invSize, 0);
|
|
3659
|
-
earcutLinked(c, triangles, dim, minX, minY, invSize, 0);
|
|
3660
|
-
return;
|
|
3661
|
-
}
|
|
3662
|
-
b = b.next;
|
|
3663
|
-
}
|
|
3664
|
-
a = a.next;
|
|
3665
|
-
} while (a !== start);
|
|
3666
|
-
}
|
|
3667
|
-
|
|
3668
|
-
// link every hole into the outer loop, producing a single-ring polygon without holes
|
|
3669
|
-
function eliminateHoles(data, holeIndices, outerNode, dim) {
|
|
3670
|
-
var queue = [],
|
|
3671
|
-
i, len, start, end, list;
|
|
3672
|
-
|
|
3673
|
-
for (i = 0, len = holeIndices.length; i < len; i++) {
|
|
3674
|
-
start = holeIndices[i] * dim;
|
|
3675
|
-
end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
|
|
3676
|
-
list = linkedList(data, start, end, dim, false);
|
|
3677
|
-
if (list === list.next) list.steiner = true;
|
|
3678
|
-
queue.push(getLeftmost(list));
|
|
3679
|
-
}
|
|
3680
|
-
|
|
3681
|
-
queue.sort(compareX);
|
|
3682
|
-
|
|
3683
|
-
// process holes from left to right
|
|
3684
|
-
for (i = 0; i < queue.length; i++) {
|
|
3685
|
-
outerNode = eliminateHole(queue[i], outerNode);
|
|
3686
|
-
}
|
|
3687
|
-
|
|
3688
|
-
return outerNode;
|
|
3689
|
-
}
|
|
3690
|
-
|
|
3691
|
-
function compareX(a, b) {
|
|
3692
|
-
return a.x - b.x;
|
|
3693
|
-
}
|
|
3694
|
-
|
|
3695
|
-
// find a bridge between vertices that connects hole with an outer ring and and link it
|
|
3696
|
-
function eliminateHole(hole, outerNode) {
|
|
3697
|
-
var bridge = findHoleBridge(hole, outerNode);
|
|
3698
|
-
if (!bridge) {
|
|
3699
|
-
return outerNode;
|
|
3700
|
-
}
|
|
3701
|
-
|
|
3702
|
-
var bridgeReverse = splitPolygon(bridge, hole);
|
|
3703
|
-
|
|
3704
|
-
// filter collinear points around the cuts
|
|
3705
|
-
filterPoints(bridgeReverse, bridgeReverse.next);
|
|
3706
|
-
return filterPoints(bridge, bridge.next);
|
|
3707
|
-
}
|
|
3708
|
-
|
|
3709
|
-
// David Eberly's algorithm for finding a bridge between hole and outer polygon
|
|
3710
|
-
function findHoleBridge(hole, outerNode) {
|
|
3711
|
-
var p = outerNode,
|
|
3712
|
-
hx = hole.x,
|
|
3713
|
-
hy = hole.y,
|
|
3714
|
-
qx = -Infinity,
|
|
3715
|
-
m;
|
|
3716
|
-
|
|
3717
|
-
// find a segment intersected by a ray from the hole's leftmost point to the left;
|
|
3718
|
-
// segment's endpoint with lesser x will be potential connection point
|
|
3719
|
-
do {
|
|
3720
|
-
if (hy <= p.y && hy >= p.next.y && p.next.y !== p.y) {
|
|
3721
|
-
var x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y);
|
|
3722
|
-
if (x <= hx && x > qx) {
|
|
3723
|
-
qx = x;
|
|
3724
|
-
m = p.x < p.next.x ? p : p.next;
|
|
3725
|
-
if (x === hx) return m; // hole touches outer segment; pick leftmost endpoint
|
|
3726
|
-
}
|
|
3727
|
-
}
|
|
3728
|
-
p = p.next;
|
|
3729
|
-
} while (p !== outerNode);
|
|
3730
|
-
|
|
3731
|
-
if (!m) return null;
|
|
3732
|
-
|
|
3733
|
-
// look for points inside the triangle of hole point, segment intersection and endpoint;
|
|
3734
|
-
// if there are no points found, we have a valid connection;
|
|
3735
|
-
// otherwise choose the point of the minimum angle with the ray as connection point
|
|
3736
|
-
|
|
3737
|
-
var stop = m,
|
|
3738
|
-
mx = m.x,
|
|
3739
|
-
my = m.y,
|
|
3740
|
-
tanMin = Infinity,
|
|
3741
|
-
tan;
|
|
3742
|
-
|
|
3743
|
-
p = m;
|
|
3744
|
-
|
|
3745
|
-
do {
|
|
3746
|
-
if (hx >= p.x && p.x >= mx && hx !== p.x &&
|
|
3747
|
-
pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y)) {
|
|
3748
|
-
|
|
3749
|
-
tan = Math.abs(hy - p.y) / (hx - p.x); // tangential
|
|
3750
|
-
|
|
3751
|
-
if (locallyInside(p, hole) &&
|
|
3752
|
-
(tan < tanMin || (tan === tanMin && (p.x > m.x || (p.x === m.x && sectorContainsSector(m, p)))))) {
|
|
3753
|
-
m = p;
|
|
3754
|
-
tanMin = tan;
|
|
3755
|
-
}
|
|
3756
|
-
}
|
|
3757
|
-
|
|
3758
|
-
p = p.next;
|
|
3759
|
-
} while (p !== stop);
|
|
3760
|
-
|
|
3761
|
-
return m;
|
|
3762
|
-
}
|
|
3763
|
-
|
|
3764
|
-
// whether sector in vertex m contains sector in vertex p in the same coordinates
|
|
3765
|
-
function sectorContainsSector(m, p) {
|
|
3766
|
-
return area(m.prev, m, p.prev) < 0 && area(p.next, m, m.next) < 0;
|
|
3767
|
-
}
|
|
3768
|
-
|
|
3769
|
-
// interlink polygon nodes in z-order
|
|
3770
|
-
function indexCurve(start, minX, minY, invSize) {
|
|
3771
|
-
var p = start;
|
|
3772
|
-
do {
|
|
3773
|
-
if (p.z === 0) p.z = zOrder(p.x, p.y, minX, minY, invSize);
|
|
3774
|
-
p.prevZ = p.prev;
|
|
3775
|
-
p.nextZ = p.next;
|
|
3776
|
-
p = p.next;
|
|
3777
|
-
} while (p !== start);
|
|
3778
|
-
|
|
3779
|
-
p.prevZ.nextZ = null;
|
|
3780
|
-
p.prevZ = null;
|
|
3781
|
-
|
|
3782
|
-
sortLinked(p);
|
|
3783
|
-
}
|
|
3784
|
-
|
|
3785
|
-
// Simon Tatham's linked list merge sort algorithm
|
|
3786
|
-
// http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
|
|
3787
|
-
function sortLinked(list) {
|
|
3788
|
-
var i, p, q, e, tail, numMerges, pSize, qSize,
|
|
3789
|
-
inSize = 1;
|
|
3790
|
-
|
|
3791
|
-
do {
|
|
3792
|
-
p = list;
|
|
3793
|
-
list = null;
|
|
3794
|
-
tail = null;
|
|
3795
|
-
numMerges = 0;
|
|
3796
|
-
|
|
3797
|
-
while (p) {
|
|
3798
|
-
numMerges++;
|
|
3799
|
-
q = p;
|
|
3800
|
-
pSize = 0;
|
|
3801
|
-
for (i = 0; i < inSize; i++) {
|
|
3802
|
-
pSize++;
|
|
3803
|
-
q = q.nextZ;
|
|
3804
|
-
if (!q) break;
|
|
3805
|
-
}
|
|
3806
|
-
qSize = inSize;
|
|
3807
|
-
|
|
3808
|
-
while (pSize > 0 || (qSize > 0 && q)) {
|
|
3809
|
-
|
|
3810
|
-
if (pSize !== 0 && (qSize === 0 || !q || p.z <= q.z)) {
|
|
3811
|
-
e = p;
|
|
3812
|
-
p = p.nextZ;
|
|
3813
|
-
pSize--;
|
|
3814
|
-
} else {
|
|
3815
|
-
e = q;
|
|
3816
|
-
q = q.nextZ;
|
|
3817
|
-
qSize--;
|
|
3818
|
-
}
|
|
3819
|
-
|
|
3820
|
-
if (tail) tail.nextZ = e;
|
|
3821
|
-
else list = e;
|
|
3822
|
-
|
|
3823
|
-
e.prevZ = tail;
|
|
3824
|
-
tail = e;
|
|
3825
|
-
}
|
|
3826
|
-
|
|
3827
|
-
p = q;
|
|
3828
|
-
}
|
|
3829
|
-
|
|
3830
|
-
tail.nextZ = null;
|
|
3831
|
-
inSize *= 2;
|
|
3832
|
-
|
|
3833
|
-
} while (numMerges > 1);
|
|
3834
|
-
|
|
3835
|
-
return list;
|
|
3836
|
-
}
|
|
3837
|
-
|
|
3838
|
-
// z-order of a point given coords and inverse of the longer side of data bbox
|
|
3839
|
-
function zOrder(x, y, minX, minY, invSize) {
|
|
3840
|
-
// coords are transformed into non-negative 15-bit integer range
|
|
3841
|
-
x = (x - minX) * invSize | 0;
|
|
3842
|
-
y = (y - minY) * invSize | 0;
|
|
3843
|
-
|
|
3844
|
-
x = (x | (x << 8)) & 0x00FF00FF;
|
|
3845
|
-
x = (x | (x << 4)) & 0x0F0F0F0F;
|
|
3846
|
-
x = (x | (x << 2)) & 0x33333333;
|
|
3847
|
-
x = (x | (x << 1)) & 0x55555555;
|
|
3848
|
-
|
|
3849
|
-
y = (y | (y << 8)) & 0x00FF00FF;
|
|
3850
|
-
y = (y | (y << 4)) & 0x0F0F0F0F;
|
|
3851
|
-
y = (y | (y << 2)) & 0x33333333;
|
|
3852
|
-
y = (y | (y << 1)) & 0x55555555;
|
|
3853
|
-
|
|
3854
|
-
return x | (y << 1);
|
|
3855
|
-
}
|
|
3856
|
-
|
|
3857
|
-
// find the leftmost node of a polygon ring
|
|
3858
|
-
function getLeftmost(start) {
|
|
3859
|
-
var p = start,
|
|
3860
|
-
leftmost = start;
|
|
3861
|
-
do {
|
|
3862
|
-
if (p.x < leftmost.x || (p.x === leftmost.x && p.y < leftmost.y)) leftmost = p;
|
|
3863
|
-
p = p.next;
|
|
3864
|
-
} while (p !== start);
|
|
3865
|
-
|
|
3866
|
-
return leftmost;
|
|
3867
|
-
}
|
|
3868
|
-
|
|
3869
|
-
// check if a point lies within a convex triangle
|
|
3870
|
-
function pointInTriangle(ax, ay, bx, by, cx, cy, px, py) {
|
|
3871
|
-
return (cx - px) * (ay - py) >= (ax - px) * (cy - py) &&
|
|
3872
|
-
(ax - px) * (by - py) >= (bx - px) * (ay - py) &&
|
|
3873
|
-
(bx - px) * (cy - py) >= (cx - px) * (by - py);
|
|
3874
|
-
}
|
|
3875
|
-
|
|
3876
|
-
// check if a diagonal between two polygon nodes is valid (lies in polygon interior)
|
|
3877
|
-
function isValidDiagonal(a, b) {
|
|
3878
|
-
return a.next.i !== b.i && a.prev.i !== b.i && !intersectsPolygon(a, b) && // dones't intersect other edges
|
|
3879
|
-
(locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b) && // locally visible
|
|
3880
|
-
(area(a.prev, a, b.prev) || area(a, b.prev, b)) || // does not create opposite-facing sectors
|
|
3881
|
-
equals(a, b) && area(a.prev, a, a.next) > 0 && area(b.prev, b, b.next) > 0); // special zero-length case
|
|
3882
|
-
}
|
|
3883
|
-
|
|
3884
|
-
// signed area of a triangle
|
|
3885
|
-
function area(p, q, r) {
|
|
3886
|
-
return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
|
|
3887
|
-
}
|
|
3888
|
-
|
|
3889
|
-
// check if two points are equal
|
|
3890
|
-
function equals(p1, p2) {
|
|
3891
|
-
return p1.x === p2.x && p1.y === p2.y;
|
|
3892
|
-
}
|
|
3893
|
-
|
|
3894
|
-
// check if two segments intersect
|
|
3895
|
-
function intersects(p1, q1, p2, q2) {
|
|
3896
|
-
var o1 = sign(area(p1, q1, p2));
|
|
3897
|
-
var o2 = sign(area(p1, q1, q2));
|
|
3898
|
-
var o3 = sign(area(p2, q2, p1));
|
|
3899
|
-
var o4 = sign(area(p2, q2, q1));
|
|
3900
|
-
|
|
3901
|
-
if (o1 !== o2 && o3 !== o4) return true; // general case
|
|
3902
|
-
|
|
3903
|
-
if (o1 === 0 && onSegment(p1, p2, q1)) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1
|
|
3904
|
-
if (o2 === 0 && onSegment(p1, q2, q1)) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1
|
|
3905
|
-
if (o3 === 0 && onSegment(p2, p1, q2)) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2
|
|
3906
|
-
if (o4 === 0 && onSegment(p2, q1, q2)) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2
|
|
3907
|
-
|
|
3908
|
-
return false;
|
|
3909
|
-
}
|
|
3910
|
-
|
|
3911
|
-
// for collinear points p, q, r, check if point q lies on segment pr
|
|
3912
|
-
function onSegment(p, q, r) {
|
|
3913
|
-
return q.x <= Math.max(p.x, r.x) && q.x >= Math.min(p.x, r.x) && q.y <= Math.max(p.y, r.y) && q.y >= Math.min(p.y, r.y);
|
|
3914
|
-
}
|
|
3915
|
-
|
|
3916
|
-
function sign(num) {
|
|
3917
|
-
return num > 0 ? 1 : num < 0 ? -1 : 0;
|
|
3918
|
-
}
|
|
3919
|
-
|
|
3920
|
-
// check if a polygon diagonal intersects any polygon segments
|
|
3921
|
-
function intersectsPolygon(a, b) {
|
|
3922
|
-
var p = a;
|
|
3923
|
-
do {
|
|
3924
|
-
if (p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i &&
|
|
3925
|
-
intersects(p, p.next, a, b)) return true;
|
|
3926
|
-
p = p.next;
|
|
3927
|
-
} while (p !== a);
|
|
3928
|
-
|
|
3929
|
-
return false;
|
|
3930
|
-
}
|
|
3931
|
-
|
|
3932
|
-
// check if a polygon diagonal is locally inside the polygon
|
|
3933
|
-
function locallyInside(a, b) {
|
|
3934
|
-
return area(a.prev, a, a.next) < 0 ?
|
|
3935
|
-
area(a, b, a.next) >= 0 && area(a, a.prev, b) >= 0 :
|
|
3936
|
-
area(a, b, a.prev) < 0 || area(a, a.next, b) < 0;
|
|
3937
|
-
}
|
|
3938
|
-
|
|
3939
|
-
// check if the middle point of a polygon diagonal is inside the polygon
|
|
3940
|
-
function middleInside(a, b) {
|
|
3941
|
-
var p = a,
|
|
3942
|
-
inside = false,
|
|
3943
|
-
px = (a.x + b.x) / 2,
|
|
3944
|
-
py = (a.y + b.y) / 2;
|
|
3945
|
-
do {
|
|
3946
|
-
if (((p.y > py) !== (p.next.y > py)) && p.next.y !== p.y &&
|
|
3947
|
-
(px < (p.next.x - p.x) * (py - p.y) / (p.next.y - p.y) + p.x))
|
|
3948
|
-
inside = !inside;
|
|
3949
|
-
p = p.next;
|
|
3950
|
-
} while (p !== a);
|
|
3951
|
-
|
|
3952
|
-
return inside;
|
|
3953
|
-
}
|
|
3954
|
-
|
|
3955
|
-
// link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two;
|
|
3956
|
-
// if one belongs to the outer ring and another to a hole, it merges it into a single ring
|
|
3957
|
-
function splitPolygon(a, b) {
|
|
3958
|
-
var a2 = new Node(a.i, a.x, a.y),
|
|
3959
|
-
b2 = new Node(b.i, b.x, b.y),
|
|
3960
|
-
an = a.next,
|
|
3961
|
-
bp = b.prev;
|
|
3962
|
-
|
|
3963
|
-
a.next = b;
|
|
3964
|
-
b.prev = a;
|
|
3965
|
-
|
|
3966
|
-
a2.next = an;
|
|
3967
|
-
an.prev = a2;
|
|
3968
|
-
|
|
3969
|
-
b2.next = a2;
|
|
3970
|
-
a2.prev = b2;
|
|
3971
|
-
|
|
3972
|
-
bp.next = b2;
|
|
3973
|
-
b2.prev = bp;
|
|
3974
|
-
|
|
3975
|
-
return b2;
|
|
3976
|
-
}
|
|
3977
|
-
|
|
3978
|
-
// create a node and optionally link it with previous one (in a circular doubly linked list)
|
|
3979
|
-
function insertNode(i, x, y, last) {
|
|
3980
|
-
var p = new Node(i, x, y);
|
|
3981
|
-
|
|
3982
|
-
if (!last) {
|
|
3983
|
-
p.prev = p;
|
|
3984
|
-
p.next = p;
|
|
3985
|
-
|
|
3986
|
-
} else {
|
|
3987
|
-
p.next = last.next;
|
|
3988
|
-
p.prev = last;
|
|
3989
|
-
last.next.prev = p;
|
|
3990
|
-
last.next = p;
|
|
3991
|
-
}
|
|
3992
|
-
return p;
|
|
3993
|
-
}
|
|
3994
|
-
|
|
3995
|
-
function removeNode(p) {
|
|
3996
|
-
p.next.prev = p.prev;
|
|
3997
|
-
p.prev.next = p.next;
|
|
3998
|
-
|
|
3999
|
-
if (p.prevZ) p.prevZ.nextZ = p.nextZ;
|
|
4000
|
-
if (p.nextZ) p.nextZ.prevZ = p.prevZ;
|
|
4001
|
-
}
|
|
4002
|
-
|
|
4003
|
-
function Node(i, x, y) {
|
|
4004
|
-
// vertex index in coordinates array
|
|
4005
|
-
this.i = i;
|
|
4006
|
-
|
|
4007
|
-
// vertex coordinates
|
|
4008
|
-
this.x = x;
|
|
4009
|
-
this.y = y;
|
|
4010
|
-
|
|
4011
|
-
// previous and next vertex nodes in a polygon ring
|
|
4012
|
-
this.prev = null;
|
|
4013
|
-
this.next = null;
|
|
4014
|
-
|
|
4015
|
-
// z-order curve value
|
|
4016
|
-
this.z = 0;
|
|
4017
|
-
|
|
4018
|
-
// previous and next nodes in z-order
|
|
4019
|
-
this.prevZ = null;
|
|
4020
|
-
this.nextZ = null;
|
|
4021
|
-
|
|
4022
|
-
// indicates whether this is a steiner point
|
|
4023
|
-
this.steiner = false;
|
|
4024
|
-
}
|
|
4025
|
-
|
|
4026
|
-
// return a percentage difference between the polygon area and its triangulation area;
|
|
4027
|
-
// used to verify correctness of triangulation
|
|
4028
|
-
earcut$1.deviation = function (data, holeIndices, dim, triangles) {
|
|
4029
|
-
var hasHoles = holeIndices && holeIndices.length;
|
|
4030
|
-
var outerLen = hasHoles ? holeIndices[0] * dim : data.length;
|
|
4031
|
-
|
|
4032
|
-
var polygonArea = Math.abs(signedArea(data, 0, outerLen, dim));
|
|
4033
|
-
if (hasHoles) {
|
|
4034
|
-
for (var i = 0, len = holeIndices.length; i < len; i++) {
|
|
4035
|
-
var start = holeIndices[i] * dim;
|
|
4036
|
-
var end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
|
|
4037
|
-
polygonArea -= Math.abs(signedArea(data, start, end, dim));
|
|
4038
|
-
}
|
|
4039
|
-
}
|
|
4040
|
-
|
|
4041
|
-
var trianglesArea = 0;
|
|
4042
|
-
for (i = 0; i < triangles.length; i += 3) {
|
|
4043
|
-
var a = triangles[i] * dim;
|
|
4044
|
-
var b = triangles[i + 1] * dim;
|
|
4045
|
-
var c = triangles[i + 2] * dim;
|
|
4046
|
-
trianglesArea += Math.abs(
|
|
4047
|
-
(data[a] - data[c]) * (data[b + 1] - data[a + 1]) -
|
|
4048
|
-
(data[a] - data[b]) * (data[c + 1] - data[a + 1]));
|
|
4049
|
-
}
|
|
4050
|
-
|
|
4051
|
-
return polygonArea === 0 && trianglesArea === 0 ? 0 :
|
|
4052
|
-
Math.abs((trianglesArea - polygonArea) / polygonArea);
|
|
4053
|
-
};
|
|
4054
|
-
|
|
4055
|
-
function signedArea(data, start, end, dim) {
|
|
4056
|
-
var sum = 0;
|
|
4057
|
-
for (var i = start, j = end - dim; i < end; i += dim) {
|
|
4058
|
-
sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]);
|
|
4059
|
-
j = i;
|
|
4060
|
-
}
|
|
4061
|
-
return sum;
|
|
4062
|
-
}
|
|
4063
|
-
|
|
4064
|
-
// turn a polygon in a multi-dimensional array form (e.g. as in GeoJSON) into a form Earcut accepts
|
|
4065
|
-
earcut$1.flatten = function (data) {
|
|
4066
|
-
var dim = data[0][0].length,
|
|
4067
|
-
result = {vertices: [], holes: [], dimensions: dim},
|
|
4068
|
-
holeIndex = 0;
|
|
4069
|
-
|
|
4070
|
-
for (var i = 0; i < data.length; i++) {
|
|
4071
|
-
for (var j = 0; j < data[i].length; j++) {
|
|
4072
|
-
for (var d = 0; d < dim; d++) result.vertices.push(data[i][j][d]);
|
|
4073
|
-
}
|
|
4074
|
-
if (i > 0) {
|
|
4075
|
-
holeIndex += data[i - 1].length;
|
|
4076
|
-
result.holes.push(holeIndex);
|
|
4077
|
-
}
|
|
4078
|
-
}
|
|
4079
|
-
return result;
|
|
4080
|
-
};
|
|
4081
|
-
return earcut.exports;
|
|
4082
|
-
}
|
|
4083
|
-
|
|
4084
|
-
requireEarcut();
|
|
4085
|
-
|
|
4086
|
-
function ascending(a, b) {
|
|
4087
|
-
return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
|
|
4088
|
-
}
|
|
4089
|
-
|
|
4090
|
-
function bisector(compare) {
|
|
4091
|
-
if (compare.length === 1) compare = ascendingComparator(compare);
|
|
4092
|
-
return {
|
|
4093
|
-
left: function(a, x, lo, hi) {
|
|
4094
|
-
if (lo == null) lo = 0;
|
|
4095
|
-
if (hi == null) hi = a.length;
|
|
4096
|
-
while (lo < hi) {
|
|
4097
|
-
var mid = lo + hi >>> 1;
|
|
4098
|
-
if (compare(a[mid], x) < 0) lo = mid + 1;
|
|
4099
|
-
else hi = mid;
|
|
4100
|
-
}
|
|
4101
|
-
return lo;
|
|
4102
|
-
},
|
|
4103
|
-
right: function(a, x, lo, hi) {
|
|
4104
|
-
if (lo == null) lo = 0;
|
|
4105
|
-
if (hi == null) hi = a.length;
|
|
4106
|
-
while (lo < hi) {
|
|
4107
|
-
var mid = lo + hi >>> 1;
|
|
4108
|
-
if (compare(a[mid], x) > 0) hi = mid;
|
|
4109
|
-
else lo = mid + 1;
|
|
4110
|
-
}
|
|
4111
|
-
return lo;
|
|
4112
|
-
}
|
|
4113
|
-
};
|
|
4114
|
-
}
|
|
4115
|
-
|
|
4116
|
-
function ascendingComparator(f) {
|
|
4117
|
-
return function(d, x) {
|
|
4118
|
-
return ascending(f(d), x);
|
|
4119
|
-
};
|
|
4120
|
-
}
|
|
4121
|
-
|
|
4122
|
-
bisector(ascending);
|
|
4123
|
-
|
|
4124
|
-
const SHARP_PATH = "m23 12-8.036-3.23L12.006 0 9.047 8.77 1 12l8.047 3.23L12.006 24l2.958-8.77z";
|
|
4125
|
-
const ROUND_PATH = "M17.425 13.854c1.665-.675 1.665-3.033 0-3.708l-2.73-1.106-.793-2.37c-.609-1.82-3.184-1.82-3.793 0l-.793 2.37-2.734 1.106c-1.666.674-1.666 3.034 0 3.708l2.734 1.106.793 2.37c.609 1.82 3.184 1.82 3.793 0l.793-2.37z";
|
|
4126
|
-
const SVG_STYLE = { width: "100%", height: "100%", display: "block" };
|
|
4127
|
-
const GRADIENT_ID = "ai-mark-gradient";
|
|
4128
|
-
function SVGMorph({ delay, paths, inheritColor = false }) {
|
|
4129
|
-
const [pathIndex, setPathIndex] = useState(0);
|
|
4130
|
-
const progress = useMotionValue(0);
|
|
4131
|
-
const arrayOfIndex = useMemo(() => paths.map((_, i) => i), [paths]);
|
|
4132
|
-
const path = useTransform(progress, arrayOfIndex, paths, {
|
|
4133
|
-
mixer: (a, b) => interpolate(a, b, { maxSegmentLength: 1 })
|
|
4134
|
-
});
|
|
4135
|
-
useEffect(() => {
|
|
4136
|
-
const animation = animate(progress, pathIndex, {
|
|
4137
|
-
duration: 0.8,
|
|
4138
|
-
ease: [0.5, 0, 0.65, 1],
|
|
4139
|
-
delay,
|
|
4140
|
-
onComplete: () => {
|
|
4141
|
-
if (pathIndex === paths.length - 1) {
|
|
4142
|
-
progress.set(0);
|
|
4143
|
-
setPathIndex(1);
|
|
4144
|
-
} else {
|
|
4145
|
-
setPathIndex(pathIndex + 1);
|
|
4146
|
-
}
|
|
4147
|
-
}
|
|
4148
|
-
});
|
|
4149
|
-
return () => {
|
|
4150
|
-
animation.stop();
|
|
4151
|
-
};
|
|
4152
|
-
}, [pathIndex, paths.length, progress, delay]);
|
|
4153
|
-
return /* @__PURE__ */ jsx(
|
|
4154
|
-
motion.path,
|
|
4155
|
-
{
|
|
4156
|
-
fill: inheritColor ? "currentColor" : `url(#${GRADIENT_ID})`,
|
|
4157
|
-
d: path
|
|
4158
|
-
}
|
|
4159
|
-
);
|
|
4160
|
-
}
|
|
4161
|
-
const AiMarkIconAnimatedSegment = memo(
|
|
4162
|
-
({
|
|
4163
|
-
animate: animate2 = false,
|
|
4164
|
-
delay,
|
|
4165
|
-
className,
|
|
4166
|
-
inheritColor = false,
|
|
4167
|
-
spin = false
|
|
4168
|
-
}) => {
|
|
4169
|
-
const fill = inheritColor ? "currentColor" : `url(#${GRADIENT_ID})`;
|
|
4170
|
-
const { mode } = useTheme();
|
|
4171
|
-
const gradientDef = !inheritColor && /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs(
|
|
4172
|
-
"linearGradient",
|
|
4173
|
-
{
|
|
4174
|
-
id: GRADIENT_ID,
|
|
4175
|
-
x1: "0.4962",
|
|
4176
|
-
y1: "0.2483",
|
|
4177
|
-
x2: "-0.0543",
|
|
4178
|
-
y2: "0.4319",
|
|
4179
|
-
gradientUnits: "objectBoundingBox",
|
|
4180
|
-
children: [
|
|
4181
|
-
/* @__PURE__ */ jsx(
|
|
4182
|
-
"stop",
|
|
4183
|
-
{
|
|
4184
|
-
stopColor: mode === "dark" ? "#77C5EA" : "#026EE4",
|
|
4185
|
-
style: {
|
|
4186
|
-
stopColor: mode === "dark" ? "#77C5EA" : "#026EE4",
|
|
4187
|
-
stopOpacity: 1
|
|
4188
|
-
}
|
|
4189
|
-
}
|
|
4190
|
-
),
|
|
4191
|
-
/* @__PURE__ */ jsx(
|
|
4192
|
-
"stop",
|
|
4193
|
-
{
|
|
4194
|
-
offset: "1",
|
|
4195
|
-
stopColor: mode === "dark" ? "#D0D8E1" : "#27AEEE",
|
|
4196
|
-
style: {
|
|
4197
|
-
stopColor: mode === "dark" ? "#D0D8E1" : "#27AEEE",
|
|
4198
|
-
stopOpacity: 1
|
|
4199
|
-
}
|
|
4200
|
-
}
|
|
4201
|
-
)
|
|
4202
|
-
]
|
|
4203
|
-
}
|
|
4204
|
-
) });
|
|
4205
|
-
if (!animate2) {
|
|
4206
|
-
return /* @__PURE__ */ jsxs("svg", { className, style: SVG_STYLE, viewBox: "0 0 24 24", children: [
|
|
4207
|
-
gradientDef,
|
|
4208
|
-
/* @__PURE__ */ jsx("path", { fill, d: SHARP_PATH })
|
|
4209
|
-
] });
|
|
4210
|
-
}
|
|
4211
|
-
return /* @__PURE__ */ jsxs(
|
|
4212
|
-
motion.svg,
|
|
4213
|
-
{
|
|
4214
|
-
className,
|
|
4215
|
-
style: SVG_STYLE,
|
|
4216
|
-
viewBox: "0 0 24 24",
|
|
4217
|
-
animate: spin ? { rotate: 180 } : {},
|
|
4218
|
-
transition: {
|
|
4219
|
-
duration: 2,
|
|
4220
|
-
type: "spring",
|
|
4221
|
-
repeat: 0,
|
|
4222
|
-
repeatType: "loop",
|
|
4223
|
-
repeatDelay: 1.5,
|
|
4224
|
-
delay
|
|
4225
|
-
},
|
|
4226
|
-
children: [
|
|
4227
|
-
gradientDef,
|
|
4228
|
-
/* @__PURE__ */ jsx(
|
|
4229
|
-
SVGMorph,
|
|
4230
|
-
{
|
|
4231
|
-
paths: [SHARP_PATH, ROUND_PATH, SHARP_PATH],
|
|
4232
|
-
delay,
|
|
4233
|
-
inheritColor
|
|
4234
|
-
}
|
|
4235
|
-
)
|
|
4236
|
-
]
|
|
4237
|
-
}
|
|
4238
|
-
);
|
|
4239
|
-
}
|
|
4240
|
-
);
|
|
4241
|
-
AiMarkIconAnimatedSegment.displayName = "AiMarkIconAnimatedSegment";
|
|
4242
|
-
const AiMarkIconAnimated = ({
|
|
4243
|
-
animate: animate2 = false,
|
|
4244
|
-
size = 16,
|
|
4245
|
-
inheritColor = false,
|
|
4246
|
-
spin = false
|
|
4247
|
-
}) => {
|
|
4248
|
-
const { prefersReducedMotion } = usePrefersReducedMotion();
|
|
4249
|
-
const shouldAnimate = animate2 && !prefersReducedMotion;
|
|
4250
|
-
const largeSvgSize = size * 0.75;
|
|
4251
|
-
const smallSvgSize = size * 6 / 16;
|
|
4252
|
-
const containerStyle = useMemo(
|
|
4253
|
-
() => ({ position: "relative", width: size, height: size }),
|
|
4254
|
-
[size]
|
|
4255
|
-
);
|
|
4256
|
-
const largeIconStyle = useMemo(
|
|
4257
|
-
() => ({
|
|
4258
|
-
position: "absolute",
|
|
4259
|
-
bottom: size / 16,
|
|
4260
|
-
left: size / 16,
|
|
4261
|
-
width: largeSvgSize,
|
|
4262
|
-
height: largeSvgSize
|
|
4263
|
-
}),
|
|
4264
|
-
[largeSvgSize, size]
|
|
4265
|
-
);
|
|
4266
|
-
const smallIconStyle = useMemo(
|
|
4267
|
-
() => ({
|
|
4268
|
-
position: "absolute",
|
|
4269
|
-
top: size / 16,
|
|
4270
|
-
right: size / 16,
|
|
4271
|
-
width: smallSvgSize,
|
|
4272
|
-
height: smallSvgSize
|
|
4273
|
-
}),
|
|
4274
|
-
[smallSvgSize, size]
|
|
4275
|
-
);
|
|
4276
|
-
return /* @__PURE__ */ jsxs("div", { style: containerStyle, "data-anv": "ai-mark-icon-animated", children: [
|
|
4277
|
-
/* @__PURE__ */ jsx("div", { style: largeIconStyle, children: /* @__PURE__ */ jsx(
|
|
4278
|
-
AiMarkIconAnimatedSegment,
|
|
4279
|
-
{
|
|
4280
|
-
animate: shouldAnimate,
|
|
4281
|
-
delay: 0.15,
|
|
4282
|
-
inheritColor,
|
|
4283
|
-
spin
|
|
4284
|
-
}
|
|
4285
|
-
) }),
|
|
4286
|
-
/* @__PURE__ */ jsx("div", { style: smallIconStyle, children: /* @__PURE__ */ jsx(
|
|
4287
|
-
AiMarkIconAnimatedSegment,
|
|
4288
|
-
{
|
|
4289
|
-
animate: shouldAnimate,
|
|
4290
|
-
inheritColor,
|
|
4291
|
-
spin
|
|
4292
|
-
}
|
|
4293
|
-
) })
|
|
4294
|
-
] });
|
|
4295
|
-
};
|
|
4296
|
-
|
|
4297
|
-
const SvgAiChat = (props) => /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: 24, height: 24, viewBox: "0 0 24 24", ...props }, /* @__PURE__ */ React.createElement("path", { d: "M20.488 7.014A1.51 1.51 0 0 1 22 8.513v8.991a1.51 1.51 0 0 1-1.512 1.499H9.9L6.875 22v-9.975l.757-2.763 6.404-2.248zm-9.831 7.493a.756.756 0 0 0-.757.75c0 .412.34.749.757.749h7.562a.755.755 0 0 0 .756-.75.755.755 0 0 0-.756-.749zm0-2.248a.756.756 0 0 0-.757.75c0 .412.34.749.757.749h7.562a.755.755 0 0 0 .756-.75.755.755 0 0 0-.756-.749zm0-2.248a.756.756 0 0 0-.757.75c0 .412.34.749.757.749h7.562a.755.755 0 0 0 .756-.75.755.755 0 0 0-.756-.749z" }), /* @__PURE__ */ React.createElement("path", { d: "m6.56 5.49 3.811 1.36L6.56 8.213l-1.373 3.776L3.81 8.213 0 6.85l3.81-1.36 1.376-3.778zm3.639-3.607 1.9.685-1.9.687-.692 1.883-.692-1.883-1.901-.687 1.9-.685L9.508 0z" }));
|
|
4298
|
-
|
|
4299
|
-
const SvgAiEdit = (props) => /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: 24, height: 24, viewBox: "0 0 24 24", ...props }, /* @__PURE__ */ React.createElement("path", { d: "M18.655 10.414 7.218 21.844A.5.5 0 0 1 6.85 22H3.666a.52.52 0 0 1-.524-.523V18.29q0-.22.157-.376l11.428-11.43zM6.814 5.756l3.96 1.427-3.96 1.43-1.427 3.958L3.96 8.612 0 7.183l3.959-1.427 1.428-3.96zM18.503 3.14a1.05 1.05 0 0 1 .74.307l2.45 2.45a1.05 1.05 0 0 1 .227 1.14q-.08.19-.227.338l-1.916 1.917-3.928-3.929 1.916-1.916a1.05 1.05 0 0 1 .738-.307m-7.908-1.165 1.975.718-1.975.72-.718 1.975-.72-1.975-1.975-.72 1.975-.718L9.877 0z" }));
|
|
4300
|
-
|
|
4301
|
-
const SvgAiForm = (props) => /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: 24, height: 24, viewBox: "0 0 24 24", ...props }, /* @__PURE__ */ React.createElement("path", { fillRule: "evenodd", d: "M22 6c1.1 0 2 .9 2 2v14c0 1.1-.9 2-2 2H8c-1.1 0-2-.9-2-2v-9.17c0-.53.21-1.04.59-1.41l4.83-4.83c.37-.38.88-.59 1.41-.59zM11 18c-.55 0-1 .45-1 1s.45 1 1 1h8c.55 0 1-.45 1-1s-.45-1-1-1zm0-4c-.55 0-1 .45-1 1s.45 1 1 1h8c.55 0 1-.45 1-1s-.45-1-1-1zm3-4c-.55 0-1 .45-1 1s.45 1 1 1h5c.55 0 1-.45 1-1s-.45-1-1-1z", clipRule: "evenodd" }), /* @__PURE__ */ React.createElement("path", { d: "m6.505 5.495 3.781 1.363-3.78 1.363L5.142 12 3.78 8.22 0 6.859l3.78-1.363 1.363-3.78zm3.61-3.608L12 2.572l-1.885.686-.687 1.885-.686-1.885-1.885-.686 1.885-.685L9.428 0z" }));
|
|
4302
|
-
|
|
4303
|
-
const SvgAiMic = (props) => /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: 24, height: 24, viewBox: "0 0 24 24", ...props }, /* @__PURE__ */ React.createElement("path", { d: "M21.513 13.737c.595 0 1.071.554.974 1.17a7.3 7.3 0 0 1-1.958 3.959 6.7 6.7 0 0 1-3.805 1.973v2.134c0 .565-.439 1.027-.975 1.027s-.974-.462-.974-1.027V20.84c-2.945-.441-5.287-2.854-5.765-5.933-.087-.615.381-1.169.976-1.169.232.002.456.09.631.25s.29.38.324.622c.4 2.412 2.4 4.26 4.808 4.26s4.408-1.848 4.808-4.26c.078-.503.479-.872.956-.872" }), /* @__PURE__ */ React.createElement("path", { d: "M15.749 4.5c1.619 0 2.925 1.375 2.925 3.08v6.157c0 1.704-1.306 3.08-2.925 3.08s-2.925-1.376-2.926-3.08V7.58c0-1.703 1.307-3.079 2.926-3.079m-7.743.994 3.78 1.362-3.78 1.364L6.643 12 5.28 8.22 1.5 6.858l3.78-1.362 1.363-3.781zm3.609-3.61 1.885.686-1.885.687-.685 1.885-.688-1.885-1.885-.687 1.885-.686L10.93 0z" }));
|
|
4304
|
-
|
|
4305
|
-
const SvgAiSearch = (props) => /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: 24, height: 24, viewBox: "0 0 24 24", ...props }, /* @__PURE__ */ React.createElement("path", { fillRule: "evenodd", d: "M11.757 7.838a6.3 6.3 0 0 1 2.828-.288c2.71.329 4.955 2.476 5.41 5.165a6.28 6.28 0 0 1-1.431 5.165l.27.26h.765l4.104 4.121a1.02 1.02 0 0 1 0 1.442 1.024 1.024 0 0 1-1.443 0l-4.112-4.11v-.765l-.262-.271a6.29 6.29 0 0 1-5.168 1.43c-2.69-.454-4.84-2.698-5.168-5.406a6.29 6.29 0 0 1 4.207-6.743m2.034 1.599a4.35 4.35 0 0 0-4.355 4.352 4.35 4.35 0 0 0 4.355 4.352 4.35 4.35 0 0 0 4.357-4.352 4.35 4.35 0 0 0-4.357-4.352", clipRule: "evenodd" }), /* @__PURE__ */ React.createElement("path", { d: "m6.505 5.495 3.781 1.362-3.78 1.364L5.142 12 3.779 8.22 0 6.858l3.78-1.362 1.363-3.781zm3.61-3.61L12 2.571l-1.885.687-.686 1.885-.687-1.885-1.885-.687 1.885-.686L9.43 0z" }));
|
|
4306
|
-
|
|
4307
|
-
const AI_ICON_MAP = {
|
|
4308
|
-
chat: SvgAiChat,
|
|
4309
|
-
edit: SvgAiEdit,
|
|
4310
|
-
form: SvgAiForm,
|
|
4311
|
-
mic: SvgAiMic,
|
|
4312
|
-
search: SvgAiSearch
|
|
4313
|
-
};
|
|
4314
|
-
const ICON_ONLY_AI_SIZE_PX = {
|
|
4315
|
-
xsmall: 12,
|
|
4316
|
-
small: 14,
|
|
4317
|
-
medium: 24,
|
|
4318
|
-
large: 24
|
|
4319
|
-
};
|
|
4320
|
-
function iconHasLeadingSlot(icon) {
|
|
4321
|
-
if (!icon) {
|
|
4322
|
-
return false;
|
|
4323
|
-
}
|
|
4324
|
-
if (typeof icon !== "object") {
|
|
4325
|
-
return true;
|
|
4326
|
-
}
|
|
4327
|
-
return "before" in icon;
|
|
4328
|
-
}
|
|
4329
|
-
function aiMarkShowsAnimatedMark(aiMark) {
|
|
4330
|
-
return aiMark === true || aiMark === "mark";
|
|
4331
|
-
}
|
|
4332
|
-
|
|
4333
|
-
const Button = forwardRef(
|
|
4334
|
-
(props, ref) => {
|
|
4335
|
-
const { layoutStyles, componentProps } = useLayoutPropsUtil(props);
|
|
4336
|
-
const {
|
|
4337
|
-
aiMark,
|
|
4338
|
-
children,
|
|
4339
|
-
className,
|
|
4340
|
-
appearance = "secondary",
|
|
4341
|
-
size = "medium",
|
|
4342
|
-
icon,
|
|
4343
|
-
loading = false,
|
|
4344
|
-
disabled,
|
|
4345
|
-
style,
|
|
4346
|
-
type = "button",
|
|
4347
|
-
onMouseEnter,
|
|
4348
|
-
onMouseLeave,
|
|
4349
|
-
onFocus,
|
|
4350
|
-
onBlur,
|
|
4351
|
-
...rest
|
|
4352
|
-
} = componentProps;
|
|
4353
|
-
const aiOn = !!aiMark;
|
|
4354
|
-
const isIconOnly = !children;
|
|
4355
|
-
if (aiOn && icon) {
|
|
4356
|
-
if (isIconOnly) {
|
|
4357
|
-
warnOnce(
|
|
4358
|
-
"[Anvil2 Button] The `icon` prop is ignored when `aiMark` is set on an icon-only button. Only the AI icon is rendered."
|
|
4359
|
-
);
|
|
4360
|
-
} else if (iconHasLeadingSlot(icon)) {
|
|
4361
|
-
warnOnce(
|
|
4362
|
-
"[Anvil2 Button] The leading `icon` (plain Svg or `icon.before`) is ignored when `aiMark` is set with button text. Use `icon={{ after: Svg }}` for a trailing icon, or omit `icon`."
|
|
4363
|
-
);
|
|
4364
|
-
}
|
|
4365
|
-
}
|
|
4366
|
-
const data = {
|
|
4367
|
-
children: childrenToString(props.children),
|
|
4368
|
-
appearance,
|
|
4369
|
-
icon,
|
|
4370
|
-
size,
|
|
4371
|
-
type,
|
|
4372
|
-
aiMark
|
|
4373
|
-
};
|
|
4374
|
-
const trackingId = useTrackingId({
|
|
4375
|
-
name: "Button",
|
|
4376
|
-
data,
|
|
4377
|
-
hasOverride: !!props["data-tracking-id"]
|
|
4378
|
-
});
|
|
4379
|
-
const [isHovered, setIsHovered] = useState(false);
|
|
4380
|
-
const [isFocused, setIsFocused] = useState(false);
|
|
4381
|
-
const isAnimated = isHovered || isFocused;
|
|
4382
|
-
const inheritColorForMark = appearance !== "secondary" && appearance !== "ghost";
|
|
4383
|
-
const renderStandardLeading = useCallback(() => {
|
|
4384
|
-
if (typeof icon === "object" && icon !== null && "before" in icon) {
|
|
4385
|
-
return /* @__PURE__ */ jsx(
|
|
4386
|
-
Icon,
|
|
4387
|
-
{
|
|
4388
|
-
className: styles["icon"],
|
|
4389
|
-
inherit: true,
|
|
4390
|
-
"aria-hidden": true,
|
|
4391
|
-
svg: icon.before
|
|
4392
|
-
}
|
|
4393
|
-
);
|
|
4394
|
-
}
|
|
4395
|
-
if (icon && typeof icon !== "object") {
|
|
4396
|
-
return /* @__PURE__ */ jsx(
|
|
4397
|
-
Icon,
|
|
4398
|
-
{
|
|
4399
|
-
className: styles["icon"],
|
|
4400
|
-
inherit: true,
|
|
4401
|
-
"aria-hidden": true,
|
|
4402
|
-
svg: icon,
|
|
4403
|
-
size: !children && !size.includes("small") ? "large" : "medium"
|
|
4404
|
-
}
|
|
4405
|
-
);
|
|
4406
|
-
}
|
|
4407
|
-
return null;
|
|
4408
|
-
}, [icon, children, size]);
|
|
4409
|
-
const renderAiLeading = useCallback(() => {
|
|
4410
|
-
if (aiMarkShowsAnimatedMark(aiMark)) {
|
|
4411
|
-
return /* @__PURE__ */ jsx(
|
|
4412
|
-
AiMarkIconAnimated,
|
|
4413
|
-
{
|
|
4414
|
-
animate: isAnimated,
|
|
4415
|
-
inheritColor: inheritColorForMark,
|
|
4416
|
-
size: isIconOnly ? ICON_ONLY_AI_SIZE_PX[size] : void 0,
|
|
4417
|
-
spin: true
|
|
4418
|
-
}
|
|
4419
|
-
);
|
|
4420
|
-
}
|
|
4421
|
-
const SvgIcon = AI_ICON_MAP[aiMark];
|
|
4422
|
-
return /* @__PURE__ */ jsx(
|
|
4423
|
-
Icon,
|
|
4424
|
-
{
|
|
4425
|
-
className: styles["icon"],
|
|
4426
|
-
inherit: true,
|
|
4427
|
-
"aria-hidden": true,
|
|
4428
|
-
"data-anv": "ai-mark-icon",
|
|
4429
|
-
svg: SvgIcon,
|
|
4430
|
-
size: isIconOnly && !size.includes("small") ? "large" : "medium"
|
|
4431
|
-
}
|
|
4432
|
-
);
|
|
4433
|
-
}, [aiMark, isAnimated, inheritColorForMark, isIconOnly, size]);
|
|
4434
|
-
const leadingContent = useMemo(() => {
|
|
4435
|
-
if (loading) {
|
|
4436
|
-
return /* @__PURE__ */ jsx(Spinner, { inherit: true, size: "small", className: styles["loading-spinner"] });
|
|
4437
|
-
}
|
|
4438
|
-
if (aiOn) {
|
|
4439
|
-
return renderAiLeading();
|
|
4440
|
-
}
|
|
4441
|
-
return renderStandardLeading();
|
|
4442
|
-
}, [aiOn, loading, renderAiLeading, renderStandardLeading]);
|
|
4443
|
-
const trailingAfter = !isIconOnly && typeof icon === "object" && "after" in icon ? /* @__PURE__ */ jsx(Icon, { className: styles["icon"], inherit: true, "aria-hidden": true, svg: icon.after }) : null;
|
|
4444
|
-
const buttonClassNames = cx(className, styles["button"], {
|
|
4445
|
-
[styles["appearance-primary"]]: appearance === "primary",
|
|
4446
|
-
[styles["appearance-secondary"]]: appearance === "secondary",
|
|
4447
|
-
[styles["appearance-ghost"]]: appearance === "ghost",
|
|
4448
|
-
[styles["danger-secondary"]]: appearance === "danger-secondary",
|
|
4449
|
-
[styles["danger-primary"]]: appearance === "danger",
|
|
4450
|
-
[styles["size-xsmall"]]: size === "xsmall",
|
|
4451
|
-
[styles["size-small"]]: size === "small",
|
|
4452
|
-
[styles["size-medium"]]: size === "medium",
|
|
4453
|
-
[styles["size-large"]]: size === "large",
|
|
4454
|
-
[styles["type-icon"]]: isIconOnly,
|
|
4455
|
-
[styles["loading"]]: loading
|
|
4456
|
-
});
|
|
4457
|
-
const styleCombined = {
|
|
4458
|
-
...style,
|
|
4459
|
-
...layoutStyles
|
|
4460
|
-
};
|
|
4461
|
-
const handleMouseEnter = useCallback(
|
|
4462
|
-
(e) => {
|
|
4463
|
-
setIsHovered(true);
|
|
4464
|
-
onMouseEnter?.(e);
|
|
4465
|
-
},
|
|
4466
|
-
[onMouseEnter]
|
|
4467
|
-
);
|
|
4468
|
-
const handleMouseLeave = useCallback(
|
|
4469
|
-
(e) => {
|
|
4470
|
-
setIsHovered(false);
|
|
4471
|
-
onMouseLeave?.(e);
|
|
4472
|
-
},
|
|
4473
|
-
[onMouseLeave]
|
|
4474
|
-
);
|
|
4475
|
-
const handleFocus = useCallback(
|
|
4476
|
-
(e) => {
|
|
4477
|
-
setIsFocused(true);
|
|
4478
|
-
onFocus?.(e);
|
|
4479
|
-
},
|
|
4480
|
-
[onFocus]
|
|
4481
|
-
);
|
|
4482
|
-
const handleBlur = useCallback(
|
|
4483
|
-
(e) => {
|
|
4484
|
-
setIsFocused(false);
|
|
4485
|
-
onBlur?.(e);
|
|
4486
|
-
},
|
|
4487
|
-
[onBlur]
|
|
4488
|
-
);
|
|
4489
|
-
return /* @__PURE__ */ jsxs(
|
|
4490
|
-
"button",
|
|
4491
|
-
{
|
|
4492
|
-
"data-tracking-id": trackingId,
|
|
4493
|
-
className: buttonClassNames,
|
|
4494
|
-
type,
|
|
4495
|
-
disabled: disabled || loading,
|
|
4496
|
-
"aria-busy": loading ? true : void 0,
|
|
4497
|
-
"data-anv": "button",
|
|
4498
|
-
style: styleCombined,
|
|
4499
|
-
ref,
|
|
4500
|
-
onMouseEnter: handleMouseEnter,
|
|
4501
|
-
onMouseLeave: handleMouseLeave,
|
|
4502
|
-
onFocus: handleFocus,
|
|
4503
|
-
onBlur: handleBlur,
|
|
4504
|
-
...rest,
|
|
4505
|
-
children: [
|
|
4506
|
-
leadingContent,
|
|
4507
|
-
children,
|
|
4508
|
-
trailingAfter
|
|
4509
|
-
]
|
|
4510
|
-
}
|
|
4511
|
-
);
|
|
4512
|
-
}
|
|
4513
|
-
);
|
|
4514
|
-
Button.displayName = "Button";
|
|
4515
|
-
|
|
4516
|
-
export { AiMarkIconAnimated as A, Button as B };
|
|
4517
|
-
//# sourceMappingURL=Button-a_D7tUgM.js.map
|