Compare commits

...

9 Commits

Author SHA1 Message Date
Panayiotis Lipiridis
8802ea62ca Grid 2021-02-03 13:59:40 +02:00
Panayiotis Lipiridis
3c86b014de Merge 2021-02-03 13:54:48 +02:00
Panayiotis Lipiridis
c6f06dd1fc Merge 2021-01-11 12:23:43 +02:00
Panayiotis Lipiridis
922e28a198 Update the state properly 2020-12-24 23:15:15 +02:00
Panayiotis Lipiridis
49363afac1 Tests 2020-12-24 20:34:12 +02:00
Panayiotis Lipiridis
28a1b9a787 order 2020-12-24 17:55:44 +02:00
Panayiotis Lipiridis
9cfab40343 cleanup 2020-12-24 17:52:41 +02:00
Panayiotis Lipiridis
1d7c5705b2 More 2020-12-24 17:51:26 +02:00
Panayiotis Lipiridis
40cd4caeec feat: Change grid size 2020-12-24 16:45:42 +02:00
11 changed files with 210 additions and 88 deletions

View File

@ -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,

View File

@ -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,
}); });

View File

@ -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 },

View File

@ -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 (

View File

@ -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>

View File

@ -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;

View File

@ -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,

View File

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

View File

@ -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

View File

@ -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) */