Moved drawing functions into the drawing helper
This commit is contained in:
parent
581ddf12aa
commit
734b966a53
@ -2,13 +2,13 @@ import React, { useRef, useEffect, useState } from "react";
|
|||||||
import simplify from "simplify-js";
|
import simplify from "simplify-js";
|
||||||
import shortid from "shortid";
|
import shortid from "shortid";
|
||||||
|
|
||||||
import colors from "../../helpers/colors";
|
|
||||||
import {
|
import {
|
||||||
getBrushPositionForTool,
|
getBrushPositionForTool,
|
||||||
getDefaultShapeData,
|
getDefaultShapeData,
|
||||||
getUpdatedShapeData,
|
getUpdatedShapeData,
|
||||||
getStrokeSize,
|
getStrokeSize,
|
||||||
shapeHasFill,
|
isShapeHovered,
|
||||||
|
drawShape,
|
||||||
} from "../../helpers/drawing";
|
} from "../../helpers/drawing";
|
||||||
|
|
||||||
function MapDrawing({
|
function MapDrawing({
|
||||||
@ -174,107 +174,6 @@ function MapDrawing({
|
|||||||
*/
|
*/
|
||||||
const hoveredShapeRef = useRef(null);
|
const hoveredShapeRef = useRef(null);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
function pointsToPath(points, close) {
|
|
||||||
const path = new Path2D();
|
|
||||||
if (points.length < 2) {
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
path.moveTo(points[0].x * width, points[0].y * height);
|
|
||||||
|
|
||||||
// Draw a smooth curve between the points
|
|
||||||
for (let i = 1; i < points.length - 2; i++) {
|
|
||||||
var xc = (points[i].x * width + points[i + 1].x * width) / 2;
|
|
||||||
var yc = (points[i].y * height + points[i + 1].y * height) / 2;
|
|
||||||
path.quadraticCurveTo(
|
|
||||||
points[i].x * width,
|
|
||||||
points[i].y * height,
|
|
||||||
xc,
|
|
||||||
yc
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// Curve through the last two points
|
|
||||||
path.quadraticCurveTo(
|
|
||||||
points[points.length - 2].x * width,
|
|
||||||
points[points.length - 2].y * height,
|
|
||||||
points[points.length - 1].x * width,
|
|
||||||
points[points.length - 1].y * height
|
|
||||||
);
|
|
||||||
|
|
||||||
if (close) {
|
|
||||||
path.closePath();
|
|
||||||
}
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
function circleToPath(x, y, radius) {
|
|
||||||
const path = new Path2D();
|
|
||||||
const minSide = width < height ? width : height;
|
|
||||||
path.arc(x * width, y * height, radius * minSide, 0, 2 * Math.PI, true);
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
function rectangleToPath(x, y, w, h) {
|
|
||||||
const path = new Path2D();
|
|
||||||
path.rect(x * width, y * height, w * width, h * height);
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
function triangleToPath(points) {
|
|
||||||
const path = new Path2D();
|
|
||||||
path.moveTo(points[0].x * width, points[0].y * height);
|
|
||||||
for (let point of points.slice(1)) {
|
|
||||||
path.lineTo(point.x * width, point.y * height);
|
|
||||||
}
|
|
||||||
path.closePath();
|
|
||||||
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
function shapeToPath(shape) {
|
|
||||||
const data = shape.data;
|
|
||||||
if (shape.type === "path") {
|
|
||||||
return pointsToPath(data.points, shape.pathType === "fill");
|
|
||||||
} else if (shape.type === "shape") {
|
|
||||||
if (shape.shapeType === "circle") {
|
|
||||||
return circleToPath(data.x, data.y, data.radius);
|
|
||||||
} else if (shape.shapeType === "rectangle") {
|
|
||||||
return rectangleToPath(data.x, data.y, data.width, data.height);
|
|
||||||
} else if (shape.shapeType === "triangle") {
|
|
||||||
return triangleToPath(data.points);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function drawPath(path, color, fill, strokeWidth, blend, context) {
|
|
||||||
context.globalAlpha = blend ? 0.5 : 1.0;
|
|
||||||
context.fillStyle = color;
|
|
||||||
context.strokeStyle = color;
|
|
||||||
if (strokeWidth > 0) {
|
|
||||||
context.lineCap = "round";
|
|
||||||
context.lineWidth = getStrokeSize(strokeWidth, gridSize, width, height);
|
|
||||||
context.stroke(path);
|
|
||||||
}
|
|
||||||
if (fill) {
|
|
||||||
context.fill(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function isPathHovered(path, hasFill, context) {
|
|
||||||
if (hasFill) {
|
|
||||||
return context.isPointInPath(
|
|
||||||
path,
|
|
||||||
pointerPosition.x * width,
|
|
||||||
pointerPosition.y * height
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return context.isPointInStroke(
|
|
||||||
path,
|
|
||||||
pointerPosition.x * width,
|
|
||||||
pointerPosition.y * height
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const canvas = canvasRef.current;
|
const canvas = canvasRef.current;
|
||||||
if (canvas) {
|
if (canvas) {
|
||||||
const context = canvas.getContext("2d");
|
const context = canvas.getContext("2d");
|
||||||
@ -282,44 +181,20 @@ function MapDrawing({
|
|||||||
context.clearRect(0, 0, width, height);
|
context.clearRect(0, 0, width, height);
|
||||||
let hoveredShape = null;
|
let hoveredShape = null;
|
||||||
for (let shape of shapes) {
|
for (let shape of shapes) {
|
||||||
const path = shapeToPath(shape);
|
|
||||||
// Detect hover
|
// Detect hover
|
||||||
if (selectedTool === "erase") {
|
if (selectedTool === "erase") {
|
||||||
if (isPathHovered(path, shapeHasFill(shape), context)) {
|
if (isShapeHovered(shape, context, pointerPosition, width, height)) {
|
||||||
hoveredShape = shape;
|
hoveredShape = shape;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
drawShape(shape, context, gridSize, width, height);
|
||||||
drawPath(
|
|
||||||
path,
|
|
||||||
colors[shape.color],
|
|
||||||
shapeHasFill(shape),
|
|
||||||
shape.strokeWidth,
|
|
||||||
shape.blend,
|
|
||||||
context
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if (drawingShape) {
|
if (drawingShape) {
|
||||||
const path = shapeToPath(drawingShape);
|
drawShape(drawingShape, context, gridSize, width, height);
|
||||||
drawPath(
|
|
||||||
path,
|
|
||||||
colors[drawingShape.color],
|
|
||||||
shapeHasFill(drawingShape),
|
|
||||||
drawingShape.strokeWidth,
|
|
||||||
drawingShape.blend,
|
|
||||||
context
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if (hoveredShape) {
|
if (hoveredShape) {
|
||||||
const path = shapeToPath(hoveredShape);
|
const shape = { ...hoveredShape, color: "#BB99FF", blend: true };
|
||||||
drawPath(
|
drawShape(shape, context, gridSize, width, height);
|
||||||
path,
|
|
||||||
"#BB99FF",
|
|
||||||
shapeHasFill(hoveredShape),
|
|
||||||
hoveredShape.strokeWidth,
|
|
||||||
true,
|
|
||||||
context
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
hoveredShapeRef.current = hoveredShape;
|
hoveredShapeRef.current = hoveredShape;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { snapPositionToGrid } from "./shared";
|
import { snapPositionToGrid } from "./shared";
|
||||||
import * as Vector2 from "./vector2";
|
import * as Vector2 from "./vector2";
|
||||||
import { toDegrees } from "./shared";
|
import { toDegrees } from "./shared";
|
||||||
|
import colors from "./colors";
|
||||||
|
|
||||||
export function getBrushPositionForTool(
|
export function getBrushPositionForTool(
|
||||||
brushPosition,
|
brushPosition,
|
||||||
@ -75,8 +76,11 @@ export function getUpdatedShapeData(type, data, brushPosition) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const defaultStrokeSize = 1 / 10;
|
const defaultStrokeSize = 1 / 10;
|
||||||
export function getStrokeSize(multiplier, gridSize, width, height) {
|
export function getStrokeSize(multiplier, gridSize, canvasWidth, canvasHeight) {
|
||||||
const gridPixelSize = Vector2.multiply(gridSize, { x: width, y: height });
|
const gridPixelSize = Vector2.multiply(gridSize, {
|
||||||
|
x: canvasWidth,
|
||||||
|
y: canvasHeight,
|
||||||
|
});
|
||||||
return Vector2.min(gridPixelSize) * defaultStrokeSize * multiplier;
|
return Vector2.min(gridPixelSize) * defaultStrokeSize * multiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,3 +90,160 @@ export function shapeHasFill(shape) {
|
|||||||
(shape.type === "path" && shape.pathType === "fill")
|
(shape.type === "path" && shape.pathType === "fill")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function pointsToPath(points, close, canvasWidth, canvasHeight) {
|
||||||
|
const path = new Path2D();
|
||||||
|
if (points.length < 2) {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
path.moveTo(points[0].x * canvasWidth, points[0].y * canvasHeight);
|
||||||
|
|
||||||
|
// Draw a smooth curve between the points
|
||||||
|
for (let i = 1; i < points.length - 2; i++) {
|
||||||
|
const pointScaled = Vector2.multiply(points[i], {
|
||||||
|
x: canvasWidth,
|
||||||
|
y: canvasHeight,
|
||||||
|
});
|
||||||
|
const nextPointScaled = Vector2.multiply(points[i + 1], {
|
||||||
|
x: canvasWidth,
|
||||||
|
y: canvasHeight,
|
||||||
|
});
|
||||||
|
var xc = (pointScaled.x + nextPointScaled.x) / 2;
|
||||||
|
var yc = (pointScaled.y + nextPointScaled.y) / 2;
|
||||||
|
path.quadraticCurveTo(pointScaled.x, pointScaled.y, xc, yc);
|
||||||
|
}
|
||||||
|
// Curve through the last two points
|
||||||
|
path.quadraticCurveTo(
|
||||||
|
points[points.length - 2].x * canvasWidth,
|
||||||
|
points[points.length - 2].y * canvasHeight,
|
||||||
|
points[points.length - 1].x * canvasWidth,
|
||||||
|
points[points.length - 1].y * canvasHeight
|
||||||
|
);
|
||||||
|
|
||||||
|
if (close) {
|
||||||
|
path.closePath();
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function circleToPath(x, y, radius, canvasWidth, canvasHeight) {
|
||||||
|
const path = new Path2D();
|
||||||
|
const minSide = canvasWidth < canvasHeight ? canvasWidth : canvasHeight;
|
||||||
|
path.arc(
|
||||||
|
x * canvasWidth,
|
||||||
|
y * canvasHeight,
|
||||||
|
radius * minSide,
|
||||||
|
0,
|
||||||
|
2 * Math.PI,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function rectangleToPath(
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
canvasWidth,
|
||||||
|
canvasHeight
|
||||||
|
) {
|
||||||
|
const path = new Path2D();
|
||||||
|
path.rect(
|
||||||
|
x * canvasWidth,
|
||||||
|
y * canvasHeight,
|
||||||
|
width * canvasWidth,
|
||||||
|
height * canvasHeight
|
||||||
|
);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function triangleToPath(points, canvasWidth, canvasHeight) {
|
||||||
|
const path = new Path2D();
|
||||||
|
path.moveTo(points[0].x * canvasWidth, points[0].y * canvasHeight);
|
||||||
|
for (let point of points.slice(1)) {
|
||||||
|
path.lineTo(point.x * canvasWidth, point.y * canvasHeight);
|
||||||
|
}
|
||||||
|
path.closePath();
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function shapeToPath(shape, canvasWidth, canvasHeight) {
|
||||||
|
const data = shape.data;
|
||||||
|
if (shape.type === "path") {
|
||||||
|
return pointsToPath(
|
||||||
|
data.points,
|
||||||
|
shape.pathType === "fill",
|
||||||
|
canvasWidth,
|
||||||
|
canvasHeight
|
||||||
|
);
|
||||||
|
} else if (shape.type === "shape") {
|
||||||
|
if (shape.shapeType === "circle") {
|
||||||
|
return circleToPath(
|
||||||
|
data.x,
|
||||||
|
data.y,
|
||||||
|
data.radius,
|
||||||
|
canvasWidth,
|
||||||
|
canvasHeight
|
||||||
|
);
|
||||||
|
} else if ((shape.shapeType === "rectangle", canvasWidth, canvasHeight)) {
|
||||||
|
return rectangleToPath(
|
||||||
|
data.x,
|
||||||
|
data.y,
|
||||||
|
data.width,
|
||||||
|
data.height,
|
||||||
|
canvasWidth,
|
||||||
|
canvasHeight
|
||||||
|
);
|
||||||
|
} else if (shape.shapeType === "triangle") {
|
||||||
|
return triangleToPath(data.points, canvasWidth, canvasHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isShapeHovered(
|
||||||
|
shape,
|
||||||
|
context,
|
||||||
|
hoverPosition,
|
||||||
|
canvasWidth,
|
||||||
|
canvasHeight
|
||||||
|
) {
|
||||||
|
const path = shapeToPath(shape, canvasWidth, canvasHeight);
|
||||||
|
if (shapeHasFill(shape)) {
|
||||||
|
return context.isPointInPath(
|
||||||
|
path,
|
||||||
|
hoverPosition.x * canvasWidth,
|
||||||
|
hoverPosition.y * canvasHeight
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return context.isPointInStroke(
|
||||||
|
path,
|
||||||
|
hoverPosition.x * canvasWidth,
|
||||||
|
hoverPosition.y * canvasHeight
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function drawShape(shape, context, gridSize, canvasWidth, canvasHeight) {
|
||||||
|
const path = shapeToPath(shape, canvasWidth, canvasHeight);
|
||||||
|
const color = colors[shape.color] || shape.color;
|
||||||
|
const fill = shapeHasFill(shape);
|
||||||
|
|
||||||
|
context.globalAlpha = shape.blend ? 0.5 : 1.0;
|
||||||
|
context.fillStyle = color;
|
||||||
|
context.strokeStyle = color;
|
||||||
|
if (shape.strokeWidth > 0) {
|
||||||
|
context.lineCap = "round";
|
||||||
|
context.lineWidth = getStrokeSize(
|
||||||
|
shape.strokeWidth,
|
||||||
|
gridSize,
|
||||||
|
canvasWidth,
|
||||||
|
canvasHeight
|
||||||
|
);
|
||||||
|
context.stroke(path);
|
||||||
|
}
|
||||||
|
if (fill) {
|
||||||
|
context.fill(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user