Added back map drawing
This commit is contained in:
parent
9e01ad1d0e
commit
d26932d17c
@ -1,14 +1,17 @@
|
||||
import React, { useState, useContext } from "react";
|
||||
import React, { useState, useContext, useEffect } from "react";
|
||||
|
||||
import MapControls from "./MapControls";
|
||||
|
||||
import MapInteraction from "./MapInteraction";
|
||||
import MapToken from "./MapToken";
|
||||
import MapDrawing from "./MapDrawing";
|
||||
|
||||
import TokenDataContext from "../../contexts/TokenDataContext";
|
||||
import TokenMenu from "../token/TokenMenu";
|
||||
import TokenDragOverlay from "../token/TokenDragOverlay";
|
||||
|
||||
import { omit } from "../../helpers/shared";
|
||||
|
||||
function Map({
|
||||
map,
|
||||
mapState,
|
||||
@ -84,6 +87,43 @@ function Map({
|
||||
const [mapShapes, setMapShapes] = useState([]);
|
||||
const [fogShapes, setFogShapes] = useState([]);
|
||||
|
||||
// Replay the draw actions and convert them to shapes for the map drawing
|
||||
useEffect(() => {
|
||||
if (!mapState) {
|
||||
return;
|
||||
}
|
||||
function actionsToShapes(actions, actionIndex) {
|
||||
let shapesById = {};
|
||||
for (let i = 0; i <= actionIndex; i++) {
|
||||
const action = actions[i];
|
||||
if (action.type === "add" || action.type === "edit") {
|
||||
for (let shape of action.shapes) {
|
||||
shapesById[shape.id] = shape;
|
||||
}
|
||||
}
|
||||
if (action.type === "remove") {
|
||||
shapesById = omit(shapesById, action.shapeIds);
|
||||
}
|
||||
}
|
||||
return Object.values(shapesById);
|
||||
}
|
||||
|
||||
setMapShapes(
|
||||
actionsToShapes(mapState.mapDrawActions, mapState.mapDrawActionIndex)
|
||||
);
|
||||
setFogShapes(
|
||||
actionsToShapes(mapState.fogDrawActions, mapState.fogDrawActionIndex)
|
||||
);
|
||||
}, [mapState]);
|
||||
|
||||
function handleMapShapeAdd(shape) {
|
||||
onMapDraw({ type: "add", shapes: [shape] });
|
||||
}
|
||||
|
||||
function handleMapShapeRemove(shapeId) {
|
||||
onMapDraw({ type: "remove", shapeIds: [shapeId] });
|
||||
}
|
||||
|
||||
const disabledControls = [];
|
||||
if (!allowMapDrawing) {
|
||||
disabledControls.push("brush");
|
||||
@ -182,6 +222,17 @@ function Map({
|
||||
/>
|
||||
);
|
||||
|
||||
const mapDrawing = (
|
||||
<MapDrawing
|
||||
shapes={mapShapes}
|
||||
onShapeAdd={handleMapShapeAdd}
|
||||
onShapeRemove={handleMapShapeRemove}
|
||||
selectedToolId={selectedToolId}
|
||||
selectedToolSettings={toolSettings[selectedToolId]}
|
||||
gridSize={gridSizeNormalized}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<MapInteraction
|
||||
map={map}
|
||||
@ -192,7 +243,9 @@ function Map({
|
||||
{tokenDragOverlay}
|
||||
</>
|
||||
}
|
||||
selectedToolId={selectedToolId}
|
||||
>
|
||||
{mapDrawing}
|
||||
{mapTokens}
|
||||
</MapInteraction>
|
||||
);
|
||||
|
@ -1,123 +1,89 @@
|
||||
import React, { useRef, useEffect, useState, useContext } from "react";
|
||||
import React, { useContext, useEffect, useState } from "react";
|
||||
import shortid from "shortid";
|
||||
import { Group, Line, Rect, Circle } from "react-konva";
|
||||
|
||||
import MapInteractionContext from "../../contexts/MapInteractionContext";
|
||||
|
||||
import { compare as comparePoints } from "../../helpers/vector2";
|
||||
import {
|
||||
getBrushPositionForTool,
|
||||
getDefaultShapeData,
|
||||
getUpdatedShapeData,
|
||||
isShapeHovered,
|
||||
drawShape,
|
||||
simplifyPoints,
|
||||
getRelativePointerPosition,
|
||||
getStrokeWidth,
|
||||
} from "../../helpers/drawing";
|
||||
|
||||
import MapInteractionContext from "../../contexts/MapInteractionContext";
|
||||
import colors from "../../helpers/colors";
|
||||
|
||||
function MapDrawing({
|
||||
width,
|
||||
height,
|
||||
selectedTool,
|
||||
toolSettings,
|
||||
shapes,
|
||||
onShapeAdd,
|
||||
onShapeRemove,
|
||||
selectedToolId,
|
||||
selectedToolSettings,
|
||||
gridSize,
|
||||
}) {
|
||||
const canvasRef = useRef();
|
||||
const containerRef = useRef();
|
||||
|
||||
const [isPointerDown, setIsPointerDown] = useState(false);
|
||||
const {
|
||||
stageDragState,
|
||||
mapDragPosition,
|
||||
stageScale,
|
||||
mapWidth,
|
||||
mapHeight,
|
||||
} = useContext(MapInteractionContext);
|
||||
const [drawingShape, setDrawingShape] = useState(null);
|
||||
const [pointerPosition, setPointerPosition] = useState({ x: -1, y: -1 });
|
||||
|
||||
const shouldHover = selectedTool === "erase";
|
||||
const shouldHover = selectedToolId === "erase";
|
||||
const isEditing =
|
||||
selectedTool === "brush" ||
|
||||
selectedTool === "shape" ||
|
||||
selectedTool === "erase";
|
||||
selectedToolId === "brush" ||
|
||||
selectedToolId === "shape" ||
|
||||
selectedToolId === "erase";
|
||||
|
||||
const { scaleRef } = useContext(MapInteractionContext);
|
||||
|
||||
// Reset pointer position when tool changes
|
||||
useEffect(() => {
|
||||
setPointerPosition({ x: -1, y: -1 });
|
||||
}, [selectedTool]);
|
||||
|
||||
function handleStart(event) {
|
||||
if (!isEditing) {
|
||||
return;
|
||||
}
|
||||
if (event.touches && event.touches.length !== 1) {
|
||||
setIsPointerDown(false);
|
||||
setDrawingShape(null);
|
||||
return;
|
||||
}
|
||||
const pointer = event.touches ? event.touches[0] : event;
|
||||
const position = getRelativePointerPosition(pointer, containerRef.current);
|
||||
setPointerPosition(position);
|
||||
setIsPointerDown(true);
|
||||
const brushPosition = getBrushPositionForTool(
|
||||
position,
|
||||
selectedTool,
|
||||
toolSettings,
|
||||
gridSize,
|
||||
shapes
|
||||
);
|
||||
const commonShapeData = {
|
||||
color: toolSettings && toolSettings.color,
|
||||
blend: toolSettings && toolSettings.useBlending,
|
||||
id: shortid.generate(),
|
||||
};
|
||||
if (selectedTool === "brush") {
|
||||
setDrawingShape({
|
||||
type: "path",
|
||||
pathType: toolSettings.type,
|
||||
data: { points: [brushPosition] },
|
||||
strokeWidth: toolSettings.type === "stroke" ? 1 : 0,
|
||||
...commonShapeData,
|
||||
});
|
||||
} else if (selectedTool === "shape") {
|
||||
setDrawingShape({
|
||||
type: "shape",
|
||||
shapeType: toolSettings.type,
|
||||
data: getDefaultShapeData(toolSettings.type, brushPosition),
|
||||
strokeWidth: 0,
|
||||
...commonShapeData,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function handleMove(event) {
|
||||
if (!isEditing) {
|
||||
return;
|
||||
}
|
||||
if (event.touches && event.touches.length !== 1) {
|
||||
return;
|
||||
}
|
||||
const pointer = event.touches ? event.touches[0] : event;
|
||||
// Set pointer position every frame for erase tool and fog
|
||||
if (shouldHover) {
|
||||
const position = getRelativePointerPosition(
|
||||
pointer,
|
||||
containerRef.current
|
||||
);
|
||||
setPointerPosition(position);
|
||||
}
|
||||
if (isPointerDown) {
|
||||
const position = getRelativePointerPosition(
|
||||
pointer,
|
||||
containerRef.current
|
||||
);
|
||||
setPointerPosition(position);
|
||||
function startShape() {
|
||||
const brushPosition = getBrushPositionForTool(
|
||||
position,
|
||||
selectedTool,
|
||||
toolSettings,
|
||||
mapDragPosition,
|
||||
selectedToolId,
|
||||
selectedToolSettings,
|
||||
gridSize,
|
||||
shapes
|
||||
);
|
||||
if (selectedTool === "brush") {
|
||||
const commonShapeData = {
|
||||
color: selectedToolSettings && selectedToolSettings.color,
|
||||
blend: selectedToolSettings && selectedToolSettings.useBlending,
|
||||
id: shortid.generate(),
|
||||
};
|
||||
if (selectedToolId === "brush") {
|
||||
setDrawingShape({
|
||||
type: "path",
|
||||
pathType: selectedToolSettings.type,
|
||||
data: { points: [brushPosition] },
|
||||
strokeWidth: selectedToolSettings.type === "stroke" ? 1 : 0,
|
||||
...commonShapeData,
|
||||
});
|
||||
} else if (selectedToolId === "shape") {
|
||||
setDrawingShape({
|
||||
type: "shape",
|
||||
shapeType: selectedToolSettings.type,
|
||||
data: getDefaultShapeData(selectedToolSettings.type, brushPosition),
|
||||
strokeWidth: 0,
|
||||
...commonShapeData,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function continueShape() {
|
||||
const brushPosition = getBrushPositionForTool(
|
||||
mapDragPosition,
|
||||
selectedToolId,
|
||||
selectedToolSettings,
|
||||
gridSize,
|
||||
shapes
|
||||
);
|
||||
if (selectedToolId === "brush") {
|
||||
setDrawingShape((prevShape) => {
|
||||
const prevPoints = prevShape.data.points;
|
||||
if (
|
||||
@ -132,14 +98,14 @@ function MapDrawing({
|
||||
const simplified = simplifyPoints(
|
||||
[...prevPoints, brushPosition],
|
||||
gridSize,
|
||||
scaleRef.current
|
||||
stageScale
|
||||
);
|
||||
return {
|
||||
...prevShape,
|
||||
data: { points: simplified },
|
||||
};
|
||||
});
|
||||
} else if (selectedTool === "shape") {
|
||||
} else if (selectedToolId === "shape") {
|
||||
setDrawingShape((prevShape) => ({
|
||||
...prevShape,
|
||||
data: getUpdatedShapeData(
|
||||
@ -151,110 +117,145 @@ function MapDrawing({
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleStop(event) {
|
||||
if (!isEditing) {
|
||||
return;
|
||||
}
|
||||
if (event.touches && event.touches.length !== 0) {
|
||||
return;
|
||||
}
|
||||
if (selectedTool === "brush" && drawingShape) {
|
||||
if (drawingShape.data.points.length > 1) {
|
||||
function endShape() {
|
||||
if (selectedToolId === "brush" && drawingShape) {
|
||||
if (drawingShape.data.points.length > 1) {
|
||||
onShapeAdd(drawingShape);
|
||||
}
|
||||
} else if (selectedToolId === "shape" && drawingShape) {
|
||||
onShapeAdd(drawingShape);
|
||||
}
|
||||
} else if (selectedTool === "shape" && drawingShape) {
|
||||
onShapeAdd(drawingShape);
|
||||
setDrawingShape(null);
|
||||
}
|
||||
|
||||
if (selectedTool === "erase" && hoveredShapeRef.current && isPointerDown) {
|
||||
onShapeRemove(hoveredShapeRef.current.id);
|
||||
}
|
||||
setIsPointerDown(false);
|
||||
setDrawingShape(null);
|
||||
}
|
||||
|
||||
// Add listeners for draw events on map to allow drawing past the bounds
|
||||
// of the container
|
||||
useEffect(() => {
|
||||
const map = document.querySelector(".map");
|
||||
map.addEventListener("mousedown", handleStart);
|
||||
map.addEventListener("mousemove", handleMove);
|
||||
map.addEventListener("mouseup", handleStop);
|
||||
map.addEventListener("touchstart", handleStart);
|
||||
map.addEventListener("touchmove", handleMove);
|
||||
map.addEventListener("touchend", handleStop);
|
||||
|
||||
return () => {
|
||||
map.removeEventListener("mousedown", handleStart);
|
||||
map.removeEventListener("mousemove", handleMove);
|
||||
map.removeEventListener("mouseup", handleStop);
|
||||
map.removeEventListener("touchstart", handleStart);
|
||||
map.removeEventListener("touchmove", handleMove);
|
||||
map.removeEventListener("touchend", handleStop);
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* Rendering
|
||||
*/
|
||||
const hoveredShapeRef = useRef(null);
|
||||
useEffect(() => {
|
||||
const canvas = canvasRef.current;
|
||||
if (canvas) {
|
||||
const context = canvas.getContext("2d");
|
||||
|
||||
context.clearRect(0, 0, width, height);
|
||||
let hoveredShape = null;
|
||||
for (let shape of shapes) {
|
||||
if (shouldHover) {
|
||||
if (isShapeHovered(shape, context, pointerPosition, width, height)) {
|
||||
hoveredShape = shape;
|
||||
}
|
||||
}
|
||||
drawShape(shape, context, gridSize, width, height);
|
||||
}
|
||||
if (drawingShape) {
|
||||
drawShape(drawingShape, context, gridSize, width, height);
|
||||
}
|
||||
if (hoveredShape) {
|
||||
const shape = { ...hoveredShape, color: "#BB99FF", blend: true };
|
||||
drawShape(shape, context, gridSize, width, height);
|
||||
}
|
||||
hoveredShapeRef.current = hoveredShape;
|
||||
switch (stageDragState) {
|
||||
case "first":
|
||||
startShape();
|
||||
return;
|
||||
case "dragging":
|
||||
continueShape();
|
||||
return;
|
||||
case "last":
|
||||
endShape();
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}, [
|
||||
shapes,
|
||||
width,
|
||||
height,
|
||||
pointerPosition,
|
||||
isPointerDown,
|
||||
selectedTool,
|
||||
drawingShape,
|
||||
stageDragState,
|
||||
mapDragPosition,
|
||||
selectedToolId,
|
||||
selectedToolSettings,
|
||||
isEditing,
|
||||
gridSize,
|
||||
shouldHover,
|
||||
stageScale,
|
||||
onShapeAdd,
|
||||
shapes,
|
||||
drawingShape,
|
||||
]);
|
||||
|
||||
function handleShapeClick(_, shape) {
|
||||
if (selectedToolId === "erase") {
|
||||
onShapeRemove(shape.id);
|
||||
}
|
||||
}
|
||||
|
||||
function handleShapeMouseOver(event, shape) {
|
||||
if (shouldHover) {
|
||||
const path = event.target;
|
||||
const hoverColor = "#BB99FF";
|
||||
path.fill(hoverColor);
|
||||
if (shape.type === "path") {
|
||||
path.stroke(hoverColor);
|
||||
}
|
||||
path.getLayer().draw();
|
||||
}
|
||||
}
|
||||
|
||||
function handleShapeMouseOut(event, shape) {
|
||||
if (shouldHover) {
|
||||
const path = event.target;
|
||||
const color = colors[shape.color] || shape.color;
|
||||
path.fill(color);
|
||||
if (shape.type === "path") {
|
||||
path.stroke(color);
|
||||
}
|
||||
path.getLayer().draw();
|
||||
}
|
||||
}
|
||||
|
||||
function renderShape(shape) {
|
||||
const defaultProps = {
|
||||
key: shape.id,
|
||||
onMouseOver: (e) => handleShapeMouseOver(e, shape),
|
||||
onMouseOut: (e) => handleShapeMouseOut(e, shape),
|
||||
onClick: (e) => handleShapeClick(e, shape),
|
||||
fill: colors[shape.color] || shape.color,
|
||||
opacity: shape.blend ? 0.5 : 1,
|
||||
};
|
||||
if (shape.type === "path") {
|
||||
return (
|
||||
<Line
|
||||
points={shape.data.points.reduce(
|
||||
(acc, point) => [...acc, point.x * mapWidth, point.y * mapHeight],
|
||||
[]
|
||||
)}
|
||||
stroke={colors[shape.color] || shape.color}
|
||||
tension={0.5}
|
||||
closed={shape.pathType === "fill"}
|
||||
fillEnabled={shape.pathType === "fill"}
|
||||
lineCap="round"
|
||||
strokeWidth={getStrokeWidth(
|
||||
shape.strokeWidth,
|
||||
gridSize,
|
||||
mapWidth,
|
||||
mapHeight
|
||||
)}
|
||||
{...defaultProps}
|
||||
/>
|
||||
);
|
||||
} else if (shape.type === "shape") {
|
||||
if (shape.shapeType === "rectangle") {
|
||||
return (
|
||||
<Rect
|
||||
x={shape.data.x * mapWidth}
|
||||
y={shape.data.y * mapHeight}
|
||||
width={shape.data.width * mapWidth}
|
||||
height={shape.data.height * mapHeight}
|
||||
{...defaultProps}
|
||||
/>
|
||||
);
|
||||
} else if (shape.shapeType === "circle") {
|
||||
const minSide = mapWidth < mapHeight ? mapWidth : mapHeight;
|
||||
return (
|
||||
<Circle
|
||||
x={shape.data.x * mapWidth}
|
||||
y={shape.data.y * mapHeight}
|
||||
radius={shape.data.radius * minSide}
|
||||
{...defaultProps}
|
||||
/>
|
||||
);
|
||||
} else if (shape.shapeType === "triangle") {
|
||||
return (
|
||||
<Line
|
||||
points={shape.data.points.reduce(
|
||||
(acc, point) => [...acc, point.x * mapWidth, point.y * mapHeight],
|
||||
[]
|
||||
)}
|
||||
closed={true}
|
||||
{...defaultProps}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
pointerEvents: "none",
|
||||
}}
|
||||
ref={containerRef}
|
||||
>
|
||||
<canvas
|
||||
ref={canvasRef}
|
||||
width={width}
|
||||
height={height}
|
||||
style={{ width: "100%", height: "100%" }}
|
||||
/>
|
||||
</div>
|
||||
<Group>
|
||||
{shapes.map(renderShape)}
|
||||
{drawingShape && renderShape(drawingShape)}
|
||||
</Group>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ const zoomSpeed = -0.001;
|
||||
const minZoom = 0.1;
|
||||
const maxZoom = 5;
|
||||
|
||||
function MapInteraction({ map, children, controls }) {
|
||||
function MapInteraction({ map, children, controls, selectedToolId }) {
|
||||
const mapSource = useDataSource(map, defaultMapSources);
|
||||
const [mapSourceImage] = useImage(mapSource);
|
||||
|
||||
@ -26,7 +26,10 @@ function MapInteraction({ map, children, controls }) {
|
||||
const [stageHeight, setStageHeight] = useState(1);
|
||||
const [stageScale, setStageScale] = useState(1);
|
||||
const [stageTranslate, setStageTranslate] = useState({ x: 0, y: 0 });
|
||||
// "none" | "first" | "dragging" | "last"
|
||||
const [stageDragState, setStageDragState] = useState("none");
|
||||
const [preventMapInteraction, setPreventMapInteraction] = useState(false);
|
||||
const [mapDragPosition, setMapDragPosition] = useState({ x: 0, y: 0 });
|
||||
|
||||
const stageWidthRef = useRef(stageWidth);
|
||||
const stageHeightRef = useRef(stageHeight);
|
||||
@ -40,6 +43,25 @@ function MapInteraction({ map, children, controls }) {
|
||||
}
|
||||
}, [map]);
|
||||
|
||||
// Convert a client space XY to be normalized to the map image
|
||||
function getMapDragPosition(xy) {
|
||||
const [x, y] = xy;
|
||||
const container = containerRef.current;
|
||||
const mapImage = mapImageRef.current;
|
||||
if (container && mapImage) {
|
||||
const containerRect = container.getBoundingClientRect();
|
||||
const mapRect = mapImage.getClientRect();
|
||||
|
||||
const offsetX = x - containerRect.left - mapRect.x;
|
||||
const offsetY = y - containerRect.top - mapRect.y;
|
||||
|
||||
const normalizedX = offsetX / mapRect.width;
|
||||
const normalizedY = offsetY / mapRect.height;
|
||||
|
||||
return { x: normalizedX, y: normalizedY };
|
||||
}
|
||||
}
|
||||
|
||||
const bind = useGesture({
|
||||
onWheel: ({ delta }) => {
|
||||
const newScale = Math.min(
|
||||
@ -49,16 +71,25 @@ function MapInteraction({ map, children, controls }) {
|
||||
setStageScale(newScale);
|
||||
stageScaleRef.current = newScale;
|
||||
},
|
||||
onDrag: ({ delta }) => {
|
||||
if (!preventMapInteraction) {
|
||||
onDrag: ({ delta, xy, first, last }) => {
|
||||
if (preventMapInteraction) {
|
||||
return;
|
||||
}
|
||||
setMapDragPosition(getMapDragPosition(xy));
|
||||
setStageDragState(first ? "first" : last ? "last" : "dragging");
|
||||
const [dx, dy] = delta;
|
||||
if (selectedToolId === "pan") {
|
||||
const newTranslate = {
|
||||
x: stageTranslate.x + delta[0] / stageScale,
|
||||
y: stageTranslate.y + delta[1] / stageScale,
|
||||
x: stageTranslate.x + dx / stageScale,
|
||||
y: stageTranslate.y + dy / stageScale,
|
||||
};
|
||||
setStageTranslate(newTranslate);
|
||||
stageTranslateRef.current = newTranslate;
|
||||
}
|
||||
},
|
||||
onDragEnd: () => {
|
||||
setStageDragState("none");
|
||||
},
|
||||
});
|
||||
|
||||
function handleResize(width, height) {
|
||||
@ -75,6 +106,7 @@ function MapInteraction({ map, children, controls }) {
|
||||
const mapHeight = map ? stageWidth * (map.height / map.width) : stageHeight;
|
||||
|
||||
const mapStageRef = useContext(MapStageContext);
|
||||
const mapImageRef = useRef();
|
||||
|
||||
const auth = useContext(AuthContext);
|
||||
|
||||
@ -83,9 +115,11 @@ function MapInteraction({ map, children, controls }) {
|
||||
stageScale,
|
||||
stageWidth,
|
||||
stageHeight,
|
||||
stageDragState,
|
||||
setPreventMapInteraction,
|
||||
mapWidth,
|
||||
mapHeight,
|
||||
mapDragPosition,
|
||||
};
|
||||
|
||||
return (
|
||||
@ -111,6 +145,7 @@ function MapInteraction({ map, children, controls }) {
|
||||
width={mapWidth}
|
||||
height={mapHeight}
|
||||
id="mapImage"
|
||||
ref={mapImageRef}
|
||||
/>
|
||||
{/* Forward auth context to konva elements */}
|
||||
<AuthContext.Provider value={auth}>
|
||||
|
@ -140,13 +140,13 @@ export function getUpdatedShapeData(type, data, brushPosition, gridSize) {
|
||||
}
|
||||
}
|
||||
|
||||
const defaultStrokeSize = 1 / 10;
|
||||
export function getStrokeSize(multiplier, gridSize, canvasWidth, canvasHeight) {
|
||||
const defaultStrokeWidth = 1 / 10;
|
||||
export function getStrokeWidth(multiplier, gridSize, mapWidth, mapHeight) {
|
||||
const gridPixelSize = Vector2.multiply(gridSize, {
|
||||
x: canvasWidth,
|
||||
y: canvasHeight,
|
||||
x: mapWidth,
|
||||
y: mapHeight,
|
||||
});
|
||||
return Vector2.min(gridPixelSize) * defaultStrokeSize * multiplier;
|
||||
return Vector2.min(gridPixelSize) * defaultStrokeWidth * multiplier;
|
||||
}
|
||||
|
||||
export function shapeHasFill(shape) {
|
||||
@ -330,7 +330,7 @@ export function drawShape(shape, context, gridSize, canvasWidth, canvasHeight) {
|
||||
context.strokeStyle = color;
|
||||
if (shape.strokeWidth > 0) {
|
||||
context.lineCap = "round";
|
||||
context.lineWidth = getStrokeSize(
|
||||
context.lineWidth = getStrokeWidth(
|
||||
shape.strokeWidth,
|
||||
gridSize,
|
||||
canvasWidth,
|
||||
|
Loading…
Reference in New Issue
Block a user