Moved drawing functions into the drawing helper

This commit is contained in:
Mitchell McCaffrey 2020-04-28 11:04:54 +10:00
parent 581ddf12aa
commit 734b966a53
2 changed files with 170 additions and 134 deletions

View File

@ -2,13 +2,13 @@ import React, { useRef, useEffect, useState } from "react";
import simplify from "simplify-js";
import shortid from "shortid";
import colors from "../../helpers/colors";
import {
getBrushPositionForTool,
getDefaultShapeData,
getUpdatedShapeData,
getStrokeSize,
shapeHasFill,
isShapeHovered,
drawShape,
} from "../../helpers/drawing";
function MapDrawing({
@ -174,107 +174,6 @@ function MapDrawing({
*/
const hoveredShapeRef = useRef(null);
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;
if (canvas) {
const context = canvas.getContext("2d");
@ -282,44 +181,20 @@ function MapDrawing({
context.clearRect(0, 0, width, height);
let hoveredShape = null;
for (let shape of shapes) {
const path = shapeToPath(shape);
// Detect hover
if (selectedTool === "erase") {
if (isPathHovered(path, shapeHasFill(shape), context)) {
if (isShapeHovered(shape, context, pointerPosition, width, height)) {
hoveredShape = shape;
}
}
drawPath(
path,
colors[shape.color],
shapeHasFill(shape),
shape.strokeWidth,
shape.blend,
context
);
drawShape(shape, context, gridSize, width, height);
}
if (drawingShape) {
const path = shapeToPath(drawingShape);
drawPath(
path,
colors[drawingShape.color],
shapeHasFill(drawingShape),
drawingShape.strokeWidth,
drawingShape.blend,
context
);
drawShape(drawingShape, context, gridSize, width, height);
}
if (hoveredShape) {
const path = shapeToPath(hoveredShape);
drawPath(
path,
"#BB99FF",
shapeHasFill(hoveredShape),
hoveredShape.strokeWidth,
true,
context
);
const shape = { ...hoveredShape, color: "#BB99FF", blend: true };
drawShape(shape, context, gridSize, width, height);
}
hoveredShapeRef.current = hoveredShape;
}

View File

@ -1,6 +1,7 @@
import { snapPositionToGrid } from "./shared";
import * as Vector2 from "./vector2";
import { toDegrees } from "./shared";
import colors from "./colors";
export function getBrushPositionForTool(
brushPosition,
@ -75,8 +76,11 @@ export function getUpdatedShapeData(type, data, brushPosition) {
}
const defaultStrokeSize = 1 / 10;
export function getStrokeSize(multiplier, gridSize, width, height) {
const gridPixelSize = Vector2.multiply(gridSize, { x: width, y: height });
export function getStrokeSize(multiplier, gridSize, canvasWidth, canvasHeight) {
const gridPixelSize = Vector2.multiply(gridSize, {
x: canvasWidth,
y: canvasHeight,
});
return Vector2.min(gridPixelSize) * defaultStrokeSize * multiplier;
}
@ -86,3 +90,160 @@ export function shapeHasFill(shape) {
(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);
}
}