More
This commit is contained in:
parent
40cd4caeec
commit
1d7c5705b2
@ -18,6 +18,7 @@ import { getNewZoom } from "../scene/zoom";
|
||||
import { centerScrollOn } from "../scene/scroll";
|
||||
import { EVENT_ACTION, EVENT_CHANGE, trackEvent } from "../analytics";
|
||||
import colors from "../colors";
|
||||
import { GRID_SIZE } from "../constants";
|
||||
|
||||
export const actionChangeViewBackgroundColor = register({
|
||||
name: "changeViewBackgroundColor",
|
||||
@ -64,7 +65,7 @@ export const actionClearCanvas = register({
|
||||
elementLocked: appState.elementLocked,
|
||||
exportBackground: appState.exportBackground,
|
||||
exportEmbedScene: appState.exportEmbedScene,
|
||||
gridSize: appState.gridSize,
|
||||
gridSize: appState.gridSize || GRID_SIZE,
|
||||
shouldAddWatermark: appState.shouldAddWatermark,
|
||||
showStats: appState.showStats,
|
||||
},
|
||||
|
@ -1,181 +1,167 @@
|
||||
import { Point, simplify } from "points-on-curve";
|
||||
import React from "react";
|
||||
|
||||
import rough from "roughjs/bin/rough";
|
||||
import { RoughCanvas } from "roughjs/bin/canvas";
|
||||
import { simplify, Point } from "points-on-curve";
|
||||
|
||||
import {
|
||||
newElement,
|
||||
newTextElement,
|
||||
duplicateElement,
|
||||
isInvisiblySmallElement,
|
||||
isTextElement,
|
||||
textWysiwyg,
|
||||
getCommonBounds,
|
||||
getCursorForResizingElement,
|
||||
getPerfectElementSize,
|
||||
getNormalizedDimensions,
|
||||
newLinearElement,
|
||||
transformElements,
|
||||
getElementWithTransformHandleType,
|
||||
getResizeOffsetXY,
|
||||
getResizeArrowDirection,
|
||||
getTransformHandleTypeFromCoords,
|
||||
isNonDeletedElement,
|
||||
updateTextElement,
|
||||
dragSelectedElements,
|
||||
getDragOffsetXY,
|
||||
dragNewElement,
|
||||
hitTest,
|
||||
isHittingElementBoundingBoxWithoutHittingElement,
|
||||
getNonDeletedElements,
|
||||
} from "../element";
|
||||
import {
|
||||
getElementsWithinSelection,
|
||||
isOverScrollBars,
|
||||
getElementsAtPosition,
|
||||
getElementContainingPosition,
|
||||
getNormalizedZoom,
|
||||
getSelectedElements,
|
||||
isSomeElementSelected,
|
||||
calculateScrollCenter,
|
||||
} from "../scene";
|
||||
import { loadFromBlob, exportCanvas } from "../data";
|
||||
|
||||
import { renderScene } from "../renderer";
|
||||
import {
|
||||
AppState,
|
||||
GestureEvent,
|
||||
Gesture,
|
||||
ExcalidrawProps,
|
||||
SceneData,
|
||||
} from "../types";
|
||||
import {
|
||||
ExcalidrawElement,
|
||||
ExcalidrawTextElement,
|
||||
NonDeleted,
|
||||
ExcalidrawGenericElement,
|
||||
ExcalidrawLinearElement,
|
||||
ExcalidrawBindableElement,
|
||||
} from "../element/types";
|
||||
|
||||
import { distance2d, isPathALoop, getGridPoint } from "../math";
|
||||
|
||||
import {
|
||||
isWritableElement,
|
||||
isInputLike,
|
||||
isToolIcon,
|
||||
debounce,
|
||||
distance,
|
||||
resetCursor,
|
||||
viewportCoordsToSceneCoords,
|
||||
sceneCoordsToViewportCoords,
|
||||
setCursorForShape,
|
||||
tupleToCoors,
|
||||
ResolvablePromise,
|
||||
resolvablePromise,
|
||||
withBatchedUpdates,
|
||||
} from "../utils";
|
||||
import {
|
||||
KEYS,
|
||||
isArrowKey,
|
||||
getResizeCenterPointKey,
|
||||
getResizeWithSidesSameLengthKey,
|
||||
getRotateWithDiscreteAngleKey,
|
||||
CODES,
|
||||
} from "../keys";
|
||||
|
||||
import { findShapeByKey } from "../shapes";
|
||||
import { createHistory, SceneHistory } from "../history";
|
||||
|
||||
import ContextMenu from "./ContextMenu";
|
||||
|
||||
import { ActionManager } from "../actions/manager";
|
||||
import rough from "roughjs/bin/rough";
|
||||
import "../actions";
|
||||
import { actionDeleteSelected, actionFinalize } from "../actions";
|
||||
import { createRedoAction, createUndoAction } from "../actions/actionHistory";
|
||||
import { ActionManager } from "../actions/manager";
|
||||
import { actions } from "../actions/register";
|
||||
|
||||
import { ActionResult } from "../actions/types";
|
||||
import { getDefaultAppState } from "../appState";
|
||||
import { t, getLanguage } from "../i18n";
|
||||
|
||||
import {
|
||||
copyToClipboard,
|
||||
parseClipboard,
|
||||
probablySupportsClipboardBlob,
|
||||
probablySupportsClipboardWriteText,
|
||||
} from "../clipboard";
|
||||
import { normalizeScroll } from "../scene";
|
||||
import { getCenter, getDistance } from "../gesture";
|
||||
import { createUndoAction, createRedoAction } from "../actions/actionHistory";
|
||||
|
||||
import {
|
||||
CURSOR_TYPE,
|
||||
ELEMENT_SHIFT_TRANSLATE_AMOUNT,
|
||||
ELEMENT_TRANSLATE_AMOUNT,
|
||||
POINTER_BUTTON,
|
||||
DRAGGING_THRESHOLD,
|
||||
TEXT_TO_CENTER_SNAP_THRESHOLD,
|
||||
LINE_CONFIRM_THRESHOLD,
|
||||
EVENT,
|
||||
ENV,
|
||||
CANVAS_ONLY_ACTIONS,
|
||||
DEFAULT_VERTICAL_ALIGN,
|
||||
GRID_SIZE,
|
||||
MIME_TYPES,
|
||||
TAP_TWICE_TIMEOUT,
|
||||
TOUCH_CTX_MENU_TIMEOUT,
|
||||
APP_NAME,
|
||||
} from "../constants";
|
||||
|
||||
import LayerUI from "./LayerUI";
|
||||
import { ScrollBars, SceneState } from "../scene/types";
|
||||
import { mutateElement } from "../element/mutateElement";
|
||||
import { invalidateShapeForElement } from "../renderer/renderElement";
|
||||
import {
|
||||
isLinearElement,
|
||||
isLinearElementType,
|
||||
isBindingElement,
|
||||
isBindingElementType,
|
||||
} from "../element/typeChecks";
|
||||
import { actionFinalize, actionDeleteSelected } from "../actions";
|
||||
|
||||
import { LinearElementEditor } from "../element/linearElementEditor";
|
||||
import {
|
||||
getSelectedGroupIds,
|
||||
isSelectedViaGroup,
|
||||
selectGroupsForSelectedElements,
|
||||
isElementInGroup,
|
||||
getSelectedGroupIdForElement,
|
||||
getElementsInGroup,
|
||||
editGroupForSelectedElement,
|
||||
} from "../groups";
|
||||
import { Library } from "../data/library";
|
||||
import Scene from "../scene/Scene";
|
||||
import {
|
||||
getHoveredElementForBinding,
|
||||
maybeBindLinearElement,
|
||||
getEligibleElementsForBinding,
|
||||
bindOrUnbindSelectedElements,
|
||||
unbindLinearElements,
|
||||
fixBindingsAfterDuplication,
|
||||
fixBindingsAfterDeletion,
|
||||
isLinearElementSimpleAndAlreadyBound,
|
||||
isBindingEnabled,
|
||||
updateBoundElements,
|
||||
shouldEnableBindingForPointerEvent,
|
||||
} from "../element/binding";
|
||||
import { MaybeTransformHandleType } from "../element/transformHandles";
|
||||
import { deepCopyElement } from "../element/newElement";
|
||||
import { renderSpreadsheet } from "../charts";
|
||||
import { isValidLibrary } from "../data/json";
|
||||
import { getNewZoom } from "../scene/zoom";
|
||||
import { restore } from "../data/restore";
|
||||
import {
|
||||
EVENT_DIALOG,
|
||||
EVENT_LIBRARY,
|
||||
EVENT_SHAPE,
|
||||
trackEvent,
|
||||
} from "../analytics";
|
||||
import { getDefaultAppState } from "../appState";
|
||||
import { renderSpreadsheet } from "../charts";
|
||||
import {
|
||||
copyToClipboard,
|
||||
parseClipboard,
|
||||
probablySupportsClipboardBlob,
|
||||
probablySupportsClipboardWriteText,
|
||||
} from "../clipboard";
|
||||
import {
|
||||
APP_NAME,
|
||||
CANVAS_ONLY_ACTIONS,
|
||||
CURSOR_TYPE,
|
||||
DEFAULT_VERTICAL_ALIGN,
|
||||
DRAGGING_THRESHOLD,
|
||||
ELEMENT_SHIFT_TRANSLATE_AMOUNT,
|
||||
ELEMENT_TRANSLATE_AMOUNT,
|
||||
ENV,
|
||||
EVENT,
|
||||
LINE_CONFIRM_THRESHOLD,
|
||||
MIME_TYPES,
|
||||
POINTER_BUTTON,
|
||||
TAP_TWICE_TIMEOUT,
|
||||
TEXT_TO_CENTER_SNAP_THRESHOLD,
|
||||
TOUCH_CTX_MENU_TIMEOUT,
|
||||
} from "../constants";
|
||||
import { exportCanvas, loadFromBlob } from "../data";
|
||||
import { isValidLibrary } from "../data/json";
|
||||
import { Library } from "../data/library";
|
||||
import { restore } from "../data/restore";
|
||||
import {
|
||||
dragNewElement,
|
||||
dragSelectedElements,
|
||||
duplicateElement,
|
||||
getCommonBounds,
|
||||
getCursorForResizingElement,
|
||||
getDragOffsetXY,
|
||||
getElementWithTransformHandleType,
|
||||
getNonDeletedElements,
|
||||
getNormalizedDimensions,
|
||||
getPerfectElementSize,
|
||||
getResizeArrowDirection,
|
||||
getResizeOffsetXY,
|
||||
getTransformHandleTypeFromCoords,
|
||||
hitTest,
|
||||
isHittingElementBoundingBoxWithoutHittingElement,
|
||||
isInvisiblySmallElement,
|
||||
isNonDeletedElement,
|
||||
isTextElement,
|
||||
newElement,
|
||||
newLinearElement,
|
||||
newTextElement,
|
||||
textWysiwyg,
|
||||
transformElements,
|
||||
updateTextElement,
|
||||
} from "../element";
|
||||
import {
|
||||
bindOrUnbindSelectedElements,
|
||||
fixBindingsAfterDeletion,
|
||||
fixBindingsAfterDuplication,
|
||||
getEligibleElementsForBinding,
|
||||
getHoveredElementForBinding,
|
||||
isBindingEnabled,
|
||||
isLinearElementSimpleAndAlreadyBound,
|
||||
maybeBindLinearElement,
|
||||
shouldEnableBindingForPointerEvent,
|
||||
unbindLinearElements,
|
||||
updateBoundElements,
|
||||
} from "../element/binding";
|
||||
import { LinearElementEditor } from "../element/linearElementEditor";
|
||||
import { mutateElement } from "../element/mutateElement";
|
||||
import { deepCopyElement } from "../element/newElement";
|
||||
import { MaybeTransformHandleType } from "../element/transformHandles";
|
||||
import {
|
||||
isBindingElement,
|
||||
isBindingElementType,
|
||||
isLinearElement,
|
||||
isLinearElementType,
|
||||
} from "../element/typeChecks";
|
||||
import {
|
||||
ExcalidrawBindableElement,
|
||||
ExcalidrawElement,
|
||||
ExcalidrawGenericElement,
|
||||
ExcalidrawLinearElement,
|
||||
ExcalidrawTextElement,
|
||||
NonDeleted,
|
||||
} from "../element/types";
|
||||
import { getCenter, getDistance } from "../gesture";
|
||||
import {
|
||||
editGroupForSelectedElement,
|
||||
getElementsInGroup,
|
||||
getSelectedGroupIdForElement,
|
||||
getSelectedGroupIds,
|
||||
isElementInGroup,
|
||||
isSelectedViaGroup,
|
||||
selectGroupsForSelectedElements,
|
||||
} from "../groups";
|
||||
import { createHistory, SceneHistory } from "../history";
|
||||
import { getLanguage, t } from "../i18n";
|
||||
import {
|
||||
CODES,
|
||||
getResizeCenterPointKey,
|
||||
getResizeWithSidesSameLengthKey,
|
||||
getRotateWithDiscreteAngleKey,
|
||||
isArrowKey,
|
||||
KEYS,
|
||||
} from "../keys";
|
||||
import { distance2d, getGridPoint, isPathALoop } from "../math";
|
||||
import { renderScene } from "../renderer";
|
||||
import { invalidateShapeForElement } from "../renderer/renderElement";
|
||||
import {
|
||||
calculateScrollCenter,
|
||||
getElementContainingPosition,
|
||||
getElementsAtPosition,
|
||||
getElementsWithinSelection,
|
||||
getNormalizedZoom,
|
||||
getSelectedElements,
|
||||
isOverScrollBars,
|
||||
isSomeElementSelected,
|
||||
normalizeScroll,
|
||||
} from "../scene";
|
||||
import Scene from "../scene/Scene";
|
||||
import { SceneState, ScrollBars } from "../scene/types";
|
||||
import { getNewZoom } from "../scene/zoom";
|
||||
import { findShapeByKey } from "../shapes";
|
||||
import {
|
||||
AppState,
|
||||
ExcalidrawProps,
|
||||
Gesture,
|
||||
GestureEvent,
|
||||
SceneData,
|
||||
} from "../types";
|
||||
import {
|
||||
debounce,
|
||||
distance,
|
||||
isInputLike,
|
||||
isToolIcon,
|
||||
isWritableElement,
|
||||
resetCursor,
|
||||
ResolvablePromise,
|
||||
resolvablePromise,
|
||||
sceneCoordsToViewportCoords,
|
||||
setCursorForShape,
|
||||
tupleToCoors,
|
||||
viewportCoordsToSceneCoords,
|
||||
withBatchedUpdates,
|
||||
} from "../utils";
|
||||
import ContextMenu from "./ContextMenu";
|
||||
import LayerUI from "./LayerUI";
|
||||
import { Stats } from "./Stats";
|
||||
|
||||
const { history } = createHistory();
|
||||
@ -3662,7 +3648,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
CANVAS_ONLY_ACTIONS.includes(action.name),
|
||||
),
|
||||
{
|
||||
checked: this.state.gridSize !== null,
|
||||
checked: this.state.showGrid,
|
||||
shortcutName: "gridMode",
|
||||
label: t("labels.gridMode"),
|
||||
action: this.toggleGridMode,
|
||||
|
@ -1,68 +0,0 @@
|
||||
import React, { CSSProperties, useEffect, useState } from "react";
|
||||
import classes from "./SlidableInput.module.css";
|
||||
import { throttle } from "./utils/throttle";
|
||||
|
||||
interface SlidableInputProps {
|
||||
value: number;
|
||||
prefix?: string;
|
||||
suffix?: string;
|
||||
minValue?: number;
|
||||
maxValue?: number;
|
||||
style?: CSSProperties;
|
||||
onChange?: (value: number) => void;
|
||||
}
|
||||
|
||||
export const SlidableInput: React.FC<SlidableInputProps> = ({
|
||||
value,
|
||||
style,
|
||||
prefix,
|
||||
suffix,
|
||||
onChange,
|
||||
minValue,
|
||||
maxValue,
|
||||
}) => {
|
||||
const [isLocked, setIsLocked] = useState<boolean>(true);
|
||||
const previousX = React.useRef(0);
|
||||
|
||||
useEffect(() => {
|
||||
const onMouseMoveHandler = throttle((event: MouseEvent) => {
|
||||
if (isLocked) return;
|
||||
|
||||
const nextX = event.screenX;
|
||||
if (nextX === previousX.current) return;
|
||||
const nextValue = value + (nextX > previousX.current ? 1 : -1);
|
||||
|
||||
onChange &&
|
||||
nextValue <= (maxValue || Infinity) &&
|
||||
nextValue >= (typeof minValue === "number" ? minValue : -Infinity) &&
|
||||
onChange(nextValue);
|
||||
|
||||
previousX.current = nextX;
|
||||
}, 250) as EventListenerOrEventListenerObject;
|
||||
|
||||
window.addEventListener("mousemove", onMouseMoveHandler);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("mousemove", onMouseMoveHandler);
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isLocked, value]);
|
||||
|
||||
const onMouseDown = () => setIsLocked(false);
|
||||
|
||||
useEffect(() => {
|
||||
const onMouseUp = () => setIsLocked(true);
|
||||
window.addEventListener("mouseup", onMouseUp);
|
||||
return () => {
|
||||
window.removeEventListener("mouseup", onMouseUp);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<span className={classes.input} style={style} onMouseDown={onMouseDown}>
|
||||
{prefix}
|
||||
{value}
|
||||
{suffix}
|
||||
</span>
|
||||
);
|
||||
};
|
@ -12,7 +12,6 @@ import { AppState } from "../types";
|
||||
import { debounce, nFormatter } from "../utils";
|
||||
import { close } from "./icons";
|
||||
import { Island } from "./Island";
|
||||
import { SlidableInput } from "./SlidableInput";
|
||||
import "./Stats.scss";
|
||||
|
||||
type StorageSizes = { scene: number; total: number };
|
||||
@ -158,19 +157,23 @@ export const Stats = (props: {
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
|
||||
<tr>
|
||||
<th colSpan={2}>{"Misc"}</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{"Grid size"}</td>
|
||||
<td>
|
||||
<SlidableInput
|
||||
value={props.appState.gridSize || 8}
|
||||
minValue={8}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
{props.appState.showGrid && (
|
||||
<>
|
||||
<tr>
|
||||
<th colSpan={2}>{"Misc"}</th>
|
||||
</tr>
|
||||
<tr
|
||||
onClick={() => {
|
||||
// TODO: better way to update the gridSize and re-render the scene
|
||||
props.appState.gridSize =
|
||||
((props.appState.gridSize - 5) % 50) + 10;
|
||||
}}
|
||||
>
|
||||
<td>{"Grid size"}</td>
|
||||
<td>{props.appState.gridSize}</td>
|
||||
</tr>
|
||||
</>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</Island>
|
||||
|
@ -1,14 +0,0 @@
|
||||
export const throttle = (func: Function, limit: number): Function => {
|
||||
let inThrottle: boolean;
|
||||
|
||||
return function (this: any): any {
|
||||
const args = arguments;
|
||||
const context = this;
|
||||
|
||||
if (!inThrottle) {
|
||||
inThrottle = true;
|
||||
func.apply(context, args);
|
||||
setTimeout(() => (inThrottle = false), limit);
|
||||
}
|
||||
};
|
||||
};
|
@ -233,7 +233,7 @@ export const renderScene = (
|
||||
context.scale(sceneState.zoom.value, sceneState.zoom.value);
|
||||
|
||||
// Grid
|
||||
if (renderGrid && appState.gridSize) {
|
||||
if (renderGrid && appState.showGrid) {
|
||||
strokeGrid(
|
||||
context,
|
||||
appState.gridSize,
|
||||
|
Loading…
x
Reference in New Issue
Block a user