Skip to content

Commit

Permalink
more progress
Browse files Browse the repository at this point in the history
  • Loading branch information
sandstone991 committed Sep 9, 2023
1 parent cd449ae commit 8784aac
Show file tree
Hide file tree
Showing 9 changed files with 111 additions and 37 deletions.
4 changes: 2 additions & 2 deletions src/actions/createText.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Command, UndoableCommand } from "./types";
import { useStore } from "@/store";
import { CursorFn, ZagyCanvasElement } from "@/types/general";
import { Point, normalizePos } from "@/utils";
import { generateTextElement } from "@/utils/canvas/generateElement";
import { Text } from "@/utils/canvas/shapes";

class TextAction {
private static lastMouseDownPosition: Point = [0, 0];
Expand Down Expand Up @@ -73,7 +73,7 @@ class TextAction {
if (ctx === null) return;
const { currentText, position } = useStore.getState();
const normalizedPosition = normalizePos(position, this.lastMouseDownPosition);
element = generateTextElement(currentText, normalizedPosition, {});
element = new Text({ point1: normalizedPosition, text: currentText });

Check failure on line 76 in src/actions/createText.ts

View workflow job for this annotation

GitHub Actions / Deploy-Preview

Type 'Text' is missing the following properties from type 'ZagyCanvasElement': x, y, endX, endY

const { setCurrentText, setIsWriting } = useStore.getState();
this.isAlreadyElement = false;
Expand Down
16 changes: 2 additions & 14 deletions src/actions/draw.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,9 @@
import { RoughGenerator } from "roughjs/bin/generator";
import { randomSeed } from "roughjs/bin/math";
import { UndoableCommand } from "./types";
import {
generateCacheLineElement,
generateCacheRectElement,
generateCachedHandDrawnElement,
generateHandDrawnElement,
generateLineElement,
generateRectElement,
} from "@/utils/canvas/generateElement";

import { useStore } from "@/store";
import {
CursorFn,
ZagyCanvasElement,
ZagyCanvasLineElement,
ZagyCanvasRectElement,
} from "@/types/general";
import { CursorFn, ZagyCanvasElement } from "@/types/general";
import { Point, normalizeToGrid } from "@/utils";
import { HandDrawn, Line, Rectangle } from "@/utils/canvas/shapes";

Expand Down
1 change: 0 additions & 1 deletion src/actions/moveElement.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Command, UndoableCommand } from "./types";
import { constructHandDrawnElementPath2D } from "@/utils/canvas/generateElement";
import { useStore } from "@/store";
import { CursorFn, ZagyCanvasElement, isHanddrawn, isLine } from "@/types/general";
import { Point, getHitElement, normalizeToGrid } from "@/utils";
Expand Down
4 changes: 1 addition & 3 deletions src/components/ZagyDraw.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,7 @@ function ZagyDraw() {
return;
}
setZoomLevel(clampedZoom);
setElements((elements) =>
elements.map((e) => regenerateCacheElement(e, clampedZoom, roughGenerator)),
);
setElements((elements) => elements.map((e) => regenerateCacheElement(e, clampedZoom)));
};
const canvas = useRef<HTMLCanvasElement>(null);
const roughCanvas = useRef<RoughCanvas | null>(null);
Expand Down
5 changes: 5 additions & 0 deletions src/types/general.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ interface TextOptions extends SharedOptions {
font: FontTypeOptions;
fontSize: FontSize;
}
interface TextRequiredOptions {
text: string;
point1: Point;
}

