feat: better default radius sizes for rectangles (#5553)
Co-authored-by: Ryan <diweihao@bytedance.com> Co-authored-by: dwelle <luzar.david@gmail.com>
This commit is contained in:
parent
65d84a5d5a
commit
5854ac3eed
@ -153,11 +153,7 @@ const flipElement = (
|
|||||||
|
|
||||||
let initialPointsCoords;
|
let initialPointsCoords;
|
||||||
if (isLinearElement(element)) {
|
if (isLinearElement(element)) {
|
||||||
initialPointsCoords = getElementPointsCoords(
|
initialPointsCoords = getElementPointsCoords(element, element.points);
|
||||||
element,
|
|
||||||
element.points,
|
|
||||||
element.strokeSharpness,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
const initialElementAbsoluteCoords = getElementAbsoluteCoords(element);
|
const initialElementAbsoluteCoords = getElementAbsoluteCoords(element);
|
||||||
|
|
||||||
@ -215,11 +211,7 @@ const flipElement = (
|
|||||||
// Adjusting origin because when a beizer curve path exceeds min/max points it offsets the origin.
|
// Adjusting origin because when a beizer curve path exceeds min/max points it offsets the origin.
|
||||||
// There's still room for improvement since when the line roughness is > 1
|
// There's still room for improvement since when the line roughness is > 1
|
||||||
// we still have a small offset of the origin when fliipping the element.
|
// we still have a small offset of the origin when fliipping the element.
|
||||||
const finalPointsCoords = getElementPointsCoords(
|
const finalPointsCoords = getElementPointsCoords(element, element.points);
|
||||||
element,
|
|
||||||
element.points,
|
|
||||||
element.strokeSharpness,
|
|
||||||
);
|
|
||||||
|
|
||||||
const topLeftCoordsDiff = initialPointsCoords[0] - finalPointsCoords[0];
|
const topLeftCoordsDiff = initialPointsCoords[0] - finalPointsCoords[0];
|
||||||
const topRightCoordDiff = initialPointsCoords[2] - finalPointsCoords[2];
|
const topRightCoordDiff = initialPointsCoords[2] - finalPointsCoords[2];
|
||||||
|
@ -42,6 +42,7 @@ import {
|
|||||||
DEFAULT_FONT_FAMILY,
|
DEFAULT_FONT_FAMILY,
|
||||||
DEFAULT_FONT_SIZE,
|
DEFAULT_FONT_SIZE,
|
||||||
FONT_FAMILY,
|
FONT_FAMILY,
|
||||||
|
ROUNDNESS,
|
||||||
VERTICAL_ALIGN,
|
VERTICAL_ALIGN,
|
||||||
} from "../constants";
|
} from "../constants";
|
||||||
import {
|
import {
|
||||||
@ -57,7 +58,7 @@ import {
|
|||||||
import {
|
import {
|
||||||
isBoundToContainer,
|
isBoundToContainer,
|
||||||
isLinearElement,
|
isLinearElement,
|
||||||
isLinearElementType,
|
isUsingAdaptiveRadius,
|
||||||
} from "../element/typeChecks";
|
} from "../element/typeChecks";
|
||||||
import {
|
import {
|
||||||
Arrowhead,
|
Arrowhead,
|
||||||
@ -72,7 +73,7 @@ import { getLanguage, t } from "../i18n";
|
|||||||
import { KEYS } from "../keys";
|
import { KEYS } from "../keys";
|
||||||
import { randomInteger } from "../random";
|
import { randomInteger } from "../random";
|
||||||
import {
|
import {
|
||||||
canChangeSharpness,
|
canChangeRoundness,
|
||||||
canHaveArrowheads,
|
canHaveArrowheads,
|
||||||
getCommonAttributeOfSelectedElements,
|
getCommonAttributeOfSelectedElements,
|
||||||
getSelectedElements,
|
getSelectedElements,
|
||||||
@ -848,69 +849,71 @@ export const actionChangeVerticalAlign = register({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const actionChangeSharpness = register({
|
export const actionChangeRoundness = register({
|
||||||
name: "changeSharpness",
|
name: "changeRoundness",
|
||||||
trackEvent: false,
|
trackEvent: false,
|
||||||
perform: (elements, appState, value) => {
|
perform: (elements, appState, value) => {
|
||||||
const targetElements = getTargetElements(
|
|
||||||
getNonDeletedElements(elements),
|
|
||||||
appState,
|
|
||||||
);
|
|
||||||
const shouldUpdateForNonLinearElements = targetElements.length
|
|
||||||
? targetElements.every((el) => !isLinearElement(el))
|
|
||||||
: !isLinearElementType(appState.activeTool.type);
|
|
||||||
const shouldUpdateForLinearElements = targetElements.length
|
|
||||||
? targetElements.every(isLinearElement)
|
|
||||||
: isLinearElementType(appState.activeTool.type);
|
|
||||||
return {
|
return {
|
||||||
elements: changeProperty(elements, appState, (el) =>
|
elements: changeProperty(elements, appState, (el) =>
|
||||||
newElementWith(el, {
|
newElementWith(el, {
|
||||||
strokeSharpness: value,
|
roundness:
|
||||||
|
value === "round"
|
||||||
|
? {
|
||||||
|
type: isUsingAdaptiveRadius(el.type)
|
||||||
|
? ROUNDNESS.ADAPTIVE_RADIUS
|
||||||
|
: ROUNDNESS.PROPORTIONAL_RADIUS,
|
||||||
|
}
|
||||||
|
: null,
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
appState: {
|
appState: {
|
||||||
...appState,
|
...appState,
|
||||||
currentItemStrokeSharpness: shouldUpdateForNonLinearElements
|
currentItemRoundness: value,
|
||||||
? value
|
|
||||||
: appState.currentItemStrokeSharpness,
|
|
||||||
currentItemLinearStrokeSharpness: shouldUpdateForLinearElements
|
|
||||||
? value
|
|
||||||
: appState.currentItemLinearStrokeSharpness,
|
|
||||||
},
|
},
|
||||||
commitToHistory: true,
|
commitToHistory: true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
PanelComponent: ({ elements, appState, updateData }) => (
|
PanelComponent: ({ elements, appState, updateData }) => {
|
||||||
<fieldset>
|
const targetElements = getTargetElements(
|
||||||
<legend>{t("labels.edges")}</legend>
|
getNonDeletedElements(elements),
|
||||||
<ButtonIconSelect
|
appState,
|
||||||
group="edges"
|
);
|
||||||
options={[
|
|
||||||
{
|
const hasLegacyRoundness = targetElements.some(
|
||||||
value: "sharp",
|
(el) => el.roundness?.type === ROUNDNESS.LEGACY,
|
||||||
text: t("labels.sharp"),
|
);
|
||||||
icon: EdgeSharpIcon,
|
|
||||||
},
|
return (
|
||||||
{
|
<fieldset>
|
||||||
value: "round",
|
<legend>{t("labels.edges")}</legend>
|
||||||
text: t("labels.round"),
|
<ButtonIconSelect
|
||||||
icon: EdgeRoundIcon,
|
group="edges"
|
||||||
},
|
options={[
|
||||||
]}
|
{
|
||||||
value={getFormValue(
|
value: "sharp",
|
||||||
elements,
|
text: t("labels.sharp"),
|
||||||
appState,
|
icon: EdgeSharpIcon,
|
||||||
(element) => element.strokeSharpness,
|
},
|
||||||
(canChangeSharpness(appState.activeTool.type) &&
|
{
|
||||||
(isLinearElementType(appState.activeTool.type)
|
value: "round",
|
||||||
? appState.currentItemLinearStrokeSharpness
|
text: t("labels.round"),
|
||||||
: appState.currentItemStrokeSharpness)) ||
|
icon: EdgeRoundIcon,
|
||||||
null,
|
},
|
||||||
)}
|
]}
|
||||||
onChange={(value) => updateData(value)}
|
value={getFormValue(
|
||||||
/>
|
elements,
|
||||||
</fieldset>
|
appState,
|
||||||
),
|
(element) =>
|
||||||
|
hasLegacyRoundness ? null : element.roundness ? "round" : "sharp",
|
||||||
|
(canChangeRoundness(appState.activeTool.type) &&
|
||||||
|
appState.currentItemRoundness) ||
|
||||||
|
null,
|
||||||
|
)}
|
||||||
|
onChange={(value) => updateData(value)}
|
||||||
|
/>
|
||||||
|
</fieldset>
|
||||||
|
);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const actionChangeArrowhead = register({
|
export const actionChangeArrowhead = register({
|
||||||
|
@ -77,6 +77,7 @@ export const actionPasteStyles = register({
|
|||||||
fillStyle: elementStylesToCopyFrom?.fillStyle,
|
fillStyle: elementStylesToCopyFrom?.fillStyle,
|
||||||
opacity: elementStylesToCopyFrom?.opacity,
|
opacity: elementStylesToCopyFrom?.opacity,
|
||||||
roughness: elementStylesToCopyFrom?.roughness,
|
roughness: elementStylesToCopyFrom?.roughness,
|
||||||
|
roundness: elementStylesToCopyFrom?.roundness,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isTextElement(newElement)) {
|
if (isTextElement(newElement)) {
|
||||||
|
@ -91,7 +91,7 @@ export type ActionName =
|
|||||||
| "ungroup"
|
| "ungroup"
|
||||||
| "goToCollaborator"
|
| "goToCollaborator"
|
||||||
| "addToLibrary"
|
| "addToLibrary"
|
||||||
| "changeSharpness"
|
| "changeRoundness"
|
||||||
| "alignTop"
|
| "alignTop"
|
||||||
| "alignBottom"
|
| "alignBottom"
|
||||||
| "alignLeft"
|
| "alignLeft"
|
||||||
|
@ -28,12 +28,11 @@ export const getDefaultAppState = (): Omit<
|
|||||||
currentItemFillStyle: "hachure",
|
currentItemFillStyle: "hachure",
|
||||||
currentItemFontFamily: DEFAULT_FONT_FAMILY,
|
currentItemFontFamily: DEFAULT_FONT_FAMILY,
|
||||||
currentItemFontSize: DEFAULT_FONT_SIZE,
|
currentItemFontSize: DEFAULT_FONT_SIZE,
|
||||||
currentItemLinearStrokeSharpness: "round",
|
|
||||||
currentItemOpacity: 100,
|
currentItemOpacity: 100,
|
||||||
currentItemRoughness: 1,
|
currentItemRoughness: 1,
|
||||||
currentItemStartArrowhead: null,
|
currentItemStartArrowhead: null,
|
||||||
currentItemStrokeColor: oc.black,
|
currentItemStrokeColor: oc.black,
|
||||||
currentItemStrokeSharpness: "sharp",
|
currentItemRoundness: "round",
|
||||||
currentItemStrokeStyle: "solid",
|
currentItemStrokeStyle: "solid",
|
||||||
currentItemStrokeWidth: 1,
|
currentItemStrokeWidth: 1,
|
||||||
currentItemTextAlign: DEFAULT_TEXT_ALIGN,
|
currentItemTextAlign: DEFAULT_TEXT_ALIGN,
|
||||||
@ -120,7 +119,7 @@ const APP_STATE_STORAGE_CONF = (<
|
|||||||
currentItemFillStyle: { browser: true, export: false, server: false },
|
currentItemFillStyle: { browser: true, export: false, server: false },
|
||||||
currentItemFontFamily: { browser: true, export: false, server: false },
|
currentItemFontFamily: { browser: true, export: false, server: false },
|
||||||
currentItemFontSize: { browser: true, export: false, server: false },
|
currentItemFontSize: { browser: true, export: false, server: false },
|
||||||
currentItemLinearStrokeSharpness: {
|
currentItemRoundness: {
|
||||||
browser: true,
|
browser: true,
|
||||||
export: false,
|
export: false,
|
||||||
server: false,
|
server: false,
|
||||||
@ -129,7 +128,6 @@ const APP_STATE_STORAGE_CONF = (<
|
|||||||
currentItemRoughness: { browser: true, export: false, server: false },
|
currentItemRoughness: { browser: true, export: false, server: false },
|
||||||
currentItemStartArrowhead: { browser: true, export: false, server: false },
|
currentItemStartArrowhead: { browser: true, export: false, server: false },
|
||||||
currentItemStrokeColor: { browser: true, export: false, server: false },
|
currentItemStrokeColor: { browser: true, export: false, server: false },
|
||||||
currentItemStrokeSharpness: { browser: true, export: false, server: false },
|
|
||||||
currentItemStrokeStyle: { browser: true, export: false, server: false },
|
currentItemStrokeStyle: { browser: true, export: false, server: false },
|
||||||
currentItemStrokeWidth: { browser: true, export: false, server: false },
|
currentItemStrokeWidth: { browser: true, export: false, server: false },
|
||||||
currentItemTextAlign: { browser: true, export: false, server: false },
|
currentItemTextAlign: { browser: true, export: false, server: false },
|
||||||
|
@ -172,7 +172,7 @@ const commonProps = {
|
|||||||
opacity: 100,
|
opacity: 100,
|
||||||
roughness: 1,
|
roughness: 1,
|
||||||
strokeColor: colors.elementStroke[0],
|
strokeColor: colors.elementStroke[0],
|
||||||
strokeSharpness: "sharp",
|
roundness: null,
|
||||||
strokeStyle: "solid",
|
strokeStyle: "solid",
|
||||||
strokeWidth: 1,
|
strokeWidth: 1,
|
||||||
verticalAlign: VERTICAL_ALIGN.MIDDLE,
|
verticalAlign: VERTICAL_ALIGN.MIDDLE,
|
||||||
@ -322,7 +322,7 @@ const chartBaseElements = (
|
|||||||
text: spreadsheet.title,
|
text: spreadsheet.title,
|
||||||
x: x + chartWidth / 2,
|
x: x + chartWidth / 2,
|
||||||
y: y - BAR_HEIGHT - BAR_GAP * 2 - DEFAULT_FONT_SIZE,
|
y: y - BAR_HEIGHT - BAR_GAP * 2 - DEFAULT_FONT_SIZE,
|
||||||
strokeSharpness: "sharp",
|
roundness: null,
|
||||||
strokeStyle: "solid",
|
strokeStyle: "solid",
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
})
|
})
|
||||||
|
@ -5,7 +5,7 @@ import { ExcalidrawElement, PointerType } from "../element/types";
|
|||||||
import { t } from "../i18n";
|
import { t } from "../i18n";
|
||||||
import { useDevice } from "../components/App";
|
import { useDevice } from "../components/App";
|
||||||
import {
|
import {
|
||||||
canChangeSharpness,
|
canChangeRoundness,
|
||||||
canHaveArrowheads,
|
canHaveArrowheads,
|
||||||
getTargetElements,
|
getTargetElements,
|
||||||
hasBackground,
|
hasBackground,
|
||||||
@ -110,9 +110,9 @@ export const SelectedShapeActions = ({
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{(canChangeSharpness(appState.activeTool.type) ||
|
{(canChangeRoundness(appState.activeTool.type) ||
|
||||||
targetElements.some((element) => canChangeSharpness(element.type))) && (
|
targetElements.some((element) => canChangeRoundness(element.type))) && (
|
||||||
<>{renderAction("changeSharpness")}</>
|
<>{renderAction("changeRoundness")}</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{(hasText(appState.activeTool.type) ||
|
{(hasText(appState.activeTool.type) ||
|
||||||
|
@ -70,6 +70,7 @@ import {
|
|||||||
MQ_RIGHT_SIDEBAR_MIN_WIDTH,
|
MQ_RIGHT_SIDEBAR_MIN_WIDTH,
|
||||||
MQ_SM_MAX_WIDTH,
|
MQ_SM_MAX_WIDTH,
|
||||||
POINTER_BUTTON,
|
POINTER_BUTTON,
|
||||||
|
ROUNDNESS,
|
||||||
SCROLL_TIMEOUT,
|
SCROLL_TIMEOUT,
|
||||||
TAP_TWICE_TIMEOUT,
|
TAP_TWICE_TIMEOUT,
|
||||||
TEXT_TO_CENTER_SNAP_THRESHOLD,
|
TEXT_TO_CENTER_SNAP_THRESHOLD,
|
||||||
@ -134,6 +135,7 @@ import {
|
|||||||
isInitializedImageElement,
|
isInitializedImageElement,
|
||||||
isLinearElement,
|
isLinearElement,
|
||||||
isLinearElementType,
|
isLinearElementType,
|
||||||
|
isUsingAdaptiveRadius,
|
||||||
} from "../element/typeChecks";
|
} from "../element/typeChecks";
|
||||||
import {
|
import {
|
||||||
ExcalidrawBindableElement,
|
ExcalidrawBindableElement,
|
||||||
@ -1658,9 +1660,9 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
fillStyle: this.state.currentItemFillStyle,
|
fillStyle: this.state.currentItemFillStyle,
|
||||||
strokeWidth: this.state.currentItemStrokeWidth,
|
strokeWidth: this.state.currentItemStrokeWidth,
|
||||||
strokeStyle: this.state.currentItemStrokeStyle,
|
strokeStyle: this.state.currentItemStrokeStyle,
|
||||||
|
roundness: null,
|
||||||
roughness: this.state.currentItemRoughness,
|
roughness: this.state.currentItemRoughness,
|
||||||
opacity: this.state.currentItemOpacity,
|
opacity: this.state.currentItemOpacity,
|
||||||
strokeSharpness: this.state.currentItemStrokeSharpness,
|
|
||||||
text,
|
text,
|
||||||
fontSize: this.state.currentItemFontSize,
|
fontSize: this.state.currentItemFontSize,
|
||||||
fontFamily: this.state.currentItemFontFamily,
|
fontFamily: this.state.currentItemFontFamily,
|
||||||
@ -2569,7 +2571,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
strokeStyle: this.state.currentItemStrokeStyle,
|
strokeStyle: this.state.currentItemStrokeStyle,
|
||||||
roughness: this.state.currentItemRoughness,
|
roughness: this.state.currentItemRoughness,
|
||||||
opacity: this.state.currentItemOpacity,
|
opacity: this.state.currentItemOpacity,
|
||||||
strokeSharpness: this.state.currentItemStrokeSharpness,
|
roundness: null,
|
||||||
text: "",
|
text: "",
|
||||||
fontSize: this.state.currentItemFontSize,
|
fontSize: this.state.currentItemFontSize,
|
||||||
fontFamily: this.state.currentItemFontFamily,
|
fontFamily: this.state.currentItemFontFamily,
|
||||||
@ -4072,7 +4074,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
strokeStyle: this.state.currentItemStrokeStyle,
|
strokeStyle: this.state.currentItemStrokeStyle,
|
||||||
roughness: this.state.currentItemRoughness,
|
roughness: this.state.currentItemRoughness,
|
||||||
opacity: this.state.currentItemOpacity,
|
opacity: this.state.currentItemOpacity,
|
||||||
strokeSharpness: this.state.currentItemLinearStrokeSharpness,
|
roundness: null,
|
||||||
simulatePressure: event.pressure === 0.5,
|
simulatePressure: event.pressure === 0.5,
|
||||||
locked: false,
|
locked: false,
|
||||||
});
|
});
|
||||||
@ -4128,8 +4130,8 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
strokeWidth: this.state.currentItemStrokeWidth,
|
strokeWidth: this.state.currentItemStrokeWidth,
|
||||||
strokeStyle: this.state.currentItemStrokeStyle,
|
strokeStyle: this.state.currentItemStrokeStyle,
|
||||||
roughness: this.state.currentItemRoughness,
|
roughness: this.state.currentItemRoughness,
|
||||||
|
roundness: null,
|
||||||
opacity: this.state.currentItemOpacity,
|
opacity: this.state.currentItemOpacity,
|
||||||
strokeSharpness: this.state.currentItemLinearStrokeSharpness,
|
|
||||||
locked: false,
|
locked: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -4215,7 +4217,10 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
strokeStyle: this.state.currentItemStrokeStyle,
|
strokeStyle: this.state.currentItemStrokeStyle,
|
||||||
roughness: this.state.currentItemRoughness,
|
roughness: this.state.currentItemRoughness,
|
||||||
opacity: this.state.currentItemOpacity,
|
opacity: this.state.currentItemOpacity,
|
||||||
strokeSharpness: this.state.currentItemLinearStrokeSharpness,
|
roundness:
|
||||||
|
this.state.currentItemRoundness === "round"
|
||||||
|
? { type: ROUNDNESS.PROPORTIONAL_RADIUS }
|
||||||
|
: null,
|
||||||
startArrowhead,
|
startArrowhead,
|
||||||
endArrowhead,
|
endArrowhead,
|
||||||
locked: false,
|
locked: false,
|
||||||
@ -4266,7 +4271,14 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
strokeStyle: this.state.currentItemStrokeStyle,
|
strokeStyle: this.state.currentItemStrokeStyle,
|
||||||
roughness: this.state.currentItemRoughness,
|
roughness: this.state.currentItemRoughness,
|
||||||
opacity: this.state.currentItemOpacity,
|
opacity: this.state.currentItemOpacity,
|
||||||
strokeSharpness: this.state.currentItemStrokeSharpness,
|
roundness:
|
||||||
|
this.state.currentItemRoundness === "round"
|
||||||
|
? {
|
||||||
|
type: isUsingAdaptiveRadius(elementType)
|
||||||
|
? ROUNDNESS.ADAPTIVE_RADIUS
|
||||||
|
: ROUNDNESS.PROPORTIONAL_RADIUS,
|
||||||
|
}
|
||||||
|
: null,
|
||||||
locked: false,
|
locked: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -216,6 +216,32 @@ export const TEXT_ALIGN = {
|
|||||||
|
|
||||||
export const ELEMENT_READY_TO_ERASE_OPACITY = 20;
|
export const ELEMENT_READY_TO_ERASE_OPACITY = 20;
|
||||||
|
|
||||||
|
// Radius represented as 25% of element's largest side (width/height).
|
||||||
|
// Used for LEGACY and PROPORTIONAL_RADIUS algorithms, or when the element is
|
||||||
|
// below the cutoff size.
|
||||||
|
export const DEFAULT_PROPORTIONAL_RADIUS = 0.25;
|
||||||
|
// Fixed radius for the ADAPTIVE_RADIUS algorithm. In pixels.
|
||||||
|
export const DEFAULT_ADAPTIVE_RADIUS = 32;
|
||||||
|
// roundness type (algorithm)
|
||||||
|
export const ROUNDNESS = {
|
||||||
|
// Used for legacy rounding (rectangles), which currently works the same
|
||||||
|
// as PROPORTIONAL_RADIUS, but we need to differentiate for UI purposes and
|
||||||
|
// forwards-compat.
|
||||||
|
LEGACY: 1,
|
||||||
|
|
||||||
|
// Used for linear elements & diamonds
|
||||||
|
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
|
||||||
|
// very large and very small elements.
|
||||||
|
//
|
||||||
|
// NOTE right now we don't allow configuration and use a constant radius
|
||||||
|
// (see DEFAULT_ADAPTIVE_RADIUS constant)
|
||||||
|
ADAPTIVE_RADIUS: 3,
|
||||||
|
} as const;
|
||||||
|
|
||||||
export const COOKIES = {
|
export const COOKIES = {
|
||||||
AUTH_STATE_COOKIE: "excplus-auth",
|
AUTH_STATE_COOKIE: "excplus-auth",
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -3,6 +3,7 @@ import {
|
|||||||
ExcalidrawSelectionElement,
|
ExcalidrawSelectionElement,
|
||||||
ExcalidrawTextElement,
|
ExcalidrawTextElement,
|
||||||
FontFamilyValues,
|
FontFamilyValues,
|
||||||
|
StrokeRoundness,
|
||||||
} from "../element/types";
|
} from "../element/types";
|
||||||
import {
|
import {
|
||||||
AppState,
|
AppState,
|
||||||
@ -17,7 +18,7 @@ import {
|
|||||||
isInvisiblySmallElement,
|
isInvisiblySmallElement,
|
||||||
refreshTextDimensions,
|
refreshTextDimensions,
|
||||||
} from "../element";
|
} from "../element";
|
||||||
import { isLinearElementType, isTextElement } from "../element/typeChecks";
|
import { isTextElement, isUsingAdaptiveRadius } from "../element/typeChecks";
|
||||||
import { randomId } from "../random";
|
import { randomId } from "../random";
|
||||||
import {
|
import {
|
||||||
DEFAULT_FONT_FAMILY,
|
DEFAULT_FONT_FAMILY,
|
||||||
@ -25,6 +26,7 @@ import {
|
|||||||
DEFAULT_VERTICAL_ALIGN,
|
DEFAULT_VERTICAL_ALIGN,
|
||||||
PRECEDING_ELEMENT_KEY,
|
PRECEDING_ELEMENT_KEY,
|
||||||
FONT_FAMILY,
|
FONT_FAMILY,
|
||||||
|
ROUNDNESS,
|
||||||
} from "../constants";
|
} from "../constants";
|
||||||
import { getDefaultAppState } from "../appState";
|
import { getDefaultAppState } from "../appState";
|
||||||
import { LinearElementEditor } from "../element/linearElementEditor";
|
import { LinearElementEditor } from "../element/linearElementEditor";
|
||||||
@ -74,6 +76,8 @@ const restoreElementWithProperties = <
|
|||||||
customData?: ExcalidrawElement["customData"];
|
customData?: ExcalidrawElement["customData"];
|
||||||
/** @deprecated */
|
/** @deprecated */
|
||||||
boundElementIds?: readonly ExcalidrawElement["id"][];
|
boundElementIds?: readonly ExcalidrawElement["id"][];
|
||||||
|
/** @deprecated */
|
||||||
|
strokeSharpness?: StrokeRoundness;
|
||||||
/** metadata that may be present in elements during collaboration */
|
/** metadata that may be present in elements during collaboration */
|
||||||
[PRECEDING_ELEMENT_KEY]?: string;
|
[PRECEDING_ELEMENT_KEY]?: string;
|
||||||
},
|
},
|
||||||
@ -112,9 +116,17 @@ const restoreElementWithProperties = <
|
|||||||
height: element.height || 0,
|
height: element.height || 0,
|
||||||
seed: element.seed ?? 1,
|
seed: element.seed ?? 1,
|
||||||
groupIds: element.groupIds ?? [],
|
groupIds: element.groupIds ?? [],
|
||||||
strokeSharpness:
|
roundness: element.roundness
|
||||||
element.strokeSharpness ??
|
? element.roundness
|
||||||
(isLinearElementType(element.type) ? "round" : "sharp"),
|
: element.strokeSharpness === "round"
|
||||||
|
? {
|
||||||
|
// for old elements that would now use adaptive radius algo,
|
||||||
|
// use legacy algo instead
|
||||||
|
type: isUsingAdaptiveRadius(element.type)
|
||||||
|
? ROUNDNESS.LEGACY
|
||||||
|
: ROUNDNESS.PROPORTIONAL_RADIUS,
|
||||||
|
}
|
||||||
|
: null,
|
||||||
boundElements: element.boundElementIds
|
boundElements: element.boundElementIds
|
||||||
? element.boundElementIds.map((id) => ({ type: "arrow", id }))
|
? element.boundElementIds.map((id) => ({ type: "arrow", id }))
|
||||||
: element.boundElements ?? [],
|
: element.boundElements ?? [],
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { ROUNDNESS } from "../constants";
|
||||||
import { getElementAbsoluteCoords, getElementBounds } from "./bounds";
|
import { getElementAbsoluteCoords, getElementBounds } from "./bounds";
|
||||||
import { ExcalidrawElement, ExcalidrawLinearElement } from "./types";
|
import { ExcalidrawElement, ExcalidrawLinearElement } from "./types";
|
||||||
|
|
||||||
@ -22,6 +23,7 @@ const _ce = ({
|
|||||||
backgroundColor: "#000",
|
backgroundColor: "#000",
|
||||||
fillStyle: "solid",
|
fillStyle: "solid",
|
||||||
strokeWidth: 1,
|
strokeWidth: 1,
|
||||||
|
roundness: { type: ROUNDNESS.PROPORTIONAL_RADIUS },
|
||||||
roughness: 0,
|
roughness: 0,
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
x,
|
x,
|
||||||
|
@ -378,7 +378,7 @@ const generateLinearElementShape = (
|
|||||||
const options = generateRoughOptions(element);
|
const options = generateRoughOptions(element);
|
||||||
|
|
||||||
const method = (() => {
|
const method = (() => {
|
||||||
if (element.strokeSharpness !== "sharp") {
|
if (element.roundness) {
|
||||||
return "curve";
|
return "curve";
|
||||||
}
|
}
|
||||||
if (options.fill) {
|
if (options.fill) {
|
||||||
@ -561,16 +561,12 @@ export const getResizedElementAbsoluteCoords = (
|
|||||||
} else {
|
} else {
|
||||||
// Line
|
// Line
|
||||||
const gen = rough.generator();
|
const gen = rough.generator();
|
||||||
const curve =
|
const curve = !element.roundness
|
||||||
element.strokeSharpness === "sharp"
|
? gen.linearPath(
|
||||||
? gen.linearPath(
|
points as [number, number][],
|
||||||
points as [number, number][],
|
generateRoughOptions(element),
|
||||||
generateRoughOptions(element),
|
)
|
||||||
)
|
: gen.curve(points as [number, number][], generateRoughOptions(element));
|
||||||
: gen.curve(
|
|
||||||
points as [number, number][],
|
|
||||||
generateRoughOptions(element),
|
|
||||||
);
|
|
||||||
|
|
||||||
const ops = getCurvePathOps(curve);
|
const ops = getCurvePathOps(curve);
|
||||||
bounds = getMinMaxXYFromCurvePathOps(ops);
|
bounds = getMinMaxXYFromCurvePathOps(ops);
|
||||||
@ -588,12 +584,11 @@ export const getResizedElementAbsoluteCoords = (
|
|||||||
export const getElementPointsCoords = (
|
export const getElementPointsCoords = (
|
||||||
element: ExcalidrawLinearElement,
|
element: ExcalidrawLinearElement,
|
||||||
points: readonly (readonly [number, number])[],
|
points: readonly (readonly [number, number])[],
|
||||||
sharpness: ExcalidrawElement["strokeSharpness"],
|
|
||||||
): [number, number, number, number] => {
|
): [number, number, number, number] => {
|
||||||
// This might be computationally heavey
|
// This might be computationally heavey
|
||||||
const gen = rough.generator();
|
const gen = rough.generator();
|
||||||
const curve =
|
const curve =
|
||||||
sharpness === "sharp"
|
element.roundness == null
|
||||||
? gen.linearPath(
|
? gen.linearPath(
|
||||||
points as [number, number][],
|
points as [number, number][],
|
||||||
generateRoughOptions(element),
|
generateRoughOptions(element),
|
||||||
|
@ -25,6 +25,7 @@ import {
|
|||||||
ExcalidrawFreeDrawElement,
|
ExcalidrawFreeDrawElement,
|
||||||
ExcalidrawImageElement,
|
ExcalidrawImageElement,
|
||||||
ExcalidrawLinearElement,
|
ExcalidrawLinearElement,
|
||||||
|
StrokeRoundness,
|
||||||
} from "./types";
|
} from "./types";
|
||||||
|
|
||||||
import { getElementAbsoluteCoords, getCurvePathOps, Bounds } from "./bounds";
|
import { getElementAbsoluteCoords, getCurvePathOps, Bounds } from "./bounds";
|
||||||
@ -419,7 +420,12 @@ const hitTestLinear = (args: HitTestArgs): boolean => {
|
|||||||
|
|
||||||
if (args.check === isInsideCheck) {
|
if (args.check === isInsideCheck) {
|
||||||
const hit = shape.some((subshape) =>
|
const hit = shape.some((subshape) =>
|
||||||
hitTestCurveInside(subshape, relX, relY, element.strokeSharpness),
|
hitTestCurveInside(
|
||||||
|
subshape,
|
||||||
|
relX,
|
||||||
|
relY,
|
||||||
|
element.roundness ? "round" : "sharp",
|
||||||
|
),
|
||||||
);
|
);
|
||||||
if (hit) {
|
if (hit) {
|
||||||
return true;
|
return true;
|
||||||
@ -851,7 +857,7 @@ const hitTestCurveInside = (
|
|||||||
drawable: Drawable,
|
drawable: Drawable,
|
||||||
x: number,
|
x: number,
|
||||||
y: number,
|
y: number,
|
||||||
sharpness: ExcalidrawElement["strokeSharpness"],
|
roundness: StrokeRoundness,
|
||||||
) => {
|
) => {
|
||||||
const ops = getCurvePathOps(drawable);
|
const ops = getCurvePathOps(drawable);
|
||||||
const points: Mutable<Point>[] = [];
|
const points: Mutable<Point>[] = [];
|
||||||
@ -875,7 +881,7 @@ const hitTestCurveInside = (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (points.length >= 4) {
|
if (points.length >= 4) {
|
||||||
if (sharpness === "sharp") {
|
if (roundness === "sharp") {
|
||||||
return isPointInPolygon(points, x, y);
|
return isPointInPolygon(points, x, y);
|
||||||
}
|
}
|
||||||
const polygonPoints = pointsOnBezierCurves(points, 10, 5);
|
const polygonPoints = pointsOnBezierCurves(points, 10, 5);
|
||||||
|
@ -527,7 +527,7 @@ export class LinearElementEditor {
|
|||||||
endPoint[0],
|
endPoint[0],
|
||||||
endPoint[1],
|
endPoint[1],
|
||||||
);
|
);
|
||||||
if (element.points.length > 2 && element.strokeSharpness === "round") {
|
if (element.points.length > 2 && element.roundness) {
|
||||||
distance = getBezierCurveLength(element, endPoint);
|
distance = getBezierCurveLength(element, endPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -541,7 +541,7 @@ export class LinearElementEditor {
|
|||||||
endPointIndex: number,
|
endPointIndex: number,
|
||||||
) {
|
) {
|
||||||
let segmentMidPoint = centerPoint(startPoint, endPoint);
|
let segmentMidPoint = centerPoint(startPoint, endPoint);
|
||||||
if (element.points.length > 2 && element.strokeSharpness === "round") {
|
if (element.points.length > 2 && element.roundness) {
|
||||||
const controlPoints = getControlPointsForBezierCurve(
|
const controlPoints = getControlPointsForBezierCurve(
|
||||||
element,
|
element,
|
||||||
element.points[endPointIndex],
|
element.points[endPointIndex],
|
||||||
@ -1221,16 +1221,8 @@ export class LinearElementEditor {
|
|||||||
offsetY: number,
|
offsetY: number,
|
||||||
otherUpdates?: { startBinding?: PointBinding; endBinding?: PointBinding },
|
otherUpdates?: { startBinding?: PointBinding; endBinding?: PointBinding },
|
||||||
) {
|
) {
|
||||||
const nextCoords = getElementPointsCoords(
|
const nextCoords = getElementPointsCoords(element, nextPoints);
|
||||||
element,
|
const prevCoords = getElementPointsCoords(element, element.points);
|
||||||
nextPoints,
|
|
||||||
element.strokeSharpness || "round",
|
|
||||||
);
|
|
||||||
const prevCoords = getElementPointsCoords(
|
|
||||||
element,
|
|
||||||
element.points,
|
|
||||||
element.strokeSharpness || "round",
|
|
||||||
);
|
|
||||||
const nextCenterX = (nextCoords[0] + nextCoords[2]) / 2;
|
const nextCenterX = (nextCoords[0] + nextCoords[2]) / 2;
|
||||||
const nextCenterY = (nextCoords[1] + nextCoords[3]) / 2;
|
const nextCenterY = (nextCoords[1] + nextCoords[3]) / 2;
|
||||||
const prevCenterX = (prevCoords[0] + prevCoords[2]) / 2;
|
const prevCenterX = (prevCoords[0] + prevCoords[2]) / 2;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { duplicateElement } from "./newElement";
|
import { duplicateElement } from "./newElement";
|
||||||
import { mutateElement } from "./mutateElement";
|
import { mutateElement } from "./mutateElement";
|
||||||
import { API } from "../tests/helpers/api";
|
import { API } from "../tests/helpers/api";
|
||||||
import { FONT_FAMILY } from "../constants";
|
import { FONT_FAMILY, ROUNDNESS } from "../constants";
|
||||||
import { isPrimitive } from "../utils";
|
import { isPrimitive } from "../utils";
|
||||||
|
|
||||||
const assertCloneObjects = (source: any, clone: any) => {
|
const assertCloneObjects = (source: any, clone: any) => {
|
||||||
@ -25,7 +25,7 @@ it("clones arrow element", () => {
|
|||||||
fillStyle: "hachure",
|
fillStyle: "hachure",
|
||||||
strokeWidth: 1,
|
strokeWidth: 1,
|
||||||
strokeStyle: "solid",
|
strokeStyle: "solid",
|
||||||
strokeSharpness: "round",
|
roundness: { type: ROUNDNESS.PROPORTIONAL_RADIUS },
|
||||||
roughness: 1,
|
roughness: 1,
|
||||||
opacity: 100,
|
opacity: 100,
|
||||||
});
|
});
|
||||||
@ -71,7 +71,7 @@ it("clones text element", () => {
|
|||||||
fillStyle: "hachure",
|
fillStyle: "hachure",
|
||||||
strokeWidth: 1,
|
strokeWidth: 1,
|
||||||
strokeStyle: "solid",
|
strokeStyle: "solid",
|
||||||
strokeSharpness: "round",
|
roundness: null,
|
||||||
roughness: 1,
|
roughness: 1,
|
||||||
opacity: 100,
|
opacity: 100,
|
||||||
text: "hello",
|
text: "hello",
|
||||||
|
@ -62,14 +62,15 @@ const _newElementBase = <T extends ExcalidrawElement>(
|
|||||||
height = 0,
|
height = 0,
|
||||||
angle = 0,
|
angle = 0,
|
||||||
groupIds = [],
|
groupIds = [],
|
||||||
strokeSharpness,
|
roundness = null,
|
||||||
boundElements = null,
|
boundElements = null,
|
||||||
link = null,
|
link = null,
|
||||||
locked,
|
locked,
|
||||||
...rest
|
...rest
|
||||||
}: ElementConstructorOpts & Omit<Partial<ExcalidrawGenericElement>, "type">,
|
}: ElementConstructorOpts & Omit<Partial<ExcalidrawGenericElement>, "type">,
|
||||||
) => {
|
) => {
|
||||||
const element = {
|
// assign type to guard against excess properties
|
||||||
|
const element: Merge<ExcalidrawGenericElement, { type: T["type"] }> = {
|
||||||
id: rest.id || randomId(),
|
id: rest.id || randomId(),
|
||||||
type,
|
type,
|
||||||
x,
|
x,
|
||||||
@ -85,7 +86,7 @@ const _newElementBase = <T extends ExcalidrawElement>(
|
|||||||
roughness,
|
roughness,
|
||||||
opacity,
|
opacity,
|
||||||
groupIds,
|
groupIds,
|
||||||
strokeSharpness,
|
roundness,
|
||||||
seed: rest.seed ?? randomInteger(),
|
seed: rest.seed ?? randomInteger(),
|
||||||
version: rest.version || 1,
|
version: rest.version || 1,
|
||||||
versionNonce: rest.versionNonce ?? 0,
|
versionNonce: rest.versionNonce ?? 0,
|
||||||
|
@ -152,3 +152,5 @@ export const isBoundToContainer = (
|
|||||||
isTextElement(element)
|
isTextElement(element)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const isUsingAdaptiveRadius = (type: string) => type === "rectangle";
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
import { Point } from "../types";
|
import { Point } from "../types";
|
||||||
import { FONT_FAMILY, TEXT_ALIGN, THEME, VERTICAL_ALIGN } from "../constants";
|
import {
|
||||||
|
FONT_FAMILY,
|
||||||
|
ROUNDNESS,
|
||||||
|
TEXT_ALIGN,
|
||||||
|
THEME,
|
||||||
|
VERTICAL_ALIGN,
|
||||||
|
} from "../constants";
|
||||||
|
|
||||||
export type ChartType = "bar" | "line";
|
export type ChartType = "bar" | "line";
|
||||||
export type FillStyle = "hachure" | "cross-hatch" | "solid";
|
export type FillStyle = "hachure" | "cross-hatch" | "solid";
|
||||||
@ -9,7 +15,8 @@ export type Theme = typeof THEME[keyof typeof THEME];
|
|||||||
export type FontString = string & { _brand: "fontString" };
|
export type FontString = string & { _brand: "fontString" };
|
||||||
export type GroupId = string;
|
export type GroupId = string;
|
||||||
export type PointerType = "mouse" | "pen" | "touch";
|
export type PointerType = "mouse" | "pen" | "touch";
|
||||||
export type StrokeSharpness = "round" | "sharp";
|
export type StrokeRoundness = "round" | "sharp";
|
||||||
|
export type RoundnessType = ValueOf<typeof ROUNDNESS>;
|
||||||
export type StrokeStyle = "solid" | "dashed" | "dotted";
|
export type StrokeStyle = "solid" | "dashed" | "dotted";
|
||||||
export type TextAlign = typeof TEXT_ALIGN[keyof typeof TEXT_ALIGN];
|
export type TextAlign = typeof TEXT_ALIGN[keyof typeof TEXT_ALIGN];
|
||||||
|
|
||||||
@ -25,7 +32,7 @@ type _ExcalidrawElementBase = Readonly<{
|
|||||||
fillStyle: FillStyle;
|
fillStyle: FillStyle;
|
||||||
strokeWidth: number;
|
strokeWidth: number;
|
||||||
strokeStyle: StrokeStyle;
|
strokeStyle: StrokeStyle;
|
||||||
strokeSharpness: StrokeSharpness;
|
roundness: null | { type: RoundnessType; value?: number };
|
||||||
roughness: number;
|
roughness: number;
|
||||||
opacity: number;
|
opacity: number;
|
||||||
width: number;
|
width: number;
|
||||||
|
36
src/math.ts
36
src/math.ts
@ -1,6 +1,15 @@
|
|||||||
import { NormalizedZoomValue, Point, Zoom } from "./types";
|
import { NormalizedZoomValue, Point, Zoom } from "./types";
|
||||||
import { LINE_CONFIRM_THRESHOLD } from "./constants";
|
import {
|
||||||
import { ExcalidrawLinearElement, NonDeleted } from "./element/types";
|
DEFAULT_ADAPTIVE_RADIUS,
|
||||||
|
LINE_CONFIRM_THRESHOLD,
|
||||||
|
DEFAULT_PROPORTIONAL_RADIUS,
|
||||||
|
ROUNDNESS,
|
||||||
|
} from "./constants";
|
||||||
|
import {
|
||||||
|
ExcalidrawElement,
|
||||||
|
ExcalidrawLinearElement,
|
||||||
|
NonDeleted,
|
||||||
|
} from "./element/types";
|
||||||
import { getShapeForElement } from "./renderer/renderElement";
|
import { getShapeForElement } from "./renderer/renderElement";
|
||||||
import { getCurvePathOps } from "./element/bounds";
|
import { getCurvePathOps } from "./element/bounds";
|
||||||
|
|
||||||
@ -266,6 +275,29 @@ export const getGridPoint = (
|
|||||||
return [x, y];
|
return [x, y];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getCornerRadius = (x: number, element: ExcalidrawElement) => {
|
||||||
|
if (
|
||||||
|
element.roundness?.type === ROUNDNESS.PROPORTIONAL_RADIUS ||
|
||||||
|
element.roundness?.type === ROUNDNESS.LEGACY
|
||||||
|
) {
|
||||||
|
return x * DEFAULT_PROPORTIONAL_RADIUS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element.roundness?.type === ROUNDNESS.ADAPTIVE_RADIUS) {
|
||||||
|
const fixedRadiusSize = element.roundness?.value ?? DEFAULT_ADAPTIVE_RADIUS;
|
||||||
|
|
||||||
|
const CUTOFF_SIZE = fixedRadiusSize / DEFAULT_PROPORTIONAL_RADIUS;
|
||||||
|
|
||||||
|
if (x <= CUTOFF_SIZE) {
|
||||||
|
return x * DEFAULT_PROPORTIONAL_RADIUS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fixedRadiusSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
export const getControlPointsForBezierCurve = (
|
export const getControlPointsForBezierCurve = (
|
||||||
element: NonDeleted<ExcalidrawLinearElement>,
|
element: NonDeleted<ExcalidrawLinearElement>,
|
||||||
endPoint: Point,
|
endPoint: Point,
|
||||||
|
@ -11,6 +11,12 @@ The change should be grouped under one of the below section and must contain PR
|
|||||||
Please add the latest change on the top under the correct section.
|
Please add the latest change on the top under the correct section.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
## Unreleased
|
||||||
|
|
||||||
|
### Excalidraw schema
|
||||||
|
|
||||||
|
- Merged `appState.currentItemStrokeSharpness` and `appState.currentItemLinearStrokeSharpness` into `appState.currentItemRoundness`. Renamed `changeSharpness` action to `changeRoundness`. Excalidraw element's `strokeSharpness` was changed to `roundness`. Check the PR for types and more details [#5553](https://github.com/excalidraw/excalidraw/pull/5553).
|
||||||
|
|
||||||
## 0.13.0 (2022-10-27)
|
## 0.13.0 (2022-10-27)
|
||||||
|
|
||||||
### Excalidraw API
|
### Excalidraw API
|
||||||
|
@ -13,7 +13,7 @@ import {
|
|||||||
withBatchedUpdates,
|
withBatchedUpdates,
|
||||||
withBatchedUpdatesThrottled,
|
withBatchedUpdatesThrottled,
|
||||||
} from "../../../utils";
|
} from "../../../utils";
|
||||||
import { EVENT } from "../../../constants";
|
import { EVENT, ROUNDNESS } from "../../../constants";
|
||||||
import { distance2d } from "../../../math";
|
import { distance2d } from "../../../math";
|
||||||
import { fileOpen } from "../../../data/filesystem";
|
import { fileOpen } from "../../../data/filesystem";
|
||||||
import { loadSceneOrLibraryFromBlob } from "../../utils";
|
import { loadSceneOrLibraryFromBlob } from "../../utils";
|
||||||
@ -244,7 +244,10 @@ export default function App() {
|
|||||||
locked: false,
|
locked: false,
|
||||||
link: null,
|
link: null,
|
||||||
updated: 1,
|
updated: 1,
|
||||||
strokeSharpness: "round",
|
roundness: {
|
||||||
|
type: ROUNDNESS.ADAPTIVE_RADIUS,
|
||||||
|
value: 32,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
null,
|
null,
|
||||||
|
@ -68,7 +68,7 @@ const excalidrawDiagram = {
|
|||||||
roughness: 1,
|
roughness: 1,
|
||||||
opacity: 100,
|
opacity: 100,
|
||||||
groupIds: [],
|
groupIds: [],
|
||||||
strokeSharpness: "sharp",
|
roundness: null,
|
||||||
seed: 1041657908,
|
seed: 1041657908,
|
||||||
version: 120,
|
version: 120,
|
||||||
versionNonce: 1188004276,
|
versionNonce: 1188004276,
|
||||||
|
@ -27,7 +27,7 @@ import { RoughGenerator } from "roughjs/bin/generator";
|
|||||||
|
|
||||||
import { RenderConfig } from "../scene/types";
|
import { RenderConfig } from "../scene/types";
|
||||||
import { distance, getFontString, getFontFamilyString, isRTL } from "../utils";
|
import { distance, getFontString, getFontFamilyString, isRTL } from "../utils";
|
||||||
import { isPathALoop } from "../math";
|
import { getCornerRadius, isPathALoop } from "../math";
|
||||||
import rough from "roughjs/bin/rough";
|
import rough from "roughjs/bin/rough";
|
||||||
import { AppState, BinaryFiles, Zoom } from "../types";
|
import { AppState, BinaryFiles, Zoom } from "../types";
|
||||||
import { getDefaultAppState } from "../appState";
|
import { getDefaultAppState } from "../appState";
|
||||||
@ -424,10 +424,10 @@ const generateElementShape = (
|
|||||||
|
|
||||||
switch (element.type) {
|
switch (element.type) {
|
||||||
case "rectangle":
|
case "rectangle":
|
||||||
if (element.strokeSharpness === "round") {
|
if (element.roundness) {
|
||||||
const w = element.width;
|
const w = element.width;
|
||||||
const h = element.height;
|
const h = element.height;
|
||||||
const r = Math.min(w, h) * 0.25;
|
const r = getCornerRadius(Math.min(w, h), element);
|
||||||
shape = generator.path(
|
shape = generator.path(
|
||||||
`M ${r} 0 L ${w - r} 0 Q ${w} 0, ${w} ${r} L ${w} ${
|
`M ${r} 0 L ${w - r} 0 Q ${w} 0, ${w} ${r} L ${w} ${
|
||||||
h - r
|
h - r
|
||||||
@ -451,32 +451,36 @@ const generateElementShape = (
|
|||||||
case "diamond": {
|
case "diamond": {
|
||||||
const [topX, topY, rightX, rightY, bottomX, bottomY, leftX, leftY] =
|
const [topX, topY, rightX, rightY, bottomX, bottomY, leftX, leftY] =
|
||||||
getDiamondPoints(element);
|
getDiamondPoints(element);
|
||||||
if (element.strokeSharpness === "round") {
|
if (element.roundness) {
|
||||||
|
const verticalRadius = getCornerRadius(
|
||||||
|
Math.abs(topX - leftX),
|
||||||
|
element,
|
||||||
|
);
|
||||||
|
|
||||||
|
const horizontalRadius = getCornerRadius(
|
||||||
|
Math.abs(rightY - topY),
|
||||||
|
element,
|
||||||
|
);
|
||||||
|
|
||||||
shape = generator.path(
|
shape = generator.path(
|
||||||
`M ${topX + (rightX - topX) * 0.25} ${
|
`M ${topX + verticalRadius} ${topY + horizontalRadius} L ${
|
||||||
topY + (rightY - topY) * 0.25
|
rightX - verticalRadius
|
||||||
} L ${rightX - (rightX - topX) * 0.25} ${
|
} ${rightY - horizontalRadius}
|
||||||
rightY - (rightY - topY) * 0.25
|
|
||||||
}
|
|
||||||
C ${rightX} ${rightY}, ${rightX} ${rightY}, ${
|
C ${rightX} ${rightY}, ${rightX} ${rightY}, ${
|
||||||
rightX - (rightX - bottomX) * 0.25
|
rightX - verticalRadius
|
||||||
} ${rightY + (bottomY - rightY) * 0.25}
|
} ${rightY + horizontalRadius}
|
||||||
L ${bottomX + (rightX - bottomX) * 0.25} ${
|
L ${bottomX + verticalRadius} ${bottomY - horizontalRadius}
|
||||||
bottomY - (bottomY - rightY) * 0.25
|
|
||||||
}
|
|
||||||
C ${bottomX} ${bottomY}, ${bottomX} ${bottomY}, ${
|
C ${bottomX} ${bottomY}, ${bottomX} ${bottomY}, ${
|
||||||
bottomX - (bottomX - leftX) * 0.25
|
bottomX - verticalRadius
|
||||||
} ${bottomY - (bottomY - leftY) * 0.25}
|
} ${bottomY - horizontalRadius}
|
||||||
L ${leftX + (bottomX - leftX) * 0.25} ${
|
L ${leftX + verticalRadius} ${leftY + horizontalRadius}
|
||||||
leftY + (bottomY - leftY) * 0.25
|
C ${leftX} ${leftY}, ${leftX} ${leftY}, ${leftX + verticalRadius} ${
|
||||||
|
leftY - horizontalRadius
|
||||||
}
|
}
|
||||||
C ${leftX} ${leftY}, ${leftX} ${leftY}, ${
|
L ${topX - verticalRadius} ${topY + horizontalRadius}
|
||||||
leftX + (topX - leftX) * 0.25
|
C ${topX} ${topY}, ${topX} ${topY}, ${topX + verticalRadius} ${
|
||||||
} ${leftY - (leftY - topY) * 0.25}
|
topY + horizontalRadius
|
||||||
L ${topX - (topX - leftX) * 0.25} ${topY + (leftY - topY) * 0.25}
|
}`,
|
||||||
C ${topX} ${topY}, ${topX} ${topY}, ${
|
|
||||||
topX + (rightX - topX) * 0.25
|
|
||||||
} ${topY + (rightY - topY) * 0.25}`,
|
|
||||||
generateRoughOptions(element, true),
|
generateRoughOptions(element, true),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@ -515,7 +519,7 @@ const generateElementShape = (
|
|||||||
|
|
||||||
// curve is always the first element
|
// curve is always the first element
|
||||||
// this simplifies finding the curve for an element
|
// this simplifies finding the curve for an element
|
||||||
if (element.strokeSharpness === "sharp") {
|
if (!element.roundness) {
|
||||||
if (options.fill) {
|
if (options.fill) {
|
||||||
shape = [generator.polygon(points as [number, number][], options)];
|
shape = [generator.polygon(points as [number, number][], options)];
|
||||||
} else {
|
} else {
|
||||||
|
@ -24,7 +24,7 @@ export const hasStrokeStyle = (type: string) =>
|
|||||||
type === "arrow" ||
|
type === "arrow" ||
|
||||||
type === "line";
|
type === "line";
|
||||||
|
|
||||||
export const canChangeSharpness = (type: string) =>
|
export const canChangeRoundness = (type: string) =>
|
||||||
type === "rectangle" ||
|
type === "rectangle" ||
|
||||||
type === "arrow" ||
|
type === "arrow" ||
|
||||||
type === "line" ||
|
type === "line" ||
|
||||||
|
@ -12,7 +12,7 @@ export {
|
|||||||
hasStrokeWidth,
|
hasStrokeWidth,
|
||||||
hasStrokeStyle,
|
hasStrokeStyle,
|
||||||
canHaveArrowheads,
|
canHaveArrowheads,
|
||||||
canChangeSharpness,
|
canChangeRoundness,
|
||||||
getElementAtPosition,
|
getElementAtPosition,
|
||||||
hasText,
|
hasText,
|
||||||
getElementsAtPosition,
|
getElementsAtPosition,
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -29,11 +29,13 @@ Object {
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
|
"roundness": Object {
|
||||||
|
"type": 2,
|
||||||
|
},
|
||||||
"seed": 337897,
|
"seed": 337897,
|
||||||
"startArrowhead": null,
|
"startArrowhead": null,
|
||||||
"startBinding": null,
|
"startBinding": null,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"strokeSharpness": "round",
|
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 1,
|
"strokeWidth": 1,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
@ -62,9 +64,11 @@ Object {
|
|||||||
"locked": false,
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
|
"roundness": Object {
|
||||||
|
"type": 2,
|
||||||
|
},
|
||||||
"seed": 337897,
|
"seed": 337897,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"strokeSharpness": "sharp",
|
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 1,
|
"strokeWidth": 1,
|
||||||
"type": "diamond",
|
"type": "diamond",
|
||||||
@ -93,9 +97,11 @@ Object {
|
|||||||
"locked": false,
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
|
"roundness": Object {
|
||||||
|
"type": 2,
|
||||||
|
},
|
||||||
"seed": 337897,
|
"seed": 337897,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"strokeSharpness": "sharp",
|
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 1,
|
"strokeWidth": 1,
|
||||||
"type": "ellipse",
|
"type": "ellipse",
|
||||||
@ -135,11 +141,13 @@ Object {
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
|
"roundness": Object {
|
||||||
|
"type": 2,
|
||||||
|
},
|
||||||
"seed": 337897,
|
"seed": 337897,
|
||||||
"startArrowhead": null,
|
"startArrowhead": null,
|
||||||
"startBinding": null,
|
"startBinding": null,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"strokeSharpness": "round",
|
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 1,
|
"strokeWidth": 1,
|
||||||
"type": "line",
|
"type": "line",
|
||||||
@ -168,9 +176,11 @@ Object {
|
|||||||
"locked": false,
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
|
"roundness": Object {
|
||||||
|
"type": 3,
|
||||||
|
},
|
||||||
"seed": 337897,
|
"seed": 337897,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"strokeSharpness": "sharp",
|
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 1,
|
"strokeWidth": 1,
|
||||||
"type": "rectangle",
|
"type": "rectangle",
|
||||||
|
@ -14,9 +14,11 @@ Object {
|
|||||||
"locked": false,
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
|
"roundness": Object {
|
||||||
|
"type": 3,
|
||||||
|
},
|
||||||
"seed": 401146281,
|
"seed": 401146281,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"strokeSharpness": "sharp",
|
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 1,
|
"strokeWidth": 1,
|
||||||
"type": "rectangle",
|
"type": "rectangle",
|
||||||
@ -43,9 +45,11 @@ Object {
|
|||||||
"locked": false,
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
|
"roundness": Object {
|
||||||
|
"type": 3,
|
||||||
|
},
|
||||||
"seed": 337897,
|
"seed": 337897,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"strokeSharpness": "sharp",
|
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 1,
|
"strokeWidth": 1,
|
||||||
"type": "rectangle",
|
"type": "rectangle",
|
||||||
@ -72,9 +76,11 @@ Object {
|
|||||||
"locked": false,
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
|
"roundness": Object {
|
||||||
|
"type": 3,
|
||||||
|
},
|
||||||
"seed": 337897,
|
"seed": 337897,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"strokeSharpness": "sharp",
|
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 1,
|
"strokeWidth": 1,
|
||||||
"type": "rectangle",
|
"type": "rectangle",
|
||||||
@ -106,9 +112,11 @@ Object {
|
|||||||
"locked": false,
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
|
"roundness": Object {
|
||||||
|
"type": 3,
|
||||||
|
},
|
||||||
"seed": 337897,
|
"seed": 337897,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"strokeSharpness": "sharp",
|
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 1,
|
"strokeWidth": 1,
|
||||||
"type": "rectangle",
|
"type": "rectangle",
|
||||||
@ -140,9 +148,11 @@ Object {
|
|||||||
"locked": false,
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
|
"roundness": Object {
|
||||||
|
"type": 3,
|
||||||
|
},
|
||||||
"seed": 449462985,
|
"seed": 449462985,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"strokeSharpness": "sharp",
|
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 1,
|
"strokeWidth": 1,
|
||||||
"type": "rectangle",
|
"type": "rectangle",
|
||||||
@ -186,6 +196,9 @@ Object {
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
|
"roundness": Object {
|
||||||
|
"type": 2,
|
||||||
|
},
|
||||||
"seed": 401146281,
|
"seed": 401146281,
|
||||||
"startArrowhead": null,
|
"startArrowhead": null,
|
||||||
"startBinding": Object {
|
"startBinding": Object {
|
||||||
@ -194,7 +207,6 @@ Object {
|
|||||||
"gap": 10,
|
"gap": 10,
|
||||||
},
|
},
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"strokeSharpness": "round",
|
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 1,
|
"strokeWidth": 1,
|
||||||
"type": "line",
|
"type": "line",
|
||||||
|
@ -34,11 +34,13 @@ Object {
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
|
"roundness": Object {
|
||||||
|
"type": 2,
|
||||||
|
},
|
||||||
"seed": 337897,
|
"seed": 337897,
|
||||||
"startArrowhead": null,
|
"startArrowhead": null,
|
||||||
"startBinding": null,
|
"startBinding": null,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"strokeSharpness": "round",
|
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 1,
|
"strokeWidth": 1,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
@ -85,11 +87,13 @@ Object {
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
|
"roundness": Object {
|
||||||
|
"type": 2,
|
||||||
|
},
|
||||||
"seed": 337897,
|
"seed": 337897,
|
||||||
"startArrowhead": null,
|
"startArrowhead": null,
|
||||||
"startBinding": null,
|
"startBinding": null,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"strokeSharpness": "round",
|
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 1,
|
"strokeWidth": 1,
|
||||||
"type": "line",
|
"type": "line",
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -27,11 +27,13 @@ Object {
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
|
"roundness": Object {
|
||||||
|
"type": 2,
|
||||||
|
},
|
||||||
"seed": 337897,
|
"seed": 337897,
|
||||||
"startArrowhead": null,
|
"startArrowhead": null,
|
||||||
"startBinding": null,
|
"startBinding": null,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"strokeSharpness": "round",
|
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 1,
|
"strokeWidth": 1,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
@ -71,11 +73,13 @@ Object {
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
|
"roundness": Object {
|
||||||
|
"type": 2,
|
||||||
|
},
|
||||||
"seed": 337897,
|
"seed": 337897,
|
||||||
"startArrowhead": null,
|
"startArrowhead": null,
|
||||||
"startBinding": null,
|
"startBinding": null,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"strokeSharpness": "round",
|
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 1,
|
"strokeWidth": 1,
|
||||||
"type": "line",
|
"type": "line",
|
||||||
@ -102,9 +106,11 @@ Object {
|
|||||||
"locked": false,
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
|
"roundness": Object {
|
||||||
|
"type": 2,
|
||||||
|
},
|
||||||
"seed": 337897,
|
"seed": 337897,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"strokeSharpness": "sharp",
|
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 1,
|
"strokeWidth": 1,
|
||||||
"type": "diamond",
|
"type": "diamond",
|
||||||
@ -131,9 +137,11 @@ Object {
|
|||||||
"locked": false,
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
|
"roundness": Object {
|
||||||
|
"type": 2,
|
||||||
|
},
|
||||||
"seed": 337897,
|
"seed": 337897,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"strokeSharpness": "sharp",
|
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 1,
|
"strokeWidth": 1,
|
||||||
"type": "ellipse",
|
"type": "ellipse",
|
||||||
@ -160,9 +168,11 @@ Object {
|
|||||||
"locked": false,
|
"locked": false,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
|
"roundness": Object {
|
||||||
|
"type": 3,
|
||||||
|
},
|
||||||
"seed": 337897,
|
"seed": 337897,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"strokeSharpness": "sharp",
|
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 1,
|
"strokeWidth": 1,
|
||||||
"type": "rectangle",
|
"type": "rectangle",
|
||||||
|
@ -27,11 +27,13 @@ Object {
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
|
"roundness": Object {
|
||||||
|
"type": 2,
|
||||||
|
},
|
||||||
"seed": Any<Number>,
|
"seed": Any<Number>,
|
||||||
"startArrowhead": null,
|
"startArrowhead": null,
|
||||||
"startBinding": null,
|
"startBinding": null,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"strokeSharpness": "sharp",
|
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 1,
|
"strokeWidth": 1,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
@ -62,9 +64,11 @@ Object {
|
|||||||
"locked": false,
|
"locked": false,
|
||||||
"opacity": 10,
|
"opacity": 10,
|
||||||
"roughness": 2,
|
"roughness": 2,
|
||||||
|
"roundness": Object {
|
||||||
|
"type": 3,
|
||||||
|
},
|
||||||
"seed": Any<Number>,
|
"seed": Any<Number>,
|
||||||
"strokeColor": "red",
|
"strokeColor": "red",
|
||||||
"strokeSharpness": "round",
|
|
||||||
"strokeStyle": "dashed",
|
"strokeStyle": "dashed",
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "rectangle",
|
"type": "rectangle",
|
||||||
@ -95,9 +99,11 @@ Object {
|
|||||||
"locked": false,
|
"locked": false,
|
||||||
"opacity": 10,
|
"opacity": 10,
|
||||||
"roughness": 2,
|
"roughness": 2,
|
||||||
|
"roundness": Object {
|
||||||
|
"type": 3,
|
||||||
|
},
|
||||||
"seed": Any<Number>,
|
"seed": Any<Number>,
|
||||||
"strokeColor": "red",
|
"strokeColor": "red",
|
||||||
"strokeSharpness": "round",
|
|
||||||
"strokeStyle": "dashed",
|
"strokeStyle": "dashed",
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "ellipse",
|
"type": "ellipse",
|
||||||
@ -128,9 +134,11 @@ Object {
|
|||||||
"locked": false,
|
"locked": false,
|
||||||
"opacity": 10,
|
"opacity": 10,
|
||||||
"roughness": 2,
|
"roughness": 2,
|
||||||
|
"roundness": Object {
|
||||||
|
"type": 3,
|
||||||
|
},
|
||||||
"seed": Any<Number>,
|
"seed": Any<Number>,
|
||||||
"strokeColor": "red",
|
"strokeColor": "red",
|
||||||
"strokeSharpness": "round",
|
|
||||||
"strokeStyle": "dashed",
|
"strokeStyle": "dashed",
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "diamond",
|
"type": "diamond",
|
||||||
@ -160,10 +168,12 @@ Object {
|
|||||||
"points": Array [],
|
"points": Array [],
|
||||||
"pressures": Array [],
|
"pressures": Array [],
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
|
"roundness": Object {
|
||||||
|
"type": 3,
|
||||||
|
},
|
||||||
"seed": Any<Number>,
|
"seed": Any<Number>,
|
||||||
"simulatePressure": true,
|
"simulatePressure": true,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"strokeSharpness": "sharp",
|
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 1,
|
"strokeWidth": 1,
|
||||||
"type": "freedraw",
|
"type": "freedraw",
|
||||||
@ -203,11 +213,13 @@ Object {
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
|
"roundness": Object {
|
||||||
|
"type": 2,
|
||||||
|
},
|
||||||
"seed": Any<Number>,
|
"seed": Any<Number>,
|
||||||
"startArrowhead": null,
|
"startArrowhead": null,
|
||||||
"startBinding": null,
|
"startBinding": null,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"strokeSharpness": "sharp",
|
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 1,
|
"strokeWidth": 1,
|
||||||
"type": "line",
|
"type": "line",
|
||||||
@ -247,11 +259,13 @@ Object {
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
|
"roundness": Object {
|
||||||
|
"type": 2,
|
||||||
|
},
|
||||||
"seed": Any<Number>,
|
"seed": Any<Number>,
|
||||||
"startArrowhead": null,
|
"startArrowhead": null,
|
||||||
"startBinding": null,
|
"startBinding": null,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"strokeSharpness": "sharp",
|
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 1,
|
"strokeWidth": 1,
|
||||||
"type": "line",
|
"type": "line",
|
||||||
@ -283,9 +297,11 @@ Object {
|
|||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"originalText": "text",
|
"originalText": "text",
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
|
"roundness": Object {
|
||||||
|
"type": 3,
|
||||||
|
},
|
||||||
"seed": Any<Number>,
|
"seed": Any<Number>,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"strokeSharpness": "sharp",
|
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 1,
|
"strokeWidth": 1,
|
||||||
"text": "text",
|
"text": "text",
|
||||||
@ -320,9 +336,11 @@ Object {
|
|||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"originalText": "test",
|
"originalText": "test",
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
|
"roundness": Object {
|
||||||
|
"type": 3,
|
||||||
|
},
|
||||||
"seed": Any<Number>,
|
"seed": Any<Number>,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"strokeSharpness": "sharp",
|
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 1,
|
"strokeWidth": 1,
|
||||||
"text": "",
|
"text": "",
|
||||||
|
@ -10,7 +10,7 @@ import { API } from "../helpers/api";
|
|||||||
import { getDefaultAppState } from "../../appState";
|
import { getDefaultAppState } from "../../appState";
|
||||||
import { ImportedDataState } from "../../data/types";
|
import { ImportedDataState } from "../../data/types";
|
||||||
import { NormalizedZoomValue } from "../../types";
|
import { NormalizedZoomValue } from "../../types";
|
||||||
import { FONT_FAMILY } from "../../constants";
|
import { FONT_FAMILY, ROUNDNESS } from "../../constants";
|
||||||
import { newElementWith } from "../../element/mutateElement";
|
import { newElementWith } from "../../element/mutateElement";
|
||||||
|
|
||||||
const mockSizeHelper = jest.spyOn(sizeHelpers, "isInvisiblySmallElement");
|
const mockSizeHelper = jest.spyOn(sizeHelpers, "isInvisiblySmallElement");
|
||||||
@ -255,7 +255,7 @@ describe("restoreElements", () => {
|
|||||||
width: 100,
|
width: 100,
|
||||||
height: 200,
|
height: 200,
|
||||||
groupIds: ["1", "2", "3"],
|
groupIds: ["1", "2", "3"],
|
||||||
strokeSharpness: "round",
|
roundness: { type: ROUNDNESS.PROPORTIONAL_RADIUS },
|
||||||
});
|
});
|
||||||
|
|
||||||
elements.push(element);
|
elements.push(element);
|
||||||
|
2
src/tests/fixtures/elementFixture.ts
vendored
2
src/tests/fixtures/elementFixture.ts
vendored
@ -15,7 +15,7 @@ const elementBase: Omit<ExcalidrawElement, "type"> = {
|
|||||||
roughness: 1,
|
roughness: 1,
|
||||||
opacity: 100,
|
opacity: 100,
|
||||||
groupIds: [],
|
groupIds: [],
|
||||||
strokeSharpness: "sharp",
|
roundness: null,
|
||||||
seed: 1041657908,
|
seed: 1041657908,
|
||||||
version: 120,
|
version: 120,
|
||||||
versionNonce: 1188004276,
|
versionNonce: 1188004276,
|
||||||
|
@ -8,7 +8,7 @@ import {
|
|||||||
FileId,
|
FileId,
|
||||||
} from "../../element/types";
|
} from "../../element/types";
|
||||||
import { newElement, newTextElement, newLinearElement } from "../../element";
|
import { newElement, newTextElement, newLinearElement } from "../../element";
|
||||||
import { DEFAULT_VERTICAL_ALIGN } from "../../constants";
|
import { DEFAULT_VERTICAL_ALIGN, ROUNDNESS } from "../../constants";
|
||||||
import { getDefaultAppState } from "../../appState";
|
import { getDefaultAppState } from "../../appState";
|
||||||
import { GlobalTestState, createEvent, fireEvent } from "../test-utils";
|
import { GlobalTestState, createEvent, fireEvent } from "../test-utils";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
@ -18,6 +18,7 @@ import { getMimeType } from "../../data/blob";
|
|||||||
import { newFreeDrawElement, newImageElement } from "../../element/newElement";
|
import { newFreeDrawElement, newImageElement } from "../../element/newElement";
|
||||||
import { Point } from "../../types";
|
import { Point } from "../../types";
|
||||||
import { getSelectedElements } from "../../scene/selection";
|
import { getSelectedElements } from "../../scene/selection";
|
||||||
|
import { isLinearElementType } from "../../element/typeChecks";
|
||||||
|
|
||||||
const readFile = util.promisify(fs.readFile);
|
const readFile = util.promisify(fs.readFile);
|
||||||
|
|
||||||
@ -89,7 +90,7 @@ export class API {
|
|||||||
fillStyle?: ExcalidrawGenericElement["fillStyle"];
|
fillStyle?: ExcalidrawGenericElement["fillStyle"];
|
||||||
strokeWidth?: ExcalidrawGenericElement["strokeWidth"];
|
strokeWidth?: ExcalidrawGenericElement["strokeWidth"];
|
||||||
strokeStyle?: ExcalidrawGenericElement["strokeStyle"];
|
strokeStyle?: ExcalidrawGenericElement["strokeStyle"];
|
||||||
strokeSharpness?: ExcalidrawGenericElement["strokeSharpness"];
|
roundness?: ExcalidrawGenericElement["roundness"];
|
||||||
roughness?: ExcalidrawGenericElement["roughness"];
|
roughness?: ExcalidrawGenericElement["roughness"];
|
||||||
opacity?: ExcalidrawGenericElement["opacity"];
|
opacity?: ExcalidrawGenericElement["opacity"];
|
||||||
// text props
|
// text props
|
||||||
@ -125,7 +126,20 @@ export class API {
|
|||||||
|
|
||||||
const appState = h?.state || getDefaultAppState();
|
const appState = h?.state || getDefaultAppState();
|
||||||
|
|
||||||
const base = {
|
const base: Omit<
|
||||||
|
ExcalidrawGenericElement,
|
||||||
|
| "id"
|
||||||
|
| "width"
|
||||||
|
| "height"
|
||||||
|
| "type"
|
||||||
|
| "seed"
|
||||||
|
| "version"
|
||||||
|
| "versionNonce"
|
||||||
|
| "isDeleted"
|
||||||
|
| "groupIds"
|
||||||
|
| "link"
|
||||||
|
| "updated"
|
||||||
|
> = {
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
angle: rest.angle ?? 0,
|
angle: rest.angle ?? 0,
|
||||||
@ -135,8 +149,17 @@ export class API {
|
|||||||
fillStyle: rest.fillStyle ?? appState.currentItemFillStyle,
|
fillStyle: rest.fillStyle ?? appState.currentItemFillStyle,
|
||||||
strokeWidth: rest.strokeWidth ?? appState.currentItemStrokeWidth,
|
strokeWidth: rest.strokeWidth ?? appState.currentItemStrokeWidth,
|
||||||
strokeStyle: rest.strokeStyle ?? appState.currentItemStrokeStyle,
|
strokeStyle: rest.strokeStyle ?? appState.currentItemStrokeStyle,
|
||||||
strokeSharpness:
|
roundness: (
|
||||||
rest.strokeSharpness ?? appState.currentItemStrokeSharpness,
|
rest.roundness === undefined
|
||||||
|
? appState.currentItemRoundness === "round"
|
||||||
|
: rest.roundness
|
||||||
|
)
|
||||||
|
? {
|
||||||
|
type: isLinearElementType(type)
|
||||||
|
? ROUNDNESS.PROPORTIONAL_RADIUS
|
||||||
|
: ROUNDNESS.ADAPTIVE_RADIUS,
|
||||||
|
}
|
||||||
|
: null,
|
||||||
roughness: rest.roughness ?? appState.currentItemRoughness,
|
roughness: rest.roughness ?? appState.currentItemRoughness,
|
||||||
opacity: rest.opacity ?? appState.currentItemOpacity,
|
opacity: rest.opacity ?? appState.currentItemOpacity,
|
||||||
boundElements: rest.boundElements ?? null,
|
boundElements: rest.boundElements ?? null,
|
||||||
|
@ -20,6 +20,7 @@ import { resize, rotate } from "./utils";
|
|||||||
import { getBoundTextElementPosition, wrapText } from "../element/textElement";
|
import { getBoundTextElementPosition, wrapText } from "../element/textElement";
|
||||||
import { getMaxContainerWidth } from "../element/newElement";
|
import { getMaxContainerWidth } from "../element/newElement";
|
||||||
import * as textElementUtils from "../element/textElement";
|
import * as textElementUtils from "../element/textElement";
|
||||||
|
import { ROUNDNESS } from "../constants";
|
||||||
|
|
||||||
const renderScene = jest.spyOn(Renderer, "renderScene");
|
const renderScene = jest.spyOn(Renderer, "renderScene");
|
||||||
|
|
||||||
@ -51,7 +52,7 @@ describe("Test Linear Elements", () => {
|
|||||||
|
|
||||||
const createTwoPointerLinearElement = (
|
const createTwoPointerLinearElement = (
|
||||||
type: ExcalidrawLinearElement["type"],
|
type: ExcalidrawLinearElement["type"],
|
||||||
strokeSharpness: ExcalidrawLinearElement["strokeSharpness"] = "sharp",
|
roundness: ExcalidrawElement["roundness"] = null,
|
||||||
roughness: ExcalidrawLinearElement["roughness"] = 0,
|
roughness: ExcalidrawLinearElement["roughness"] = 0,
|
||||||
) => {
|
) => {
|
||||||
const line = API.createElement({
|
const line = API.createElement({
|
||||||
@ -65,7 +66,7 @@ describe("Test Linear Elements", () => {
|
|||||||
[0, 0],
|
[0, 0],
|
||||||
[p2[0] - p1[0], p2[1] - p1[1]],
|
[p2[0] - p1[0], p2[1] - p1[1]],
|
||||||
],
|
],
|
||||||
strokeSharpness,
|
roundness,
|
||||||
});
|
});
|
||||||
h.elements = [line];
|
h.elements = [line];
|
||||||
|
|
||||||
@ -75,7 +76,7 @@ describe("Test Linear Elements", () => {
|
|||||||
|
|
||||||
const createThreePointerLinearElement = (
|
const createThreePointerLinearElement = (
|
||||||
type: ExcalidrawLinearElement["type"],
|
type: ExcalidrawLinearElement["type"],
|
||||||
strokeSharpness: ExcalidrawLinearElement["strokeSharpness"] = "sharp",
|
roundness: ExcalidrawElement["roundness"] = null,
|
||||||
roughness: ExcalidrawLinearElement["roughness"] = 0,
|
roughness: ExcalidrawLinearElement["roughness"] = 0,
|
||||||
) => {
|
) => {
|
||||||
//dragging line from midpoint
|
//dragging line from midpoint
|
||||||
@ -92,7 +93,7 @@ describe("Test Linear Elements", () => {
|
|||||||
[p3[0], p3[1]],
|
[p3[0], p3[1]],
|
||||||
[p2[0] - p1[0], p2[1] - p1[1]],
|
[p2[0] - p1[0], p2[1] - p1[1]],
|
||||||
],
|
],
|
||||||
strokeSharpness,
|
roundness,
|
||||||
});
|
});
|
||||||
h.elements = [line];
|
h.elements = [line];
|
||||||
mouse.clickAt(p1[0], p1[1]);
|
mouse.clickAt(p1[0], p1[1]);
|
||||||
@ -286,7 +287,7 @@ describe("Test Linear Elements", () => {
|
|||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should update the midpoints when element sharpness changed", async () => {
|
it("should update the midpoints when element roundness changed", async () => {
|
||||||
createThreePointerLinearElement("line");
|
createThreePointerLinearElement("line");
|
||||||
|
|
||||||
const line = h.elements[0] as ExcalidrawLinearElement;
|
const line = h.elements[0] as ExcalidrawLinearElement;
|
||||||
@ -299,7 +300,7 @@ describe("Test Linear Elements", () => {
|
|||||||
h.state,
|
h.state,
|
||||||
);
|
);
|
||||||
|
|
||||||
// update sharpness
|
// update roundness
|
||||||
fireEvent.click(screen.getByTitle("Round"));
|
fireEvent.click(screen.getByTitle("Round"));
|
||||||
|
|
||||||
expect(renderScene).toHaveBeenCalledTimes(12);
|
expect(renderScene).toHaveBeenCalledTimes(12);
|
||||||
@ -325,7 +326,9 @@ describe("Test Linear Elements", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should update all the midpoints when element position changed", async () => {
|
it("should update all the midpoints when element position changed", async () => {
|
||||||
createThreePointerLinearElement("line", "round");
|
createThreePointerLinearElement("line", {
|
||||||
|
type: ROUNDNESS.PROPORTIONAL_RADIUS,
|
||||||
|
});
|
||||||
|
|
||||||
const line = h.elements[0] as ExcalidrawLinearElement;
|
const line = h.elements[0] as ExcalidrawLinearElement;
|
||||||
expect(line.points.length).toEqual(3);
|
expect(line.points.length).toEqual(3);
|
||||||
@ -370,8 +373,8 @@ describe("Test Linear Elements", () => {
|
|||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("When edges are sharp", () => {
|
describe("When edges are round", () => {
|
||||||
// This is the expected midpoint for line with sharp edge
|
// This is the expected midpoint for line with round edge
|
||||||
// hence hardcoding it so if later some bug is introduced
|
// hence hardcoding it so if later some bug is introduced
|
||||||
// this will fail and we can fix it
|
// this will fail and we can fix it
|
||||||
const firstSegmentMidpoint: Point = [55, 45];
|
const firstSegmentMidpoint: Point = [55, 45];
|
||||||
@ -525,7 +528,9 @@ describe("Test Linear Elements", () => {
|
|||||||
let line: ExcalidrawLinearElement;
|
let line: ExcalidrawLinearElement;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
line = createThreePointerLinearElement("line", "round");
|
line = createThreePointerLinearElement("line", {
|
||||||
|
type: ROUNDNESS.PROPORTIONAL_RADIUS,
|
||||||
|
});
|
||||||
expect(line.points.length).toEqual(3);
|
expect(line.points.length).toEqual(3);
|
||||||
|
|
||||||
enterLineEditingMode(line);
|
enterLineEditingMode(line);
|
||||||
@ -768,7 +773,9 @@ describe("Test Linear Elements", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should return correct position for arrow with odd points", () => {
|
it("should return correct position for arrow with odd points", () => {
|
||||||
createThreePointerLinearElement("arrow", "round");
|
createThreePointerLinearElement("arrow", {
|
||||||
|
type: ROUNDNESS.PROPORTIONAL_RADIUS,
|
||||||
|
});
|
||||||
const arrow = h.elements[0] as ExcalidrawLinearElement;
|
const arrow = h.elements[0] as ExcalidrawLinearElement;
|
||||||
const { textElement, container } = createBoundTextElement(
|
const { textElement, container } = createBoundTextElement(
|
||||||
DEFAULT_TEXT,
|
DEFAULT_TEXT,
|
||||||
@ -788,7 +795,9 @@ describe("Test Linear Elements", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should return correct position for arrow with even points", () => {
|
it("should return correct position for arrow with even points", () => {
|
||||||
createThreePointerLinearElement("arrow", "round");
|
createThreePointerLinearElement("arrow", {
|
||||||
|
type: ROUNDNESS.PROPORTIONAL_RADIUS,
|
||||||
|
});
|
||||||
const arrow = h.elements[0] as ExcalidrawLinearElement;
|
const arrow = h.elements[0] as ExcalidrawLinearElement;
|
||||||
const { textElement, container } = createBoundTextElement(
|
const { textElement, container } = createBoundTextElement(
|
||||||
DEFAULT_TEXT,
|
DEFAULT_TEXT,
|
||||||
@ -903,7 +912,9 @@ describe("Test Linear Elements", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should not rotate the bound text and update position of bound text and bounding box correctly when arrow rotated", () => {
|
it("should not rotate the bound text and update position of bound text and bounding box correctly when arrow rotated", () => {
|
||||||
createThreePointerLinearElement("arrow", "round");
|
createThreePointerLinearElement("arrow", {
|
||||||
|
type: ROUNDNESS.PROPORTIONAL_RADIUS,
|
||||||
|
});
|
||||||
|
|
||||||
const arrow = h.elements[0] as ExcalidrawLinearElement;
|
const arrow = h.elements[0] as ExcalidrawLinearElement;
|
||||||
|
|
||||||
@ -967,7 +978,9 @@ describe("Test Linear Elements", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should resize and position the bound text and bounding box correctly when 3 pointer arrow element resized", () => {
|
it("should resize and position the bound text and bounding box correctly when 3 pointer arrow element resized", () => {
|
||||||
createThreePointerLinearElement("arrow", "round");
|
createThreePointerLinearElement("arrow", {
|
||||||
|
type: ROUNDNESS.PROPORTIONAL_RADIUS,
|
||||||
|
});
|
||||||
|
|
||||||
const arrow = h.elements[0] as ExcalidrawLinearElement;
|
const arrow = h.elements[0] as ExcalidrawLinearElement;
|
||||||
|
|
||||||
|
@ -15,12 +15,11 @@ Object {
|
|||||||
"currentItemFillStyle": "hachure",
|
"currentItemFillStyle": "hachure",
|
||||||
"currentItemFontFamily": 1,
|
"currentItemFontFamily": 1,
|
||||||
"currentItemFontSize": 20,
|
"currentItemFontSize": 20,
|
||||||
"currentItemLinearStrokeSharpness": "round",
|
|
||||||
"currentItemOpacity": 100,
|
"currentItemOpacity": 100,
|
||||||
"currentItemRoughness": 1,
|
"currentItemRoughness": 1,
|
||||||
|
"currentItemRoundness": "round",
|
||||||
"currentItemStartArrowhead": null,
|
"currentItemStartArrowhead": null,
|
||||||
"currentItemStrokeColor": "#000000",
|
"currentItemStrokeColor": "#000000",
|
||||||
"currentItemStrokeSharpness": "sharp",
|
|
||||||
"currentItemStrokeStyle": "solid",
|
"currentItemStrokeStyle": "solid",
|
||||||
"currentItemStrokeWidth": 1,
|
"currentItemStrokeWidth": 1,
|
||||||
"currentItemTextAlign": "left",
|
"currentItemTextAlign": "left",
|
||||||
|
@ -95,7 +95,7 @@ exports[`exportToSvg with elements that have a link 1`] = `
|
|||||||
exports[`exportToSvg with exportEmbedScene 1`] = `
|
exports[`exportToSvg with exportEmbedScene 1`] = `
|
||||||
"
|
"
|
||||||
<!-- svg-source:excalidraw -->
|
<!-- svg-source:excalidraw -->
|
||||||
<!-- payload-type:application/vnd.excalidraw+json --><!-- payload-version:2 --><!-- payload-start -->eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nO1SPW/CMFx1MDAxMN35XHUwMDE1kbtcIpGk4aNstFRVpapcdTAwMWRcdTAwMTiQWnUw8YVYMbaxXHUwMDFkPoT477VccsRtxNpcclx1MDAwZpbu+b278907dKJcYpm9XHUwMDA0NI5cdTAwMTDscswoUXiLulx1MDAwZd+A0lRw+5T6WIta5Z5ZXHUwMDFhI8e9XHUwMDFlXHUwMDEzVlBcbm1OfGCwXHUwMDAybrRlfNk4ilx1MDAwZf62L5Q41Wau1lx1MDAxZpOiopyk63w1fJtOXj691JN2lpMlWVx1MDAxM+9d4fthXHUwMDEzbykxpcWSOG6wXHUwMDEy6LI0LVx1MDAxMPMlc21cdTAwMDZEXHUwMDFiJSp4XHUwMDEyTCjXyF3sTyi9wHm1VKLmJHCSPsaLXCJwXG7K2Mzs2WlcdTAwMDA4L2tcdTAwMDWoVWF+abGFNzot7ICDypZcXJZcdTAwMWO0/qNcdTAwMTFcdTAwMTLn1Oxbv3L9yVfip/vdzl9iJc95kHbBr85cdTAwMDCIT5Ulg/7wIVx1MDAxZTUvYb9JXHUwMDFht9F3wf2uk2Q0iuMsXHUwMDFkXHUwMDBlXHUwMDFhXHUwMDA21VO7auPTXHUwMDE2mGlcYnN0I3xcdTAwMGU24DVjzWMtXHQ+icJXXHUwMDE55VWbZ11VXcl9cSmheCU4QVx1MDAxZT92b0a7XHUwMDE57X+MXHUwMDA2jFGp4Ww0e/thICzlzNj8lnKyXHUwMDFk2lDYPl5ZbOGP03ubusWCa/Zw7Fx1MDAxY39cdTAwMDCLqmbvIn0=<!-- payload-end -->
|
<!-- payload-type:application/vnd.excalidraw+json --><!-- payload-version:2 --><!-- payload-start -->eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nO1SsW7CMFx1MDAxMN35iihdkUjSQChcdTAwMWItVVWpalx1MDAwN1x1MDAwNqRWXHUwMDFkTHxJrFx1MDAxONvEXHUwMDBlXHUwMDEwIf69tlx1MDAwM3GJXHUwMDE4O9aDpXt+7+58945cdTAwMDPP81UjwJ95Plx1MDAxY1JEXHSu0N5cdTAwMWZcdTAwMWF8XHUwMDA3lSSc6afIxpLXVWqZhVJiNlx1MDAxYVGuXHUwMDA1XHUwMDA1l6rlXHUwMDAzhVxyMCU140vHnne0t34h2Kh2q2r7Mc9KwnC0TTfJ22L+8mmllnTQnDiMu7gxhe+TLt5cdTAwMTOsXG6NhUHQYVx1MDAwNZC8UD1cdTAwMTCxnJo2XHUwMDFkXCJVxUt44pRXppG7wFx1MDAxZVd6jdIyr3jNsOOEY4TWmeNkhNKlamg7XHUwMDAwlFx1MDAxNnVcdTAwMDV+r8Lq0mJcdTAwMGbvdJLrXHUwMDAxO5UumVx1MDAxN1xmpLzScIFSoprer0x/4lx1MDAxNdvpfv/OwPA5XHUwMDAzqyl1hVx1MDAwMbDNXHUwMDEwh5Nx8lx1MDAxMEy7XHUwMDE3t9YwXG766DtndsVhOJ1cdTAwMDZBXHUwMDFjJZOOQeRCb1jZtFx1MDAxOaJcdTAwMTLc+ExcdTAwMTPPbvtXjdRcdTAwMDKjVuR+SFx0K/s8babyRu6LOTFBXHUwMDFizrBv8dPw31///vpTf1x1MDAwMaVESDj7S992XHUwMDA2Plx1MDAxMmKpdH5Nad3m71xi7Fx1MDAxZm/sM7PH6K07zT7BNHs8XHJOP7VXYMUifQ==<!-- payload-end -->
|
||||||
<defs>
|
<defs>
|
||||||
<style class=\\"style-fonts\\">
|
<style class=\\"style-fonts\\">
|
||||||
@font-face {
|
@font-face {
|
||||||
|
@ -13,6 +13,7 @@ import {
|
|||||||
FileId,
|
FileId,
|
||||||
ExcalidrawImageElement,
|
ExcalidrawImageElement,
|
||||||
Theme,
|
Theme,
|
||||||
|
StrokeRoundness,
|
||||||
} from "./element/types";
|
} from "./element/types";
|
||||||
import { SHAPES } from "./shapes";
|
import { SHAPES } from "./shapes";
|
||||||
import { Point as RoughPoint } from "roughjs/bin/geometry";
|
import { Point as RoughPoint } from "roughjs/bin/geometry";
|
||||||
@ -134,10 +135,9 @@ export type AppState = {
|
|||||||
currentItemFontFamily: FontFamilyValues;
|
currentItemFontFamily: FontFamilyValues;
|
||||||
currentItemFontSize: number;
|
currentItemFontSize: number;
|
||||||
currentItemTextAlign: TextAlign;
|
currentItemTextAlign: TextAlign;
|
||||||
currentItemStrokeSharpness: ExcalidrawElement["strokeSharpness"];
|
|
||||||
currentItemStartArrowhead: Arrowhead | null;
|
currentItemStartArrowhead: Arrowhead | null;
|
||||||
currentItemEndArrowhead: Arrowhead | null;
|
currentItemEndArrowhead: Arrowhead | null;
|
||||||
currentItemLinearStrokeSharpness: ExcalidrawElement["strokeSharpness"];
|
currentItemRoundness: StrokeRoundness;
|
||||||
viewBackgroundColor: string;
|
viewBackgroundColor: string;
|
||||||
scrollX: number;
|
scrollX: number;
|
||||||
scrollY: number;
|
scrollY: number;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user