feat: Change grid size

change-grid
Panayiotis Lipiridis 4 years ago
parent 39e7b8cf4f
commit 40cd4caeec

@ -6,6 +6,7 @@ import {
DEFAULT_FONT_SIZE,
DEFAULT_FONT_FAMILY,
DEFAULT_TEXT_ALIGN,
GRID_SIZE,
} from "./constants";
export const getDefaultAppState = (): Omit<
@ -65,7 +66,8 @@ export const getDefaultAppState = (): Omit<
showShortcutsDialog: false,
suggestedBindings: [],
zenModeEnabled: false,
gridSize: null,
gridSize: GRID_SIZE,
showGrid: false,
editingGroupId: null,
selectedGroupIds: {},
width: window.innerWidth,
@ -121,6 +123,7 @@ const APP_STATE_STORAGE_CONF = (<
exportBackground: { browser: true, export: false },
exportEmbedScene: { browser: true, export: false },
gridSize: { browser: true, export: true },
showGrid: { browser: true, export: false },
height: { browser: false, export: false },
isBindingEnabled: { browser: false, export: false },
isLibraryOpen: { browser: false, export: false },

@ -1036,7 +1036,12 @@ class App extends React.Component<ExcalidrawProps, AppState> {
const dy = y - elementsCenterY;
const groupIdMap = new Map();
const [gridX, gridY] = getGridPoint(dx, dy, this.state.gridSize);
const [gridX, gridY] = getGridPoint(
dx,
dy,
this.state.showGrid,
this.state.gridSize,
);
const oldIdToDuplicatedId = new Map();
const newElements = clipboardElements.map((element) => {
@ -1149,7 +1154,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
toggleGridMode = () => {
this.setState({
gridSize: this.state.gridSize ? null : GRID_SIZE,
showGrid: !this.state.showGrid,
});
};
@ -1275,7 +1280,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
if (isArrowKey(event.key)) {
const step =
(this.state.gridSize &&
(this.state.showGrid &&
(event.shiftKey ? ELEMENT_TRANSLATE_AMOUNT : this.state.gridSize)) ||
(event.shiftKey
? ELEMENT_SHIFT_TRANSLATE_AMOUNT
@ -1819,6 +1824,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
scenePointerX,
scenePointerY,
this.state.editingLinearElement,
this.state.showGrid,
this.state.gridSize,
);
if (editingLinearElement !== this.state.editingLinearElement) {
@ -2249,7 +2255,12 @@ class App extends React.Component<ExcalidrawProps, AppState> {
return {
origin,
originInGrid: tupleToCoors(
getGridPoint(origin.x, origin.y, this.state.gridSize),
getGridPoint(
origin.x,
origin.y,
this.state.showGrid,
this.state.gridSize,
),
),
scrollbars: isOverScrollBars(
currentScrollBars,
@ -2607,7 +2618,8 @@ class App extends React.Component<ExcalidrawProps, AppState> {
const [gridX, gridY] = getGridPoint(
pointerDownState.origin.x,
pointerDownState.origin.y,
elementType === "draw" ? null : this.state.gridSize,
elementType === "draw" ? false : this.state.showGrid,
this.state.gridSize,
);
/* If arrow is pre-arrowheads, it will have undefined for both start and end arrowheads.
@ -2669,6 +2681,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
const [gridX, gridY] = getGridPoint(
pointerDownState.origin.x,
pointerDownState.origin.y,
this.state.showGrid,
this.state.gridSize,
);
const element = newElement({
@ -2758,6 +2771,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
const [gridX, gridY] = getGridPoint(
pointerCoords.x,
pointerCoords.y,
this.state.showGrid,
this.state.gridSize,
);
@ -2830,6 +2844,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
const [dragX, dragY] = getGridPoint(
pointerCoords.x - pointerDownState.drag.offset.x,
pointerCoords.y - pointerDownState.drag.offset.y,
this.state.showGrid,
this.state.gridSize,
);
@ -2882,6 +2897,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
const [originDragX, originDragY] = getGridPoint(
pointerDownState.origin.x - pointerDownState.drag.offset.x,
pointerDownState.origin.y - pointerDownState.drag.offset.y,
this.state.showGrid,
this.state.gridSize,
);
mutateElement(duplicatedElement, {
@ -3542,6 +3558,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
const [gridX, gridY] = getGridPoint(
pointerCoords.x,
pointerCoords.y,
this.state.showGrid,
this.state.gridSize,
);
dragNewElement(
@ -3580,6 +3597,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
const [resizeX, resizeY] = getGridPoint(
pointerCoords.x - pointerDownState.resize.offset.x,
pointerCoords.y - pointerDownState.resize.offset.y,
this.state.showGrid,
this.state.gridSize,
);
if (

@ -0,0 +1,4 @@
.input {
cursor: ew-resize;
user-select: none;
}

@ -0,0 +1,68 @@
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,6 +12,7 @@ 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 };
@ -157,6 +158,19 @@ 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>
</tbody>
</table>
</Island>

@ -0,0 +1,14 @@
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);
}
};
};

@ -102,6 +102,7 @@ export class LinearElementEditor {
element,
scenePointerX - editingLinearElement.pointerOffset.x,
scenePointerY - editingLinearElement.pointerOffset.y,
appState.showGrid,
appState.gridSize,
);
LinearElementEditor.movePoint(element, activePointIndex, newPoint);
@ -198,6 +199,7 @@ export class LinearElementEditor {
element,
scenePointer.x,
scenePointer.y,
appState.showGrid,
appState.gridSize,
),
],
@ -282,7 +284,8 @@ export class LinearElementEditor {
scenePointerX: number,
scenePointerY: number,
editingLinearElement: LinearElementEditor,
gridSize: number | null,
isGridOn: boolean,
gridSize: number,
): LinearElementEditor {
const { elementId, lastUncommittedPoint } = editingLinearElement;
const element = LinearElementEditor.getElement(elementId);
@ -304,6 +307,7 @@ export class LinearElementEditor {
element,
scenePointerX - editingLinearElement.pointerOffset.x,
scenePointerY - editingLinearElement.pointerOffset.y,
isGridOn,
gridSize,
);
@ -398,9 +402,15 @@ export class LinearElementEditor {
element: NonDeleted<ExcalidrawLinearElement>,
scenePointerX: number,
scenePointerY: number,
gridSize: number | null,
isGridOn: boolean,
gridSize: number,
): Point {
const pointerOnGrid = getGridPoint(scenePointerX, scenePointerY, gridSize);
const pointerOnGrid = getGridPoint(
scenePointerX,
scenePointerY,
isGridOn,
gridSize,
);
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
const cx = (x1 + x2) / 2;
const cy = (y1 + y2) / 2;

@ -307,9 +307,10 @@ const doSegmentsIntersect = (p1: Point, q1: Point, p2: Point, q2: Point) => {
export const getGridPoint = (
x: number,
y: number,
gridSize: number | null,
isGridOn: boolean,
gridSize: number,
): [number, number] => {
if (gridSize) {
if (isGridOn) {
return [
Math.round(x / gridSize) * gridSize,
Math.round(y / gridSize) * gridSize,

@ -75,7 +75,7 @@ const excalidrawDiagram = {
],
appState: {
viewBackgroundColor: "#ffffff",
gridSize: null,
gridSize: 20,
},
};

@ -83,7 +83,8 @@ export type AppState = {
showShortcutsDialog: boolean;
zenModeEnabled: boolean;
appearance: "light" | "dark";
gridSize: number | null;
gridSize: number;
showGrid: boolean;
/** top-most selected groups (i.e. does not include nested groups) */
selectedGroupIds: { [groupId: string]: boolean };

Loading…
Cancel
Save