Compare commits
9 Commits
master
...
change-gri
Author | SHA1 | Date | |
---|---|---|---|
![]() |
8802ea62ca | ||
![]() |
3c86b014de | ||
![]() |
c6f06dd1fc | ||
![]() |
922e28a198 | ||
![]() |
49363afac1 | ||
![]() |
28a1b9a787 | ||
![]() |
9cfab40343 | ||
![]() |
1d7c5705b2 | ||
![]() |
40cd4caeec |
@ -3,7 +3,7 @@ import { getDefaultAppState } from "../appState";
|
|||||||
import { ColorPicker } from "../components/ColorPicker";
|
import { ColorPicker } from "../components/ColorPicker";
|
||||||
import { resetZoom, trash, zoomIn, zoomOut } from "../components/icons";
|
import { resetZoom, trash, zoomIn, zoomOut } from "../components/icons";
|
||||||
import { ToolButton } from "../components/ToolButton";
|
import { ToolButton } from "../components/ToolButton";
|
||||||
import { ZOOM_STEP } from "../constants";
|
import { GRID_SIZE, ZOOM_STEP } from "../constants";
|
||||||
import { getCommonBounds, getNonDeletedElements } from "../element";
|
import { getCommonBounds, getNonDeletedElements } from "../element";
|
||||||
import { newElementWith } from "../element/mutateElement";
|
import { newElementWith } from "../element/mutateElement";
|
||||||
import { ExcalidrawElement } from "../element/types";
|
import { ExcalidrawElement } from "../element/types";
|
||||||
@ -52,7 +52,7 @@ export const actionClearCanvas = register({
|
|||||||
elementLocked: appState.elementLocked,
|
elementLocked: appState.elementLocked,
|
||||||
exportBackground: appState.exportBackground,
|
exportBackground: appState.exportBackground,
|
||||||
exportEmbedScene: appState.exportEmbedScene,
|
exportEmbedScene: appState.exportEmbedScene,
|
||||||
gridSize: appState.gridSize,
|
gridSize: appState.gridSize || GRID_SIZE,
|
||||||
shouldAddWatermark: appState.shouldAddWatermark,
|
shouldAddWatermark: appState.shouldAddWatermark,
|
||||||
showStats: appState.showStats,
|
showStats: appState.showStats,
|
||||||
pasteDialog: appState.pasteDialog,
|
pasteDialog: appState.pasteDialog,
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import { CODES, KEYS } from "../keys";
|
|
||||||
import { register } from "./register";
|
|
||||||
import { GRID_SIZE } from "../constants";
|
|
||||||
import { AppState } from "../types";
|
|
||||||
import { trackEvent } from "../analytics";
|
import { trackEvent } from "../analytics";
|
||||||
|
import { CODES, KEYS } from "../keys";
|
||||||
|
import { AppState } from "../types";
|
||||||
|
import { register } from "./register";
|
||||||
|
|
||||||
export const actionToggleGridMode = register({
|
export const actionToggleGridMode = register({
|
||||||
name: "gridMode",
|
name: "gridMode",
|
||||||
@ -11,12 +10,12 @@ export const actionToggleGridMode = register({
|
|||||||
return {
|
return {
|
||||||
appState: {
|
appState: {
|
||||||
...appState,
|
...appState,
|
||||||
gridSize: this.checked!(appState) ? null : GRID_SIZE,
|
showGrid: !appState.showGrid,
|
||||||
},
|
},
|
||||||
commitToHistory: false,
|
commitToHistory: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
checked: (appState: AppState) => appState.gridSize !== null,
|
checked: (appState: AppState) => appState.showGrid,
|
||||||
contextItemLabel: "labels.gridMode",
|
contextItemLabel: "labels.gridMode",
|
||||||
keyTest: (event) => event[KEYS.CTRL_OR_CMD] && event.code === CODES.QUOTE,
|
keyTest: (event) => event[KEYS.CTRL_OR_CMD] && event.code === CODES.QUOTE,
|
||||||
});
|
});
|
||||||
|
@ -3,6 +3,7 @@ import {
|
|||||||
DEFAULT_FONT_FAMILY,
|
DEFAULT_FONT_FAMILY,
|
||||||
DEFAULT_FONT_SIZE,
|
DEFAULT_FONT_SIZE,
|
||||||
DEFAULT_TEXT_ALIGN,
|
DEFAULT_TEXT_ALIGN,
|
||||||
|
GRID_SIZE,
|
||||||
} from "./constants";
|
} from "./constants";
|
||||||
import { t } from "./i18n";
|
import { t } from "./i18n";
|
||||||
import { AppState, NormalizedZoomValue } from "./types";
|
import { AppState, NormalizedZoomValue } from "./types";
|
||||||
@ -41,7 +42,7 @@ export const getDefaultAppState = (): Omit<
|
|||||||
exportBackground: true,
|
exportBackground: true,
|
||||||
exportEmbedScene: false,
|
exportEmbedScene: false,
|
||||||
fileHandle: null,
|
fileHandle: null,
|
||||||
gridSize: null,
|
gridSize: GRID_SIZE,
|
||||||
height: window.innerHeight,
|
height: window.innerHeight,
|
||||||
isBindingEnabled: true,
|
isBindingEnabled: true,
|
||||||
isLibraryOpen: false,
|
isLibraryOpen: false,
|
||||||
@ -63,6 +64,7 @@ export const getDefaultAppState = (): Omit<
|
|||||||
selectionElement: null,
|
selectionElement: null,
|
||||||
shouldAddWatermark: false,
|
shouldAddWatermark: false,
|
||||||
shouldCacheIgnoreZoom: false,
|
shouldCacheIgnoreZoom: false,
|
||||||
|
showGrid: false,
|
||||||
showHelpDialog: false,
|
showHelpDialog: false,
|
||||||
showStats: false,
|
showStats: false,
|
||||||
startBoundElement: null,
|
startBoundElement: null,
|
||||||
@ -120,6 +122,7 @@ const APP_STATE_STORAGE_CONF = (<
|
|||||||
exportEmbedScene: { browser: true, export: false },
|
exportEmbedScene: { browser: true, export: false },
|
||||||
fileHandle: { browser: false, export: false },
|
fileHandle: { browser: false, export: false },
|
||||||
gridSize: { browser: true, export: true },
|
gridSize: { browser: true, export: true },
|
||||||
|
showGrid: { browser: true, export: false },
|
||||||
height: { browser: false, export: false },
|
height: { browser: false, export: false },
|
||||||
isBindingEnabled: { browser: false, export: false },
|
isBindingEnabled: { browser: false, export: false },
|
||||||
isLibraryOpen: { browser: false, export: false },
|
isLibraryOpen: { browser: false, export: false },
|
||||||
|
@ -456,6 +456,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
|||||||
/>
|
/>
|
||||||
{this.state.showStats && (
|
{this.state.showStats && (
|
||||||
<Stats
|
<Stats
|
||||||
|
setAppState={this.setAppState}
|
||||||
appState={this.state}
|
appState={this.state}
|
||||||
elements={this.scene.getElements()}
|
elements={this.scene.getElements()}
|
||||||
onClose={this.toggleStats}
|
onClose={this.toggleStats}
|
||||||
@ -1087,7 +1088,12 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
|||||||
const dy = y - elementsCenterY;
|
const dy = y - elementsCenterY;
|
||||||
const groupIdMap = new Map();
|
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 oldIdToDuplicatedId = new Map();
|
||||||
const newElements = clipboardElements.map((element) => {
|
const newElements = clipboardElements.map((element) => {
|
||||||
@ -1195,6 +1201,10 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
|||||||
this.actionManager.executeAction(actionToggleZenMode);
|
this.actionManager.executeAction(actionToggleZenMode);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
toggleGridMode = () => {
|
||||||
|
this.actionManager.executeAction(actionToggleGridMode);
|
||||||
|
};
|
||||||
|
|
||||||
toggleStats = () => {
|
toggleStats = () => {
|
||||||
if (!this.state.showStats) {
|
if (!this.state.showStats) {
|
||||||
trackEvent("dialog", "stats");
|
trackEvent("dialog", "stats");
|
||||||
@ -1307,7 +1317,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
|||||||
|
|
||||||
if (isArrowKey(event.key)) {
|
if (isArrowKey(event.key)) {
|
||||||
const step =
|
const step =
|
||||||
(this.state.gridSize &&
|
(this.state.showGrid &&
|
||||||
(event.shiftKey ? ELEMENT_TRANSLATE_AMOUNT : this.state.gridSize)) ||
|
(event.shiftKey ? ELEMENT_TRANSLATE_AMOUNT : this.state.gridSize)) ||
|
||||||
(event.shiftKey
|
(event.shiftKey
|
||||||
? ELEMENT_SHIFT_TRANSLATE_AMOUNT
|
? ELEMENT_SHIFT_TRANSLATE_AMOUNT
|
||||||
@ -1849,6 +1859,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
|||||||
scenePointerX,
|
scenePointerX,
|
||||||
scenePointerY,
|
scenePointerY,
|
||||||
this.state.editingLinearElement,
|
this.state.editingLinearElement,
|
||||||
|
this.state.showGrid,
|
||||||
this.state.gridSize,
|
this.state.gridSize,
|
||||||
);
|
);
|
||||||
if (editingLinearElement !== this.state.editingLinearElement) {
|
if (editingLinearElement !== this.state.editingLinearElement) {
|
||||||
@ -2278,7 +2289,12 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
|||||||
return {
|
return {
|
||||||
origin,
|
origin,
|
||||||
originInGrid: tupleToCoors(
|
originInGrid: tupleToCoors(
|
||||||
getGridPoint(origin.x, origin.y, this.state.gridSize),
|
getGridPoint(
|
||||||
|
origin.x,
|
||||||
|
origin.y,
|
||||||
|
this.state.showGrid,
|
||||||
|
this.state.gridSize,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
scrollbars: isOverScrollBars(
|
scrollbars: isOverScrollBars(
|
||||||
currentScrollBars,
|
currentScrollBars,
|
||||||
@ -2634,7 +2650,8 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
|||||||
const [gridX, gridY] = getGridPoint(
|
const [gridX, gridY] = getGridPoint(
|
||||||
pointerDownState.origin.x,
|
pointerDownState.origin.x,
|
||||||
pointerDownState.origin.y,
|
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.
|
/* If arrow is pre-arrowheads, it will have undefined for both start and end arrowheads.
|
||||||
@ -2696,6 +2713,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
|||||||
const [gridX, gridY] = getGridPoint(
|
const [gridX, gridY] = getGridPoint(
|
||||||
pointerDownState.origin.x,
|
pointerDownState.origin.x,
|
||||||
pointerDownState.origin.y,
|
pointerDownState.origin.y,
|
||||||
|
this.state.showGrid,
|
||||||
this.state.gridSize,
|
this.state.gridSize,
|
||||||
);
|
);
|
||||||
const element = newElement({
|
const element = newElement({
|
||||||
@ -2785,6 +2803,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
|||||||
const [gridX, gridY] = getGridPoint(
|
const [gridX, gridY] = getGridPoint(
|
||||||
pointerCoords.x,
|
pointerCoords.x,
|
||||||
pointerCoords.y,
|
pointerCoords.y,
|
||||||
|
this.state.showGrid,
|
||||||
this.state.gridSize,
|
this.state.gridSize,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -2857,6 +2876,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
|||||||
const [dragX, dragY] = getGridPoint(
|
const [dragX, dragY] = getGridPoint(
|
||||||
pointerCoords.x - pointerDownState.drag.offset.x,
|
pointerCoords.x - pointerDownState.drag.offset.x,
|
||||||
pointerCoords.y - pointerDownState.drag.offset.y,
|
pointerCoords.y - pointerDownState.drag.offset.y,
|
||||||
|
this.state.showGrid,
|
||||||
this.state.gridSize,
|
this.state.gridSize,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -2909,6 +2929,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
|||||||
const [originDragX, originDragY] = getGridPoint(
|
const [originDragX, originDragY] = getGridPoint(
|
||||||
pointerDownState.origin.x - pointerDownState.drag.offset.x,
|
pointerDownState.origin.x - pointerDownState.drag.offset.x,
|
||||||
pointerDownState.origin.y - pointerDownState.drag.offset.y,
|
pointerDownState.origin.y - pointerDownState.drag.offset.y,
|
||||||
|
this.state.showGrid,
|
||||||
this.state.gridSize,
|
this.state.gridSize,
|
||||||
);
|
);
|
||||||
mutateElement(duplicatedElement, {
|
mutateElement(duplicatedElement, {
|
||||||
@ -3565,6 +3586,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
|||||||
const [gridX, gridY] = getGridPoint(
|
const [gridX, gridY] = getGridPoint(
|
||||||
pointerCoords.x,
|
pointerCoords.x,
|
||||||
pointerCoords.y,
|
pointerCoords.y,
|
||||||
|
this.state.showGrid,
|
||||||
this.state.gridSize,
|
this.state.gridSize,
|
||||||
);
|
);
|
||||||
dragNewElement(
|
dragNewElement(
|
||||||
@ -3603,6 +3625,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
|||||||
const [resizeX, resizeY] = getGridPoint(
|
const [resizeX, resizeY] = getGridPoint(
|
||||||
pointerCoords.x - pointerDownState.resize.offset.x,
|
pointerCoords.x - pointerDownState.resize.offset.x,
|
||||||
pointerCoords.y - pointerDownState.resize.offset.y,
|
pointerCoords.y - pointerDownState.resize.offset.y,
|
||||||
|
this.state.showGrid,
|
||||||
this.state.gridSize,
|
this.state.gridSize,
|
||||||
);
|
);
|
||||||
if (
|
if (
|
||||||
|
@ -24,6 +24,7 @@ const getStorageSizes = debounce((cb: (sizes: StorageSizes) => void) => {
|
|||||||
}, 500);
|
}, 500);
|
||||||
|
|
||||||
export const Stats = (props: {
|
export const Stats = (props: {
|
||||||
|
setAppState: React.Component<any, AppState>["setState"];
|
||||||
appState: AppState;
|
appState: AppState;
|
||||||
elements: readonly NonDeletedExcalidrawElement[];
|
elements: readonly NonDeletedExcalidrawElement[];
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
@ -46,6 +47,12 @@ export const Stats = (props: {
|
|||||||
const selectedElements = getTargetElements(props.elements, props.appState);
|
const selectedElements = getTargetElements(props.elements, props.appState);
|
||||||
const selectedBoundingBox = getCommonBounds(selectedElements);
|
const selectedBoundingBox = getCommonBounds(selectedElements);
|
||||||
|
|
||||||
|
const onGridSizeChange = () => {
|
||||||
|
props.setAppState({
|
||||||
|
gridSize: ((props.appState.gridSize - 5) % 50) + 10,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
if (isMobile && props.appState.openMenu) {
|
if (isMobile && props.appState.openMenu) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -156,6 +163,17 @@ export const Stats = (props: {
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
)}
|
)}
|
||||||
|
{props.appState.showGrid && (
|
||||||
|
<>
|
||||||
|
<tr>
|
||||||
|
<th colSpan={2}>{"Misc"}</th>
|
||||||
|
</tr>
|
||||||
|
<tr onClick={onGridSizeChange} style={{ cursor: "pointer" }}>
|
||||||
|
<td>{"Grid size"}</td>
|
||||||
|
<td>{props.appState.gridSize}</td>
|
||||||
|
</tr>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</Island>
|
</Island>
|
||||||
|
@ -102,6 +102,7 @@ export class LinearElementEditor {
|
|||||||
element,
|
element,
|
||||||
scenePointerX - editingLinearElement.pointerOffset.x,
|
scenePointerX - editingLinearElement.pointerOffset.x,
|
||||||
scenePointerY - editingLinearElement.pointerOffset.y,
|
scenePointerY - editingLinearElement.pointerOffset.y,
|
||||||
|
appState.showGrid,
|
||||||
appState.gridSize,
|
appState.gridSize,
|
||||||
);
|
);
|
||||||
LinearElementEditor.movePoint(element, activePointIndex, newPoint);
|
LinearElementEditor.movePoint(element, activePointIndex, newPoint);
|
||||||
@ -198,6 +199,7 @@ export class LinearElementEditor {
|
|||||||
element,
|
element,
|
||||||
scenePointer.x,
|
scenePointer.x,
|
||||||
scenePointer.y,
|
scenePointer.y,
|
||||||
|
appState.showGrid,
|
||||||
appState.gridSize,
|
appState.gridSize,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -282,7 +284,8 @@ export class LinearElementEditor {
|
|||||||
scenePointerX: number,
|
scenePointerX: number,
|
||||||
scenePointerY: number,
|
scenePointerY: number,
|
||||||
editingLinearElement: LinearElementEditor,
|
editingLinearElement: LinearElementEditor,
|
||||||
gridSize: number | null,
|
isGridOn: boolean,
|
||||||
|
gridSize: number,
|
||||||
): LinearElementEditor {
|
): LinearElementEditor {
|
||||||
const { elementId, lastUncommittedPoint } = editingLinearElement;
|
const { elementId, lastUncommittedPoint } = editingLinearElement;
|
||||||
const element = LinearElementEditor.getElement(elementId);
|
const element = LinearElementEditor.getElement(elementId);
|
||||||
@ -304,6 +307,7 @@ export class LinearElementEditor {
|
|||||||
element,
|
element,
|
||||||
scenePointerX - editingLinearElement.pointerOffset.x,
|
scenePointerX - editingLinearElement.pointerOffset.x,
|
||||||
scenePointerY - editingLinearElement.pointerOffset.y,
|
scenePointerY - editingLinearElement.pointerOffset.y,
|
||||||
|
isGridOn,
|
||||||
gridSize,
|
gridSize,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -398,9 +402,15 @@ export class LinearElementEditor {
|
|||||||
element: NonDeleted<ExcalidrawLinearElement>,
|
element: NonDeleted<ExcalidrawLinearElement>,
|
||||||
scenePointerX: number,
|
scenePointerX: number,
|
||||||
scenePointerY: number,
|
scenePointerY: number,
|
||||||
gridSize: number | null,
|
isGridOn: boolean,
|
||||||
|
gridSize: number,
|
||||||
): Point {
|
): Point {
|
||||||
const pointerOnGrid = getGridPoint(scenePointerX, scenePointerY, gridSize);
|
const pointerOnGrid = getGridPoint(
|
||||||
|
scenePointerX,
|
||||||
|
scenePointerY,
|
||||||
|
isGridOn,
|
||||||
|
gridSize,
|
||||||
|
);
|
||||||
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
|
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
|
||||||
const cx = (x1 + x2) / 2;
|
const cx = (x1 + x2) / 2;
|
||||||
const cy = (y1 + y2) / 2;
|
const cy = (y1 + y2) / 2;
|
||||||
|
@ -249,9 +249,10 @@ const doSegmentsIntersect = (p1: Point, q1: Point, p2: Point, q2: Point) => {
|
|||||||
export const getGridPoint = (
|
export const getGridPoint = (
|
||||||
x: number,
|
x: number,
|
||||||
y: number,
|
y: number,
|
||||||
gridSize: number | null,
|
isGridOn: boolean,
|
||||||
|
gridSize: number,
|
||||||
): [number, number] => {
|
): [number, number] => {
|
||||||
if (gridSize) {
|
if (isGridOn) {
|
||||||
return [
|
return [
|
||||||
Math.round(x / gridSize) * gridSize,
|
Math.round(x / gridSize) * gridSize,
|
||||||
Math.round(y / gridSize) * gridSize,
|
Math.round(y / gridSize) * gridSize,
|
||||||
|
@ -74,7 +74,7 @@ const excalidrawDiagram = {
|
|||||||
],
|
],
|
||||||
appState: {
|
appState: {
|
||||||
viewBackgroundColor: "#ffffff",
|
viewBackgroundColor: "#ffffff",
|
||||||
gridSize: null,
|
gridSize: 20,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -233,7 +233,7 @@ export const renderScene = (
|
|||||||
context.scale(sceneState.zoom.value, sceneState.zoom.value);
|
context.scale(sceneState.zoom.value, sceneState.zoom.value);
|
||||||
|
|
||||||
// Grid
|
// Grid
|
||||||
if (renderGrid && appState.gridSize) {
|
if (renderGrid && appState.showGrid) {
|
||||||
strokeGrid(
|
strokeGrid(
|
||||||
context,
|
context,
|
||||||
appState.gridSize,
|
appState.gridSize,
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -84,7 +84,8 @@ export type AppState = {
|
|||||||
toastMessage: string | null;
|
toastMessage: string | null;
|
||||||
zenModeEnabled: boolean;
|
zenModeEnabled: boolean;
|
||||||
appearance: "light" | "dark";
|
appearance: "light" | "dark";
|
||||||
gridSize: number | null;
|
gridSize: number;
|
||||||
|
showGrid: boolean;
|
||||||
viewModeEnabled: boolean;
|
viewModeEnabled: boolean;
|
||||||
|
|
||||||
/** top-most selected groups (i.e. does not include nested groups) */
|
/** top-most selected groups (i.e. does not include nested groups) */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user