type HandDrawnOptions = SharedOptions;
type HandDrawnRequiredOptions = {
Expand Down Expand Up @@ -203,5 +207,6 @@ export type {
RectRequiredOptions,
LineRequiredOptions,
HandDrawnRequiredOptions,
TextRequiredOptions,
};
export { CursorFn, FontTypeOptions, isLine, isRect, isText, isHanddrawn, isImage, isZagyPortable };
23 changes: 6 additions & 17 deletions src/utils/canvas/generateElement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { nanoid } from "nanoid";

import { randomSeed } from "roughjs/bin/math";
import { RoughGenerator } from "roughjs/bin/generator";
import Shape from "./shapes/shape";
import {
ZagyCanvasLineElement,
ZagyCanvasRectElement,
Expand Down Expand Up @@ -435,23 +436,11 @@ const generateCachedHandDrawnElement = (
};
};

const regenerateCacheElement = (
el: ZagyCanvasElement,
newZoom: number,
generator: RoughGenerator,
): ZagyCanvasElement => {
if (isRect(el)) {
return generateCacheRectElement(
generator,
[el.x, el.y],
[el.endX, el.endY],
newZoom,
el.options,
);
} else if (isLine(el)) {
return generateCacheLineElement(generator, el.point1, el.point2, newZoom, el.options);
} else if (isHanddrawn(el)) {
return generateCachedHandDrawnElement(el.paths, newZoom, el.options);
const regenerateCacheElement = (el: ZagyCanvasElement, newZoom: number): ZagyCanvasElement => {
if (el instanceof Shape) {
return el.regenerate({
zoom: newZoom,
});
} else {
return el;
}
Expand Down
Empty file.
1 change: 1 addition & 0 deletions src/utils/canvas/shapes/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { Rectangle } from "./rectangle";
export { Line } from "./line";
export { HandDrawn } from "./handdrawn";
export { Text } from "./text";
94 changes: 94 additions & 0 deletions src/utils/canvas/shapes/text.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { nanoid } from "nanoid";
import Shape from "./shape";
import { Point, getCorrectCoordOrder } from "@/utils";
import { FontTypeOptions, TextOptions, TextRequiredOptions } from "@/types/general";
import { useStore } from "@/store";
const { getElementConfigState: getConfigState } = useStore.getState();
export class Text extends Shape<TextOptions & TextRequiredOptions> {
// todo add a cache canvas for text
protected options!: TextOptions & TextRequiredOptions;
protected text!: string[];
protected boundingRect!: [Point, Point];
constructor(options: Partial<TextOptions> & TextRequiredOptions) {
super(nanoid(), "rectangle");
this.generate(options);
}
public generate(options: Partial<TextOptions> & TextRequiredOptions) {
const normalizedOptions = this.normalizeOptions(options);
const tempCanvas = document.createElement("canvas");
const ctx = tempCanvas.getContext("2d");
if (!ctx) throw new Error("GENERATE TEXT: must have ctx to be able to create new text");
const lines = options.text.split("\n");
// text element width is the largest line width
let largestLineIndex = 0;
let tempLen = lines[0].length;
lines.forEach((val, i) => {
if (val.length > tempLen) {
tempLen = val.length;
largestLineIndex = i;
}
});
ctx.save();
ctx.font = `${normalizedOptions.fontSize}px ` + FontTypeOptions[normalizedOptions.font];
const width = ctx.measureText(lines[largestLineIndex]).width;
ctx.restore();
// note using font-size as line height
// calc height = number of lines * lineHeight
const height = lines.length * normalizedOptions.fontSize;
const text = lines;
const endPos = [options.point1[0] + width, options.point1[1] + height];
const { x, y, endX, endY } = getCorrectCoordOrder(options.point1, endPos as Point);
this.boundingRect = [
[x, y],
[endX, endY],
];
this.text = text;
this.options = normalizedOptions;
return this;
}
public regenerate(options: Partial<TextOptions & TextRequiredOptions>) {
return this.generate({
...this.options,
...options,
});
}
private normalizeOptions(
options: Partial<TextOptions> & TextRequiredOptions,
): TextOptions & TextRequiredOptions {
const globalConfig = getConfigState();
const zoom = useStore.getState().zoomLevel;
return {
...options,
opacity: options.opacity || globalConfig.opacity,
stroke: options.stroke || globalConfig.stroke,
strokeWidth: options.strokeWidth || globalConfig.strokeWidth,
font: options.font || globalConfig.font,
fontSize: options.fontSize || globalConfig.fontSize,
zoom: options.zoom || zoom,
};
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public render(ctx: CanvasRenderingContext2D, zoom: number): void {
ctx.save();
ctx.font = `${this.options.fontSize}px ` + FontTypeOptions[this.options.font];
ctx.fillStyle = this.options.stroke;
ctx.textBaseline = "top";
this.text.forEach((val, i) =>
ctx.fillText(
val,
this.boundingRect[0][0],
this.boundingRect[0][1] + i * this.options.fontSize,
),
);
ctx.restore();
}
public copy() {
return { ...this.options, shape: this.shape };
}
public move(walkX: number, walkY: number) {
const newStart = [this.options.point1[0] + walkX, this.options.point1[1] + walkY] as Point;
return this.regenerate({
point1: newStart,
});
}
}

0 comments on commit 8784aac

Please sign in to comment.