mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-04-14 16:40:58 -04:00
Compare commits
4 commits
9978a7d020
...
1074b34058
Author | SHA1 | Date | |
---|---|---|---|
|
1074b34058 | ||
|
dff69e9191 | ||
|
e7ab347f15 | ||
|
e3bdb9f5cd |
46 changed files with 124 additions and 153 deletions
|
@ -17,7 +17,7 @@ VITE_APP_FIREBASE_CONFIG='{"apiKey":"AIzaSyCMkxA60XIW8KbqMYL7edC4qT5l4qHX2h8","a
|
|||
# put these in your .env.local, or make sure you don't commit!
|
||||
# must be lowercase `true` when turned on
|
||||
#
|
||||
# whether to disable live reload / HMR. Usuaully what you want to do when
|
||||
# whether to disable live reload / HMR. Usually what you want to do when
|
||||
# debugging Service Workers.
|
||||
VITE_APP_DEV_DISABLE_LIVE_RELOAD=
|
||||
VITE_APP_ENABLE_TRACKING=true
|
||||
|
|
|
@ -27,7 +27,7 @@ You can customize which welcome screen subcomponents are rendered by passing the
|
|||
The welcome screen consists of two main groups of subcomponents:
|
||||
|
||||
1. [WelcomeScreen.Center](#welcomescreencenterlogo).
|
||||
2. [WeelcomeScreen.Hints](#welcomescreenhints).
|
||||
2. [WelcomeScreen.Hints](#welcomescreenhints).
|
||||
|
||||
<img
|
||||
src={require("@site/static/img/welcome-screen-overview.png").default}
|
||||
|
|
|
@ -16,7 +16,7 @@ import { FONT_FAMILY } from "@excalidraw/excalidraw";
|
|||
| `Nunito` | The `Normal` Font |
|
||||
| `Comic Shanns` | The `Code` Font |
|
||||
|
||||
Pre-selected family is `FONT_FAMILY.Excalifont`, unless it's overriden with `initialData.appState.currentItemFontFamily`.
|
||||
Pre-selected family is `FONT_FAMILY.Excalifont`, unless it's overridden with `initialData.appState.currentItemFontFamily`.
|
||||
|
||||
### THEME
|
||||
|
||||
|
|
|
@ -164,7 +164,7 @@ convertToExcalidrawElements([
|
|||
|
||||

|
||||
|
||||
#### With Addtional properties
|
||||
#### With Additional properties
|
||||
|
||||
```js
|
||||
convertToExcalidrawElements([
|
||||
|
|
|
@ -65,7 +65,7 @@ You can use this function to update the scene with the sceneData. It accepts the
|
|||
| `elements` | [`ImportedDataState["elements"]`](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/data/types.ts#L38) | The `elements` to be updated in the scene |
|
||||
| `appState` | [`ImportedDataState["appState"]`](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/data/types.ts#L39) | The `appState` to be updated in the scene. |
|
||||
| `collaborators` | <code>Map<string, <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L37">Collaborator></a></code> | The list of collaborators to be updated in the scene. |
|
||||
| `captureUpdate` | [`CaptureUpdateAction`](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/store.ts#L40) | Controls which updates should be captured by the `Store`. Captured updates are emmitted and listened to by other components, such as `History` for undo / redo purposes. |
|
||||
| `captureUpdate` | [`CaptureUpdateAction`](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/store.ts#L40) | Controls which updates should be captured by the `Store`. Captured updates are emitted and listened to by other components, such as `History` for undo / redo purposes. |
|
||||
|
||||
```jsx live
|
||||
function App() {
|
||||
|
@ -333,7 +333,7 @@ This API can be used to show the toast with custom message.
|
|||
| --- | --- | --- |
|
||||
| message | string | The message to be shown on the toast. |
|
||||
| closable | boolean | Indicates whether to show the closable button on toast to dismiss the toast. |
|
||||
| duration | number | Determines the duration after which the toast should auto dismiss. To prevent autodimiss you can pass `Infinity`. |
|
||||
| duration | number | Determines the duration after which the toast should auto dismiss. To prevent autodismiss you can pass `Infinity`. |
|
||||
|
||||
To dismiss an existing toast you can simple pass `null`
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ function App() {
|
|||
|
||||
### exportOpts
|
||||
|
||||
The below attributes can be set in `UIOptions.canvasActions.export` to customize the export dialog.
|
||||
The below attributes can be set in `UIOptions.canvasActions.export` to customize the export dialog.
|
||||
If `UIOptions.canvasActions.export` is `false` the export button will not be rendered.
|
||||
|
||||
| Prop | Type | Default | Description |
|
||||
|
@ -55,9 +55,9 @@ If `UIOptions.canvasActions.export` is `false` the export button will not be ren
|
|||
|
||||
## dockedSidebarBreakpoint
|
||||
|
||||
This prop indicates at what point should we break to a docked, permanent sidebar. If not passed it defaults to [`MQ_RIGHT_SIDEBAR_MAX_WIDTH_PORTRAIT`](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/constants.ts#L161).
|
||||
If the _width_ of the _excalidraw_ container exceeds _dockedSidebarBreakpoint_, the sidebar will be `dockable` and the button to `dock` the sidebar will be shown
|
||||
If user choses to `dock` the sidebar, it will push the right part of the UI towards the left, making space for the sidebar as shown below.
|
||||
This prop indicates at what point should we break to a docked, permanent sidebar. If not passed it defaults to [`MQ_RIGHT_SIDEBAR_MAX_WIDTH_PORTRAIT`](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/constants.ts#L161).
|
||||
If the _width_ of the _excalidraw_ container exceeds _dockedSidebarBreakpoint_, the sidebar will be `dockable` and the button to `dock` the sidebar will be shown
|
||||
If user chooses to `dock` the sidebar, it will push the right part of the UI towards the left, making space for the sidebar as shown below.
|
||||
|
||||

|
||||
|
||||
|
|
|
@ -88,7 +88,7 @@ loadFromBlob(<br/>
|
|||
|
||||
### loadLibraryFromBlob
|
||||
|
||||
This function loads the library from the blob. Additonally takes `defaultStatus` param which sets the default status for library item if not present, defaults to `unpublished`.
|
||||
This function loads the library from the blob. Additionally takes `defaultStatus` param which sets the default status for library item if not present, defaults to `unpublished`.
|
||||
|
||||
**How to use **
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ We strongly recommend turning it off. You can follow the steps below on how to d
|
|||
3. Switch to **Block Fingerprinting**
|
||||

|
||||
|
||||
4. Thats all. All text elements should be fixed now 🎉
|
||||
4. That's all. All text elements should be fixed now 🎉
|
||||
|
||||
</div>
|
||||
|
||||
|
|
|
@ -33,11 +33,11 @@ or, if you serve your assets from the root of your CDN, you would do:
|
|||
<head>
|
||||
<script>
|
||||
window.EXCALIDRAW_ASSET_PATH = "https://my.cdn.com/assets/";
|
||||
</script>
|
||||
</script>
|
||||
</head>
|
||||
```
|
||||
|
||||
or, if you prefer the path to be dynamicly set based on the `location.origin`, you could do the following:
|
||||
or, if you prefer the path to be dynamically set based on the `location.origin`, you could do the following:
|
||||
|
||||
```jsx
|
||||
// Next.js
|
||||
|
|
|
@ -85,7 +85,7 @@ If you are using `pages router` then importing the wrapper dynamically would wor
|
|||
```jsx showLineNumbers
|
||||
import dynamic from "next/dynamic";
|
||||
|
||||
// Since client components get prerenderd on server as well hence importing
|
||||
// Since client components get pre-rendered on server as well hence importing
|
||||
// the excalidraw stuff dynamically with ssr false
|
||||
|
||||
const ExcalidrawWrapper = dynamic(
|
||||
|
|
|
@ -26,7 +26,7 @@ try {
|
|||
|
||||
## Supported Diagram Types
|
||||
|
||||
Currently only [flowcharts](https://mermaid.js.org/syntax/flowchart.html) are supported. Oother diagram types will be rendered as an image in Excalidraw.
|
||||
Currently only [flowcharts](https://mermaid.js.org/syntax/flowchart.html) are supported. Other diagram types will be rendered as an image in Excalidraw.
|
||||
|
||||
### Flowchart
|
||||
|
||||
|
|
|
@ -26,13 +26,13 @@ For this create a file named `{{diagramType}}.ts` in [`src/parser`](https://gith
|
|||
|
||||
The main aim of the parser is :point_down:
|
||||
|
||||
1. Determine how elements are connected in the diagram and thus finding arrow and text bindings.
|
||||
1. Determine how elements are connected in the diagram and thus finding arrow and text bindings.
|
||||
|
||||
For this you might have to dig in to the parser `diagram.parser.yy` and which attributes to parse for the new diagram.
|
||||
|
||||
2. Determine the position and dimensions of each element, for this would be using the `svg`
|
||||
|
||||
Once the parser is ready, lets start using it.
|
||||
Once the parser is ready, lets start using it.
|
||||
|
||||
Add the diagram type in switch case in [`parseMermaid`](https://github.com/excalidraw/mermaid-to-excalidraw/blob/master/src/parseMermaid.ts#L97) and call the parser for the same.
|
||||
|
||||
|
@ -42,7 +42,7 @@ With the completion of previous step, we have all the data, now we need to trans
|
|||
|
||||
Similar to [`FlowChartToExcalidrawSkeletonConverter`](https://github.com/excalidraw/mermaid-to-excalidraw/blob/master/src/converter/types/flowchart.ts#L24), you have to write the `{{diagramType}}ToExcalidrawSkeletonConverter` which parses the data received in previous step and returns the [ExcalidrawElementSkeleton](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/data/transform.ts#L133).
|
||||
|
||||
Thats it, you have added the new diagram type 🥳, now lets test it out!
|
||||
That's it, you have added the new diagram type 🥳, now lets test it out!
|
||||
|
||||
## Updating the Playground
|
||||
|
||||
|
|
|
@ -33,9 +33,9 @@ If the diagram isn't supported, this svg is converted to `dataURL` and can be re
|
|||
|
||||
### Parsing the mermaid syntax
|
||||
|
||||
For this we first need to process the options along with mermaid defination for diagram provided by the user.
|
||||
For this we first need to process the options along with mermaid definition for diagram provided by the user.
|
||||
|
||||
[`processMermaidTextWithOptions`](https://github.com/excalidraw/mermaid-to-excalidraw/blob/master/src/parseMermaid.ts#L13) takes the mermaid defination and options and returns the full defination including the mermaid [directives ](https://mermaid.js.org/config/directives.html).
|
||||
[`processMermaidTextWithOptions`](https://github.com/excalidraw/mermaid-to-excalidraw/blob/master/src/parseMermaid.ts#L13) takes the mermaid definition and options and returns the full definition including the mermaid [directives ](https://mermaid.js.org/config/directives.html).
|
||||
|
||||

|
||||
|
||||
|
@ -49,7 +49,7 @@ Next we write our own parser to parse this diagram.
|
|||
|
||||
### Parsing the Diagram
|
||||
|
||||
For each diagram type, we need a parser as the result of every diagram would differ and dependinng on the data we have to write the parser. Since currently we support flowchart, so here is the [`parseMermaidFlowChartDiagram`](https://github.com/excalidraw/mermaid-to-excalidraw/blob/master/src/parser/flowchart.ts#L256) to parse the flowchart diagram.
|
||||
For each diagram type, we need a parser as the result of every diagram would differ and depending on the data we have to write the parser. Since currently we support flowchart, so here is the [`parseMermaidFlowChartDiagram`](https://github.com/excalidraw/mermaid-to-excalidraw/blob/master/src/parser/flowchart.ts#L256) to parse the flowchart diagram.
|
||||
|
||||
If you want to understand how flowchart parser works, you can navigate to [Flowchart Parser](http://localhost:3003/docs/@excalidraw/mermaid-to-excalidraw/codebase/parser/flowchart).
|
||||
|
||||
|
@ -62,4 +62,4 @@ For Unsupported types, we have already mentioned above that we convert it to `da
|
|||
|
||||
For supported types, currently only flowchart, we have [flowchartConverter](https://github.com/excalidraw/mermaid-to-excalidraw/blob/master/src/converter/types/flowchart.ts#L24) which parses the data and converts to [ExcalidrawElementSkeleton](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/data/transform.ts#L133C13-L133C38).
|
||||
|
||||

|
||||

|
||||
|
|
|
@ -57,4 +57,4 @@ Update the package name and version in [package.json](https://github.com/excalid
|
|||
yarn publish
|
||||
```
|
||||
|
||||
And thats all your test release is successfully created 🎉
|
||||
And that's all your test release is successfully created 🎉
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
const nextConfig = {
|
||||
distDir: "build",
|
||||
typescript: {
|
||||
// The ts config doesn't work with `jsx: preserve" and if updated to `react-jsx` it gets ovewritten by next js throwing ts errors hence I am ignoring build errors until this is fixed.
|
||||
// The ts config doesn't work with `jsx: preserve" and if updated to `react-jsx` it gets overwritten by next js throwing ts errors hence I am ignoring build errors until this is fixed.
|
||||
ignoreBuildErrors: true,
|
||||
},
|
||||
// This is needed as in pages router the code for importing types throws error as its outside next js app
|
||||
// This is needed as in pages router the code for importing types throws error as it's outside next js app
|
||||
transpilePackages: ["../"],
|
||||
};
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ import Script from "next/script";
|
|||
|
||||
import "../common.scss";
|
||||
|
||||
// Since client components get prerenderd on server as well hence importing the excalidraw stuff dynamically
|
||||
// Since client components get pre-rendered on server as well hence importing the excalidraw stuff dynamically
|
||||
// with ssr false
|
||||
const ExcalidrawWithClientOnly = dynamic(
|
||||
async () => (await import("../excalidrawWrapper")).default,
|
||||
|
|
|
@ -2,7 +2,7 @@ import dynamic from "next/dynamic";
|
|||
|
||||
import "../common.scss";
|
||||
|
||||
// Since client components get prerenderd on server as well hence importing the excalidraw stuff dynamically
|
||||
// Since client components get pre-rendered on server as well hence importing the excalidraw stuff dynamically
|
||||
// with ssr false
|
||||
const Excalidraw = dynamic(
|
||||
async () => (await import("../excalidrawWrapper")).default,
|
||||
|
|
|
@ -20,7 +20,7 @@ export const updateBrowserStateVersion = (type: BrowserStateTypes) => {
|
|||
localStorage.setItem(type, JSON.stringify(timestamp));
|
||||
LOCAL_STATE_VERSIONS[type] = timestamp;
|
||||
} catch (error) {
|
||||
console.error("error while updating browser state verison", error);
|
||||
console.error("error while updating browser state version", error);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -34,6 +34,6 @@ export const resetBrowserStateVersions = () => {
|
|||
LOCAL_STATE_VERSIONS[key] = timestamp;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("error while resetting browser state verison", error);
|
||||
console.error("error while resetting browser state version", error);
|
||||
}
|
||||
};
|
||||
|
|
2
excalidraw-app/vite-env.d.ts
vendored
2
excalidraw-app/vite-env.d.ts
vendored
|
@ -17,7 +17,7 @@ interface ImportMetaEnv {
|
|||
|
||||
VITE_APP_FIREBASE_CONFIG: string;
|
||||
|
||||
// whether to disable live reload / HMR. Usuaully what you want to do when
|
||||
// whether to disable live reload / HMR. Usually what you want to do when
|
||||
// debugging Service Workers.
|
||||
VITE_APP_DEV_DISABLE_LIVE_RELOAD: string;
|
||||
|
||||
|
|
|
@ -134,7 +134,7 @@ export const DEFAULT_ELEMENT_STROKE_COLOR_PALETTE = {
|
|||
...COMMON_ELEMENT_SHADES,
|
||||
} as const;
|
||||
|
||||
// ORDER matters for positioning in pallete (5x3 grid)s
|
||||
// ORDER matters for positioning in palette (5x3 grid)s
|
||||
export const DEFAULT_ELEMENT_BACKGROUND_COLOR_PALETTE = {
|
||||
transparent: COLOR_PALETTE.transparent,
|
||||
white: COLOR_PALETTE.white,
|
||||
|
|
|
@ -62,7 +62,7 @@ export const POINTER_EVENTS = {
|
|||
enabled: "all",
|
||||
disabled: "none",
|
||||
// asserted as any so it can be freely assigned to React Element
|
||||
// "pointerEnvets" CSS prop
|
||||
// "pointerEvents" CSS prop
|
||||
inheritFromUI: "var(--ui-pointerEvents)" as any,
|
||||
} as const;
|
||||
|
||||
|
@ -361,8 +361,8 @@ export const ROUNDNESS = {
|
|||
PROPORTIONAL_RADIUS: 2,
|
||||
|
||||
// Current default algorithm for rectangles, using fixed pixel radius.
|
||||
// It's working similarly to a regular border-radius, but attemps to make
|
||||
// radius visually similar across differnt element sizes, especially
|
||||
// It's working similarly to a regular border-radius, but attempts to make
|
||||
// radius visually similar across different element sizes, especially
|
||||
// very large and very small elements.
|
||||
//
|
||||
// NOTE right now we don't allow configuration and use a constant radius
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import { average } from "@excalidraw/math";
|
||||
import { average, pointFrom, type GlobalPoint } from "@excalidraw/math";
|
||||
|
||||
import type {
|
||||
ExcalidrawBindableElement,
|
||||
FontFamilyValues,
|
||||
FontString,
|
||||
ExcalidrawElement,
|
||||
} from "@excalidraw/element/types";
|
||||
|
||||
import type {
|
||||
|
@ -1201,3 +1202,17 @@ export const escapeDoubleQuotes = (str: string) => {
|
|||
|
||||
export const castArray = <T>(value: T | T[]): T[] =>
|
||||
Array.isArray(value) ? value : [value];
|
||||
|
||||
export const elementCenterPoint = (
|
||||
element: ExcalidrawElement,
|
||||
xOffset: number = 0,
|
||||
yOffset: number = 0,
|
||||
) => {
|
||||
const { x, y, width, height } = element;
|
||||
|
||||
const centerXPoint = x + width / 2 + xOffset;
|
||||
|
||||
const centerYPoint = y + height / 2 + yOffset;
|
||||
|
||||
return pointFrom<GlobalPoint>(centerXPoint, centerYPoint);
|
||||
};
|
||||
|
|
|
@ -6,6 +6,7 @@ import {
|
|||
invariant,
|
||||
isDevEnv,
|
||||
isTestEnv,
|
||||
elementCenterPoint,
|
||||
} from "@excalidraw/common";
|
||||
|
||||
import {
|
||||
|
@ -904,13 +905,7 @@ export const getHeadingForElbowArrowSnap = (
|
|||
|
||||
if (!distance) {
|
||||
return vectorToHeading(
|
||||
vectorFromPoint(
|
||||
p,
|
||||
pointFrom<GlobalPoint>(
|
||||
bindableElement.x + bindableElement.width / 2,
|
||||
bindableElement.y + bindableElement.height / 2,
|
||||
),
|
||||
),
|
||||
vectorFromPoint(p, elementCenterPoint(bindableElement)),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1040,10 +1035,7 @@ export const avoidRectangularCorner = (
|
|||
element: ExcalidrawBindableElement,
|
||||
p: GlobalPoint,
|
||||
): GlobalPoint => {
|
||||
const center = pointFrom<GlobalPoint>(
|
||||
element.x + element.width / 2,
|
||||
element.y + element.height / 2,
|
||||
);
|
||||
const center = elementCenterPoint(element);
|
||||
const nonRotatedPoint = pointRotateRads(p, center, -element.angle as Radians);
|
||||
|
||||
if (nonRotatedPoint[0] < element.x && nonRotatedPoint[1] < element.y) {
|
||||
|
@ -1140,10 +1132,9 @@ export const snapToMid = (
|
|||
tolerance: number = 0.05,
|
||||
): GlobalPoint => {
|
||||
const { x, y, width, height, angle } = element;
|
||||
const center = pointFrom<GlobalPoint>(
|
||||
x + width / 2 - 0.1,
|
||||
y + height / 2 - 0.1,
|
||||
);
|
||||
|
||||
const center = elementCenterPoint(element, -0.1, -0.1);
|
||||
|
||||
const nonRotated = pointRotateRads(p, center, -angle as Radians);
|
||||
|
||||
// snap-to-center point is adaptive to element size, but we don't want to go
|
||||
|
@ -1228,10 +1219,7 @@ const updateBoundPoint = (
|
|||
startOrEnd === "startBinding" ? "start" : "end",
|
||||
elementsMap,
|
||||
).fixedPoint;
|
||||
const globalMidPoint = pointFrom<GlobalPoint>(
|
||||
bindableElement.x + bindableElement.width / 2,
|
||||
bindableElement.y + bindableElement.height / 2,
|
||||
);
|
||||
const globalMidPoint = elementCenterPoint(bindableElement);
|
||||
const global = pointFrom<GlobalPoint>(
|
||||
bindableElement.x + fixedPoint[0] * bindableElement.width,
|
||||
bindableElement.y + fixedPoint[1] * bindableElement.height,
|
||||
|
@ -1275,10 +1263,7 @@ const updateBoundPoint = (
|
|||
elementsMap,
|
||||
);
|
||||
|
||||
const center = pointFrom<GlobalPoint>(
|
||||
bindableElement.x + bindableElement.width / 2,
|
||||
bindableElement.y + bindableElement.height / 2,
|
||||
);
|
||||
const center = elementCenterPoint(bindableElement);
|
||||
const interceptorLength =
|
||||
pointDistance(adjacentPoint, edgePointAbsolute) +
|
||||
pointDistance(adjacentPoint, center) +
|
||||
|
@ -1771,10 +1756,7 @@ const determineFocusDistance = (
|
|||
// Another point on the line, in absolute coordinates (closer to element)
|
||||
b: GlobalPoint,
|
||||
): number => {
|
||||
const center = pointFrom<GlobalPoint>(
|
||||
element.x + element.width / 2,
|
||||
element.y + element.height / 2,
|
||||
);
|
||||
const center = elementCenterPoint(element);
|
||||
|
||||
if (pointsEqual(a, b)) {
|
||||
return 0;
|
||||
|
@ -1904,10 +1886,7 @@ const determineFocusPoint = (
|
|||
focus: number,
|
||||
adjacentPoint: GlobalPoint,
|
||||
): GlobalPoint => {
|
||||
const center = pointFrom<GlobalPoint>(
|
||||
element.x + element.width / 2,
|
||||
element.y + element.height / 2,
|
||||
);
|
||||
const center = elementCenterPoint(element);
|
||||
|
||||
if (focus === 0) {
|
||||
return center;
|
||||
|
@ -2338,10 +2317,7 @@ export const getGlobalFixedPointForBindableElement = (
|
|||
element.x + element.width * fixedX,
|
||||
element.y + element.height * fixedY,
|
||||
),
|
||||
pointFrom<GlobalPoint>(
|
||||
element.x + element.width / 2,
|
||||
element.y + element.height / 2,
|
||||
),
|
||||
elementCenterPoint(element),
|
||||
element.angle,
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { isTransparent } from "@excalidraw/common";
|
||||
import { isTransparent, elementCenterPoint } from "@excalidraw/common";
|
||||
import {
|
||||
curveIntersectLineSegment,
|
||||
isPointWithinBounds,
|
||||
|
@ -16,7 +16,7 @@ import {
|
|||
} from "@excalidraw/math/ellipse";
|
||||
|
||||
import { isPointInShape, isPointOnShape } from "@excalidraw/utils/collision";
|
||||
import { getPolygonShape } from "@excalidraw/utils/shape";
|
||||
import { type GeometricShape, getPolygonShape } from "@excalidraw/utils/shape";
|
||||
|
||||
import type {
|
||||
GlobalPoint,
|
||||
|
@ -26,8 +26,6 @@ import type {
|
|||
Radians,
|
||||
} from "@excalidraw/math";
|
||||
|
||||
import type { GeometricShape } from "@excalidraw/utils/shape";
|
||||
|
||||
import type { FrameNameBounds } from "@excalidraw/excalidraw/types";
|
||||
|
||||
import { getBoundTextShape, isPathALoop } from "./shapes";
|
||||
|
@ -92,7 +90,7 @@ export const hitElementItself = <Point extends GlobalPoint | LocalPoint>({
|
|||
frameNameBound = null,
|
||||
}: HitTestArgs<Point>) => {
|
||||
let hit = shouldTestInside(element)
|
||||
? // Since `inShape` tests STRICTLY againt the insides of a shape
|
||||
? // Since `inShape` tests STRICTLY against the insides of a shape
|
||||
// we would need `onShape` as well to include the "borders"
|
||||
isPointInShape(pointFrom(x, y), shape) ||
|
||||
isPointOnShape(pointFrom(x, y), shape, threshold)
|
||||
|
@ -191,10 +189,7 @@ const intersectRectanguloidWithLineSegment = (
|
|||
l: LineSegment<GlobalPoint>,
|
||||
offset: number = 0,
|
||||
): GlobalPoint[] => {
|
||||
const center = pointFrom<GlobalPoint>(
|
||||
element.x + element.width / 2,
|
||||
element.y + element.height / 2,
|
||||
);
|
||||
const center = elementCenterPoint(element);
|
||||
// To emulate a rotated rectangle we rotate the point in the inverse angle
|
||||
// instead. It's all the same distance-wise.
|
||||
const rotatedA = pointRotateRads<GlobalPoint>(
|
||||
|
@ -253,10 +248,7 @@ const intersectDiamondWithLineSegment = (
|
|||
l: LineSegment<GlobalPoint>,
|
||||
offset: number = 0,
|
||||
): GlobalPoint[] => {
|
||||
const center = pointFrom<GlobalPoint>(
|
||||
element.x + element.width / 2,
|
||||
element.y + element.height / 2,
|
||||
);
|
||||
const center = elementCenterPoint(element);
|
||||
|
||||
// Rotate the point to the inverse direction to simulate the rotated diamond
|
||||
// points. It's all the same distance-wise.
|
||||
|
@ -304,10 +296,7 @@ const intersectEllipseWithLineSegment = (
|
|||
l: LineSegment<GlobalPoint>,
|
||||
offset: number = 0,
|
||||
): GlobalPoint[] => {
|
||||
const center = pointFrom<GlobalPoint>(
|
||||
element.x + element.width / 2,
|
||||
element.y + element.height / 2,
|
||||
);
|
||||
const center = elementCenterPoint(element);
|
||||
|
||||
const rotatedA = pointRotateRads(l[0], center, -element.angle as Radians);
|
||||
const rotatedB = pointRotateRads(l[1], center, -element.angle as Radians);
|
||||
|
|
|
@ -14,6 +14,8 @@ import {
|
|||
} from "@excalidraw/math";
|
||||
import { type Point } from "points-on-curve";
|
||||
|
||||
import { elementCenterPoint } from "@excalidraw/common";
|
||||
|
||||
import {
|
||||
getElementAbsoluteCoords,
|
||||
getResizedElementAbsoluteCoords,
|
||||
|
@ -61,7 +63,7 @@ export const cropElement = (
|
|||
|
||||
const rotatedPointer = pointRotateRads(
|
||||
pointFrom(pointerX, pointerY),
|
||||
pointFrom(element.x + element.width / 2, element.y + element.height / 2),
|
||||
elementCenterPoint(element),
|
||||
-element.angle as Radians,
|
||||
);
|
||||
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import {
|
||||
curvePointDistance,
|
||||
distanceToLineSegment,
|
||||
pointFrom,
|
||||
pointRotateRads,
|
||||
} from "@excalidraw/math";
|
||||
|
||||
import { ellipse, ellipseDistanceFromPoint } from "@excalidraw/math/ellipse";
|
||||
|
||||
import { elementCenterPoint } from "@excalidraw/common";
|
||||
|
||||
import type { GlobalPoint, Radians } from "@excalidraw/math";
|
||||
|
||||
import {
|
||||
|
@ -47,16 +48,13 @@ export const distanceToBindableElement = (
|
|||
*
|
||||
* @param element The rectanguloid element
|
||||
* @param p The point to consider
|
||||
* @returns The eucledian distance to the outline of the rectanguloid element
|
||||
* @returns The euclidean distance to the outline of the rectanguloid element
|
||||
*/
|
||||
const distanceToRectanguloidElement = (
|
||||
element: ExcalidrawRectanguloidElement,
|
||||
p: GlobalPoint,
|
||||
) => {
|
||||
const center = pointFrom<GlobalPoint>(
|
||||
element.x + element.width / 2,
|
||||
element.y + element.height / 2,
|
||||
);
|
||||
const center = elementCenterPoint(element);
|
||||
// To emulate a rotated rectangle we rotate the point in the inverse angle
|
||||
// instead. It's all the same distance-wise.
|
||||
const rotatedPoint = pointRotateRads(p, center, -element.angle as Radians);
|
||||
|
@ -78,16 +76,13 @@ const distanceToRectanguloidElement = (
|
|||
*
|
||||
* @param element The diamond element
|
||||
* @param p The point to consider
|
||||
* @returns The eucledian distance to the outline of the diamond
|
||||
* @returns The euclidean distance to the outline of the diamond
|
||||
*/
|
||||
const distanceToDiamondElement = (
|
||||
element: ExcalidrawDiamondElement,
|
||||
p: GlobalPoint,
|
||||
): number => {
|
||||
const center = pointFrom<GlobalPoint>(
|
||||
element.x + element.width / 2,
|
||||
element.y + element.height / 2,
|
||||
);
|
||||
const center = elementCenterPoint(element);
|
||||
|
||||
// Rotate the point to the inverse direction to simulate the rotated diamond
|
||||
// points. It's all the same distance-wise.
|
||||
|
@ -109,16 +104,13 @@ const distanceToDiamondElement = (
|
|||
*
|
||||
* @param element The ellipse element
|
||||
* @param p The point to consider
|
||||
* @returns The eucledian distance to the outline of the ellipse
|
||||
* @returns The euclidean distance to the outline of the ellipse
|
||||
*/
|
||||
const distanceToEllipseElement = (
|
||||
element: ExcalidrawEllipseElement,
|
||||
p: GlobalPoint,
|
||||
): number => {
|
||||
const center = pointFrom(
|
||||
element.x + element.width / 2,
|
||||
element.y + element.height / 2,
|
||||
);
|
||||
const center = elementCenterPoint(element);
|
||||
return ellipseDistanceFromPoint(
|
||||
// Instead of rotating the ellipse, rotate the point to the inverse angle
|
||||
pointRotateRads(p, center, -element.angle as Radians),
|
||||
|
|
|
@ -4,6 +4,7 @@ import {
|
|||
LINE_CONFIRM_THRESHOLD,
|
||||
ROUNDNESS,
|
||||
invariant,
|
||||
elementCenterPoint,
|
||||
} from "@excalidraw/common";
|
||||
import {
|
||||
isPoint,
|
||||
|
@ -297,7 +298,7 @@ export const aabbForElement = (
|
|||
midY: element.y + element.height / 2,
|
||||
};
|
||||
|
||||
const center = pointFrom(bbox.midX, bbox.midY);
|
||||
const center = elementCenterPoint(element);
|
||||
const [topLeftX, topLeftY] = pointRotateRads(
|
||||
pointFrom(bbox.minX, bbox.minY),
|
||||
center,
|
||||
|
|
|
@ -56,7 +56,7 @@ const COMMON = {
|
|||
/**
|
||||
* Generally do not break, unless closed symbol is followed by an opening symbol.
|
||||
*
|
||||
* Also, western punctation is often used in modern Korean and expects to be treated
|
||||
* Also, western punctuation is often used in modern Korean and expects to be treated
|
||||
* similarly to the CJK opening and closing symbols.
|
||||
*
|
||||
* Hello(한글)→ ["Hello", "(한", "글)"]
|
||||
|
|
|
@ -10,6 +10,8 @@ import {
|
|||
type GlobalPoint,
|
||||
} from "@excalidraw/math";
|
||||
|
||||
import { elementCenterPoint } from "@excalidraw/common";
|
||||
|
||||
import type { Curve, LineSegment } from "@excalidraw/math";
|
||||
|
||||
import { getCornerRadius } from "./shapes";
|
||||
|
@ -68,10 +70,7 @@ export function deconstructRectanguloidElement(
|
|||
return [sides, []];
|
||||
}
|
||||
|
||||
const center = pointFrom<GlobalPoint>(
|
||||
element.x + element.width / 2,
|
||||
element.y + element.height / 2,
|
||||
);
|
||||
const center = elementCenterPoint(element);
|
||||
|
||||
const r = rectangle(
|
||||
pointFrom(element.x, element.y),
|
||||
|
@ -254,10 +253,7 @@ export function deconstructDiamondElement(
|
|||
return [[topRight, bottomRight, bottomLeft, topLeft], []];
|
||||
}
|
||||
|
||||
const center = pointFrom<GlobalPoint>(
|
||||
element.x + element.width / 2,
|
||||
element.y + element.height / 2,
|
||||
);
|
||||
const center = elementCenterPoint(element);
|
||||
|
||||
const [top, right, bottom, left]: GlobalPoint[] = [
|
||||
pointFrom(element.x + topX, element.y + topY),
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
@include outlineButtonIconStyles;
|
||||
|
||||
& > * {
|
||||
// dissalow pointer events on children, so we always have event.target on the button itself
|
||||
// disallow pointer events on children, so we always have event.target on the button itself
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ exports[`Test <App/> > should show error modal when using brave and measureText
|
|||
data-testid="brave-measure-text-error"
|
||||
>
|
||||
<p>
|
||||
Looks like you are using Brave browser with the
|
||||
Looks like you are using Brave browser with the
|
||||
<span
|
||||
style="font-weight: 600;"
|
||||
>
|
||||
|
@ -14,7 +14,7 @@ exports[`Test <App/> > should show error modal when using brave and measureText
|
|||
setting enabled.
|
||||
</p>
|
||||
<p>
|
||||
This could result in breaking the
|
||||
This could result in breaking the
|
||||
<span
|
||||
style="font-weight: 600;"
|
||||
>
|
||||
|
@ -23,22 +23,22 @@ exports[`Test <App/> > should show error modal when using brave and measureText
|
|||
in your drawings.
|
||||
</p>
|
||||
<p>
|
||||
We strongly recommend disabling this setting. You can follow
|
||||
We strongly recommend disabling this setting. You can follow
|
||||
<a
|
||||
href="http://docs.excalidraw.com/docs/@excalidraw/excalidraw/faq#turning-off-aggresive-block-fingerprinting-in-brave-browser"
|
||||
href="http://docs.excalidraw.com/docs/@excalidraw/excalidraw/faq#turning-off-aggressive-block-fingerprinting-in-brave-browser"
|
||||
>
|
||||
these steps
|
||||
</a>
|
||||
on how to do so.
|
||||
</p>
|
||||
<p>
|
||||
If disabling this setting doesn't fix the display of text elements, please open an
|
||||
If disabling this setting doesn't fix the display of text elements, please open an
|
||||
<a
|
||||
href="https://github.com/excalidraw/excalidraw/issues/new"
|
||||
>
|
||||
issue
|
||||
</a>
|
||||
on our GitHub, or write us on
|
||||
on our GitHub, or write us on
|
||||
<a
|
||||
href="https://discord.gg/UexuTaE"
|
||||
>
|
||||
|
|
|
@ -20,7 +20,7 @@ export const withInternalFallback = <P,>(
|
|||
// for rerenders
|
||||
const [, setCounter] = useAtom(renderAtom);
|
||||
// for initial & subsequent renders. Tracked as component state
|
||||
// due to excalidraw multi-instance scanerios.
|
||||
// due to excalidraw multi-instance scenarios.
|
||||
const metaRef = useRef({
|
||||
// flag set on initial render to tell the fallback component to skip the
|
||||
// render until mount counter are initialized. This is because the counter
|
||||
|
|
|
@ -21,7 +21,7 @@ export interface ExportedDataState {
|
|||
|
||||
/**
|
||||
* Map of legacy AppState keys, with values of:
|
||||
* [<legacy type>, <new AppState proeprty>]
|
||||
* [<legacy type>, <new AppState property>]
|
||||
*
|
||||
* This is a helper type used in downstream abstractions.
|
||||
* Don't consume on its own.
|
||||
|
|
|
@ -37,7 +37,7 @@ const deburredLetters = {
|
|||
'\xd9': 'U', '\xda': 'U', '\xdb': 'U', '\xdc': 'U',
|
||||
'\xf9': 'u', '\xfa': 'u', '\xfb': 'u', '\xfc': 'u',
|
||||
'\xdd': 'Y', '\xfd': 'y', '\xff': 'y',
|
||||
// normaly Ae/ae
|
||||
// normally Ae/ae
|
||||
'\xc6': 'E', '\xe6': 'e',
|
||||
// normally Th/th
|
||||
'\xde': 'T', '\xfe': 't',
|
||||
|
|
|
@ -82,9 +82,9 @@ const truncateText = (element: ExcalidrawTextElement, maxWidth: number) => {
|
|||
|
||||
if (metrics.width > maxWidth) {
|
||||
// we iterate from the right, removing characters one by one instead
|
||||
// of bulding the string up. This assumes that it's more likely
|
||||
// of building the string up. This assumes that it's more likely
|
||||
// your frame names will overflow by not that many characters
|
||||
// (if ever), so it sohuld be faster this way.
|
||||
// (if ever), so it should be faster this way.
|
||||
for (let i = text.length; i > 0; i--) {
|
||||
const newText = `${text.slice(0, i)}...`;
|
||||
if (ctx.measureText(newText).width <= maxWidth) {
|
||||
|
@ -376,7 +376,7 @@ export const exportToSvg = async (
|
|||
try {
|
||||
encodeSvgBase64Payload({
|
||||
metadataElement,
|
||||
// when embedding scene, we want to embed the origionally supplied
|
||||
// when embedding scene, we want to embed the originally supplied
|
||||
// elements which don't contain the temp frame labels.
|
||||
// But it also requires that the exportToSvg is being supplied with
|
||||
// only the elements that we're exporting, and no extra.
|
||||
|
|
|
@ -50,7 +50,7 @@ export type SVGRenderConfig = {
|
|||
embedsValidationStatus: EmbedsValidationStatus;
|
||||
/**
|
||||
* whether to attempt to reuse images as much as possible through symbols
|
||||
* (reduces SVG size, but may be incompoatible with some SVG renderers)
|
||||
* (reduces SVG size, but may be incompatible with some SVG renderers)
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
// @ts-nocheck
|
||||
|
||||
/**
|
||||
* Slitghly modified emscripten bindings of https://github.com/kekee000/fonteditor-core/blob/582bba757aa2915ec2240c61717ff12c50594675/woff2src/woff2.js
|
||||
*
|
||||
* Slightly modified emscripten bindings of https://github.com/kekee000/fonteditor-core/blob/582bba757aa2915ec2240c61717ff12c50594675/woff2src/woff2.js
|
||||
*
|
||||
* CHANGELOG:
|
||||
* - replaced existing exports with default esm export (`export default Module;`)
|
||||
* - replaced "instanceof ArrayBuffer" with "Object.prototype.toString.call(d) === "[object ArrayBuffer]", due to unreliability of different ArrayBuffer instances depending on the context (i.e. inside VM)
|
||||
|
|
|
@ -5,7 +5,7 @@ exports[`Test <App/> > should show error modal when using brave and measureText
|
|||
data-testid="brave-measure-text-error"
|
||||
>
|
||||
<p>
|
||||
Looks like you are using Brave browser with the
|
||||
Looks like you are using Brave browser with the
|
||||
<span
|
||||
style="font-weight: 600;"
|
||||
>
|
||||
|
@ -14,7 +14,7 @@ exports[`Test <App/> > should show error modal when using brave and measureText
|
|||
setting enabled.
|
||||
</p>
|
||||
<p>
|
||||
This could result in breaking the
|
||||
This could result in breaking the
|
||||
<span
|
||||
style="font-weight: 600;"
|
||||
>
|
||||
|
@ -23,22 +23,22 @@ exports[`Test <App/> > should show error modal when using brave and measureText
|
|||
in your drawings.
|
||||
</p>
|
||||
<p>
|
||||
We strongly recommend disabling this setting. You can follow
|
||||
We strongly recommend disabling this setting. You can follow
|
||||
<a
|
||||
href="http://docs.excalidraw.com/docs/@excalidraw/excalidraw/faq#turning-off-aggresive-block-fingerprinting-in-brave-browser"
|
||||
href="http://docs.excalidraw.com/docs/@excalidraw/excalidraw/faq#turning-off-aggressive-block-fingerprinting-in-brave-browser"
|
||||
>
|
||||
these steps
|
||||
</a>
|
||||
on how to do so.
|
||||
</p>
|
||||
<p>
|
||||
If disabling this setting doesn't fix the display of text elements, please open an
|
||||
If disabling this setting doesn't fix the display of text elements, please open an
|
||||
<a
|
||||
href="https://github.com/excalidraw/excalidraw/issues/new"
|
||||
>
|
||||
issue
|
||||
</a>
|
||||
on our GitHub, or write us on
|
||||
on our GitHub, or write us on
|
||||
<a
|
||||
href="https://discord.gg/UexuTaE"
|
||||
>
|
||||
|
|
|
@ -20,7 +20,7 @@ exports[`<Excalidraw/> > <MainMenu/> > should render main menu with host menu it
|
|||
</button>
|
||||
<a
|
||||
class="dropdown-menu-item dropdown-menu-item-base"
|
||||
href="blog.excalidaw.com"
|
||||
href="blog.excalidraw.com"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
|
|
|
@ -20,7 +20,7 @@ import {
|
|||
isTextElement,
|
||||
isFrameLikeElement,
|
||||
} from "@excalidraw/element/typeChecks";
|
||||
import { KEYS, arrayToMap } from "@excalidraw/common";
|
||||
import { KEYS, arrayToMap, elementCenterPoint } from "@excalidraw/common";
|
||||
|
||||
import type { GlobalPoint, LocalPoint, Radians } from "@excalidraw/math";
|
||||
|
||||
|
@ -151,7 +151,7 @@ export class Keyboard {
|
|||
const getElementPointForSelection = (
|
||||
element: ExcalidrawElement,
|
||||
): GlobalPoint => {
|
||||
const { x, y, width, height, angle } = element;
|
||||
const { x, y, width, angle } = element;
|
||||
const target = pointFrom<GlobalPoint>(
|
||||
x +
|
||||
(isLinearElement(element) || isFreeDrawElement(element) ? 0 : width / 2),
|
||||
|
@ -166,7 +166,7 @@ const getElementPointForSelection = (
|
|||
(bounds[1] + bounds[3]) / 2,
|
||||
);
|
||||
} else {
|
||||
center = pointFrom(x + width / 2, y + height / 2);
|
||||
center = elementCenterPoint(element);
|
||||
}
|
||||
|
||||
if (isTextElement(element)) {
|
||||
|
|
|
@ -245,7 +245,7 @@ export type ObservedElementsAppState = {
|
|||
editingGroupId: AppState["editingGroupId"];
|
||||
selectedElementIds: AppState["selectedElementIds"];
|
||||
selectedGroupIds: AppState["selectedGroupIds"];
|
||||
// Avoiding storing whole instance, as it could lead into state incosistencies, empty undos/redos and etc.
|
||||
// Avoiding storing whole instance, as it could lead into state inconsistencies, empty undos/redos and etc.
|
||||
editingLinearElementId: LinearElementEditor["elementId"] | null;
|
||||
// Right now it's coupled to `editingLinearElement`, ideally it should not be really needed as we already have selectedElementIds & editingLinearElementId
|
||||
selectedLinearElementId: LinearElementEditor["elementId"] | null;
|
||||
|
|
2
packages/excalidraw/vite-env.d.ts
vendored
2
packages/excalidraw/vite-env.d.ts
vendored
|
@ -21,7 +21,7 @@ interface ImportMetaEnv {
|
|||
|
||||
VITE_APP_FIREBASE_CONFIG: string;
|
||||
|
||||
// whether to disable live reload / HMR. Usuaully what you want to do when
|
||||
// whether to disable live reload / HMR. Usually what you want to do when
|
||||
// debugging Service Workers.
|
||||
VITE_APP_DEV_DISABLE_LIVE_RELOAD: string;
|
||||
// To enable bounding box for text containers
|
||||
|
|
|
@ -67,7 +67,7 @@ export const ellipseIncludesPoint = <Point extends GlobalPoint | LocalPoint>(
|
|||
* @param point The point to test
|
||||
* @param ellipse The ellipse to compare against
|
||||
* @param threshold The distance to consider a point close enough to be "on" the outline
|
||||
* @returns TRUE if the point is on the ellise outline
|
||||
* @returns TRUE if the point is on the ellipse outline
|
||||
*/
|
||||
export const ellipseTouchesPoint = <Point extends GlobalPoint | LocalPoint>(
|
||||
point: Point,
|
||||
|
@ -83,7 +83,7 @@ export const ellipseTouchesPoint = <Point extends GlobalPoint | LocalPoint>(
|
|||
*
|
||||
* @param p The point to consider
|
||||
* @param ellipse The ellipse to calculate the distance to
|
||||
* @returns The eucledian distance
|
||||
* @returns The euclidean distance
|
||||
*/
|
||||
export const ellipseDistanceFromPoint = <
|
||||
Point extends GlobalPoint | LocalPoint,
|
||||
|
@ -137,7 +137,7 @@ export const ellipseDistanceFromPoint = <
|
|||
};
|
||||
|
||||
/**
|
||||
* Calculate a maximum of two intercept points for a line going throug an
|
||||
* Calculate a maximum of two intercept points for a line going through an
|
||||
* ellipse.
|
||||
*/
|
||||
export function ellipseSegmentInterceptPoints<
|
||||
|
|
|
@ -47,7 +47,7 @@ export const rangesOverlap = (
|
|||
};
|
||||
|
||||
/**
|
||||
* Given two ranges,return ther intersection of the two ranges if any e.g. the
|
||||
* Given two ranges, return the intersection of the two ranges if any e.g. the
|
||||
* intersection of [1, 3] and [2, 4] is [2, 3].
|
||||
*
|
||||
* @param param0 The first range to compare
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type { GlobalPoint, LocalPoint, Vector } from "./types";
|
||||
|
||||
/**
|
||||
* Create a vector from the x and y coordiante elements.
|
||||
* Create a vector from the x and y coordinate elements.
|
||||
*
|
||||
* @param x The X aspect of the vector
|
||||
* @param y T Y aspect of the vector
|
||||
|
@ -20,7 +20,7 @@ export function vector(
|
|||
* Turn a point into a vector with the origin point.
|
||||
*
|
||||
* @param p The point to turn into a vector
|
||||
* @param origin The origin point in a given coordiante system
|
||||
* @param origin The origin point in a given coordinate system
|
||||
* @returns The created vector from the point and the origin
|
||||
*/
|
||||
export function vectorFromPoint<Point extends GlobalPoint | LocalPoint>(
|
||||
|
@ -36,7 +36,7 @@ export function vectorFromPoint<Point extends GlobalPoint | LocalPoint>(
|
|||
*
|
||||
* @param a One of the vectors to use for the directed area calculation
|
||||
* @param b The other vector to use for the directed area calculation
|
||||
* @returns The directed area value for the two vectos
|
||||
* @returns The directed area value for the two vectors
|
||||
*/
|
||||
export function vectorCross(a: Vector, b: Vector): number {
|
||||
return a[0] * b[1] - b[0] * a[1];
|
||||
|
@ -108,7 +108,7 @@ export function vectorScale(v: Vector, scalar: number): Vector {
|
|||
}
|
||||
|
||||
/**
|
||||
* Calculates the sqare magnitude of a vector. Use this if you compare
|
||||
* Calculates the square magnitude of a vector. Use this if you compare
|
||||
* magnitudes as it saves you an SQRT.
|
||||
*
|
||||
* @param v The vector to measure
|
||||
|
@ -129,7 +129,7 @@ export function vectorMagnitude(v: Vector) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Normalize the vector (i.e. make the vector magnitue equal 1).
|
||||
* Normalize the vector (i.e. make the vector magnitude equal 1).
|
||||
*
|
||||
* @param v The vector to normalize
|
||||
* @returns The new normalized vector
|
||||
|
|
|
@ -71,7 +71,7 @@ const createESMRawBuild = async () => {
|
|||
...chunksConfig,
|
||||
});
|
||||
|
||||
// production minified buld without sourcemaps
|
||||
// production minified build without sourcemaps
|
||||
await buildProd({
|
||||
...getConfig("dist/prod"),
|
||||
...chunksConfig,
|
||||
|
|
Loading…
Add table
Reference in a new issue