moving an svg element on a page within a container - javascript

I have a project that lets you place a text element onto an SVG. Once that element is placed, I then want it to be draggable so that it can be repositioned. currently, I can place the text element, and I can do edit it, however, when I go to move it, that is where I am having problems. Currently, the issue is that when I click and move a text element, it moves. But when I release and click again, the element will move on its own always to the same spot. When I go to click it, then it will move off the page entirely.
I have looked and attempted several different ideas including these sources:
https://dev.to/tvanantwerp/dragging-svgs-with-react-38h6
http://www.petercollingridge.co.uk/tutorials/svg/interactive/dragging/
I believe, it has to do with the fact that a mouseclick reads according to the whole page, but I need it to be a specific area.
This is my canvas element that has the SVG:
import React, { useState } from "react";
const SvgCanvas = (props) => {
const [Dragging, setDragging] = useState(false);
const [origin, setOrigin] = useState({ x: 0, y: 0 });
const [coordinates, setCoordinates] = useState({ x: 20, y: 20 });
const DragClick = (e) => {
console.log(e.target.attributes);
e.preventDefault();
setDragging(true);
setOrigin({ x: e.clientX, y: e.clientY });
};
const DragMove = (e) => {
e.preventDefault();
if (Dragging) {
// var x = parseFloat(e.target.getAttributeNS(null,"x"))
// console.log(x)
// e.target.setAttributeNS(null,"x",x+.1);
console.log("Origin= X: "+origin.x+", Y: "+origin.y);
console.log("Current= X: "+e.clientX+", Y: "+e.clientY);
setCoordinates({ x: e.clientX - origin.x, y: e.clientY = origin.y });
}
};
const DragRelease = (e) => {
e.preventDefault();
setDragging(false);
};
var lnk = props.details.url;
const TextBoxArray = [];
for (var i = 0; i < props.details.box_count; i++) {
//console.log("for");
//console.log(props.Meme[i]);
const y = '20';
const x = '30';
TextBoxArray.push(
<text
key={i}
id={"MemeBox" + i}
//y={`${coordinates.y}`}
// x={`${coordinates.x}`}
transform={`translate(${coordinates.x}, ${coordinates.y})`}
fontSize={props.Meme[i] ? props.Meme[i].range : "16"}
fill={props.Meme[i] ? props.Meme[i].color : "black"}
onMouseDown={(e) => DragClick(e)}
onMouseMove={(e) => DragMove(e)}
onMouseUp={(e) => DragRelease(e)}
>
{props.Meme[i]
? (document.getElementById("MemeBox" + i).textContent =
props.Meme[i].text)
: null}
</text>
);
}
return (
<div id="SvgCanvas">
<svg>
<image key={props.details.id} x="10" y="10" href={lnk} />
{TextBoxArray}
</svg>
</div>
);
};
export default SvgCanvas;
And, the app.js file
import React, { useState} from "react";
import ReactDom from 'react-dom';
import SvgControls from "./components/svgcontrols";
import SvgCanvas from "./components/svgcanvas";
import MemeChooser from "./components/selector";
import "./style/meme.css";
function App() {
const [Meme, setMeme] = useState([]);
const [MemeText, setMemeText] = useState([]);
const MemeSet = (e) => {
setMeme(e);
};
const TextSet = (MemeEditArray, InitialArraySetFlag) => {
if (!InitialArraySetFlag) {
setMemeText(MemeEditArray);
}
if (InitialArraySetFlag) {
var MemeEditArrayCopy = [...MemeText];
MemeEditArrayCopy[MemeEditArray["id"]] = MemeEditArray;
setMemeText(MemeEditArrayCopy);
}
};
return (
<div className="App">
<header>Meme Maker</header>
<div id="MemeMaker">
<SvgCanvas Meme={MemeText} details={Meme} />
<SvgControls getter={MemeText} setter={TextSet} details={Meme} Create={document.getElementsByName(SvgCanvas)} />
<MemeChooser click={MemeSet} />
{
//console.log(ReactDom.findDOMNode(this).querySelector(SvgCanvas))
}
</div>
</div>
);
}
export default App;
I appreciate any suggestions, that you may have to help me fix this.

So after a while, I was able to come up with a solution for my issue. What I did was add a starting variable, and then making adjustments off of that.
const DragMove = (e) => {
e.preventDefault();
if (Dragging) {
// var x = parseFloat(e.target.getAttributeNS(null,"x"))
// console.log(x)
// e.target.setAttributeNS(null,"x",x+.1);
console.log("Origin= X: "+origin.x+", Y: "+origin.y);
console.log("Current= X: "+e.clientX+", Y: "+e.clientY);
setCoordinates({ x: e.clientX - origin.x, y: e.clientY = origin.y });
}
};
The problem was that when I was chaning the coordinates based on the click position, I was not adjusting for the initial position of the text.
const [Dragging, setDragging] = useState(false);
const [origin, setOrigin] = useState({ x: 0, y: 0 });
const [coordinates, setCoordinates] = useState({ x: 20, y: 20 });
const DragClick = (e) => {
console.log(e.target.attributes);
e.preventDefault();
setDragging(true);
setOrigin({ x: e.clientX, y: e.clientY });
};
const DragMove = (e) => {
e.preventDefault();
var startX = coordinates.x;
var startY = coordinates.y;
if (Dragging) {
setCoordinates({
x: startX + e.clientX - origin.x,
y: startY + e.clientY - origin.y,
});
}
};

Related

Canvas scale with dpr redraw issues

When I add scale and dpr to my drawing app's canvas to improve the look of objects on the canvas, it produces issues when resizing the window. The scale seems to be off and possibly flickering between 2 different scales as you change window size quickly? I can't seem to figure out the cause of this. As soon as I remove scale and dpr, then everything works fine. Here's my code and a codesandbox with it. https://codesandbox.io/s/holy-wave-t9y2g0?file=/src/App.js
import React, { useEffect, useRef, useState } from "react";
import getStroke from "perfect-freehand";
function getSvgPathFromStroke(stroke) {
if (!stroke.length) return "";
const d = stroke.reduce(
(acc, [x0, y0], i, arr) => {
const [x1, y1] = arr[(i + 1) % arr.length];
acc.push(x0, y0, (x0 + x1) / 2, (y0 + y1) / 2);
return acc;
},
["M", ...stroke[0], "Q"]
);
d.push("Z");
return d.join(" ");
}
export default function App() {
const [elements, setElements] = useState([]);
const wrapperRef = useRef(null);
const canvasRef = useRef(null);
const [isDrawing, setIsDrawing] = useState(false);
const [dimensions, setDimensions] = useState({
height: 0,
width: 0
});
const elementsRef = useRef(elements);
const dpr = window.devicePixelRatio || 1;
// in place of original `setElements`
const setElementsRef = (x) => {
elementsRef.current = x; // keep updated
setElements(x);
};
const setNewElements = ({ type, points, ...rest }) => {
setElementsRef([...elements, { type, points, ...rest }]);
};
useEffect(() => {
document.body.style.overscrollBehavior = "contain";
window.addEventListener("resize", () => {
resizeCanvas();
});
}, []);
useEffect(() => {
if (wrapperRef.current && canvasRef.current) {
setupCanvas(true);
}
}, [wrapperRef.current, canvasRef.current]);
useEffect(() => {
drawCanvas();
}, [elements]);
const drawCanvas = () => {
const context = canvasRef.current.getContext("2d");
context.clearRect(0, 0, dimensions.width * dpr, dimensions.height * dpr);
elementsRef.current.forEach((element) => {
const stroke = getStroke(element.points);
const pathData = getSvgPathFromStroke(stroke);
const myPath = new Path2D(pathData);
context.fill(myPath);
});
};
const setupCanvas = () => {
const newHeight = wrapperRef.current.clientHeight ?? 0;
const newWidth = wrapperRef.current.clientWidth ?? 0;
setDimensions({
height: newHeight,
width: newWidth
});
const context = canvasRef?.current?.getContext("2d");
context.scale(dpr, dpr);
return new Promise((fulfill) => fulfill(true));
};
const resizeCanvas = () => {
if (canvasRef.current) {
setupCanvas().then(() => drawCanvas());
}
};
function handleMouseDown(e) {
setIsDrawing(true);
if (canvasRef.current) {
const bounds = canvasRef?.current?.getBoundingClientRect();
const x = e.pageX - bounds.left - window.scrollX;
const y = e.pageY - bounds.top - window.scrollY;
setNewElements({ type: "pen", points: [[x, y]] });
}
}
function handleMouseMove(e) {
if (canvasRef.current && isDrawing) {
const bounds = canvasRef.current.getBoundingClientRect();
const x = e.pageX - bounds.left - window.scrollX;
const y = e.pageY - bounds.top - window.scrollY;
const arr = [...elements];
arr[arr.length - 1].points.push([x, y]);
setElementsRef(arr);
}
}
function handleMouseUp(e) {
setIsDrawing(false);
}
return (
<div
id="wrapper"
style={{ height: "100vh", width: "100vw", overflow: "hidden" }}
ref={wrapperRef}
>
<canvas
id="canvas"
ref={canvasRef}
style={{ height: "100%", width: "100%" }}
width={dimensions.width * dpr}
height={dimensions.height * dpr}
onMouseDown={handleMouseDown}
onMouseMove={handleMouseMove}
onMouseUp={handleMouseUp}
/>
</div>
);
}

Drag Background in React

I 'm new in React and i'm tryind to make draggable background, but no matter how hard I try, nothing happens. I found some code on jQuery, but there many advices that it's bad practice use jQuery in React.
Maybe i make something wrong.
Thanks in advance
Here's my React code
import React from "react";
import "../styles/board.css";
class Board extends React.Component {
constructor(props) {
super(props);
this.state = { mouseCliked: 0, startX: 0, startY: 0 };
}
mouseDown(e) {
this.setState({ mouseCliked: 1, startX: e.clientX, startY: e.clientY });
}
mouseUp(e) {
this.setState({ mouseCliked: 0, startX: e.clientX, startY: e.clientY });
}
mouseMove = (e) => {
let newPosY = e.clientY - this.stateY;
let newPosX = e.clientX - this.stateX;
if (this.state.mouseClicked) {
e.target.style.backgroundPositionX += newPosX;
e.target.style.backgroundPositionY += newPosY;
}
};
render() {
return (
<div
onMouseMove={this.mouseMove.bind(this)}
onMouseUp={this.mouseUp.bind(this)}
onMouseDown={this.mouseDown.bind(this)}
className="background-image"
>
</div>
);
}
}
export default Board;
CSS:
width:300px;
height: 300px;
background-size: 1000px;
background-position-x: 0;
background-position-y: 0;
background-image: url('https://images.unsplash.com/photo-1452723312111-3a7d0db0e024?crop=entropy&dpr=2&fit=crop&fm=jpg&h=750&ixjsv=2.1.0&ixlib=rb-0.3.5&q=50&w=1450.jpg');
}
I have encountered this problem and also checked jQuery - drag div css background
Finally I came up with this solution and seemed working fine.
const imageStyleInitialValue = {
backgroundImage: "",
backgroundPosition: "0 0",
backgroundSize: "0 0",
height: 0,
width: 0,
};
const [startPoint, setStartPoint] = useState({x: 0, y: 0});
const [dragging, setDragging] = useState(false);
const [imageStartPos, setImageStartPos] = useState([0, 0]);
const [imageStyles, setImageStyles] = useState<ImageStyles>(imageStyleInitialValue);
// add onMouseMove={handleDragImage} to the image component
const handleDragImage = (e) => {
if (dragging) {
const deltaX = e.clientX - startPoint.x;
const deltaY = e.clientY - startPoint.y;
setImageStyles({...imageStyles,
backgroundPosition:
`${imageStartPos[0] + deltaX} ${imageStartPos[1] + deltaY}`
})
}
};
// add onMouseDown={handleStartDragImage} to the image component
const handleStartDragImage = (e) => {
setDragging(true);
const backgroundPosArray = imageStyles.backgroundPosition.split(" ").map(value => Number(value));
setImageStartPos(backgroundPosArray);
setStartPoint({x: e.clientX, y: e.clientY});
}
// add onMouseUp={handleEndDragImage} to the top component because you want
// to set Dragging to false when the dragging ends outside of the image
const handleEndDragImage = (e) => {
setDragging(false)
};

React - Render happening before state is changed

Very confused about this one. From the code, If you move the green square you will see the printed values.
I expected all of the code to run before the state is changed and the rerender however from this code example i can see the rerender happens as soon as the function to change state is called.
import React, { useState, useEffect, useRef } from "react";
import styled, { ThemeProvider, css } from "styled-components";
export default function App() {
const pos = useRef({ x: 0, y: 0 });
const offset = useRef({ x: 0, y: 0 });
const myDiv = useRef(null);
const [rerender, setRerender] = useState(0);
console.log("render");
useEffect(() => {
window.addEventListener("mousemove", doSomething);
window.addEventListener("mousedown", doSomethingAgain);
return () => {
window.removeEventListener("mousemove", doSomething);
window.removeEventListener("mousedown", doSomethingAgain);
};
}, [rerender]);
console.log("global", rerender);
function doSomething(e) {
if (e.buttons == 1) {
const newPos = {
x: e.pageX,
y: e.pageY
};
pos.current = newPos;
console.log("first", rerender);
setRerender(rerender + 1);
console.log("second", rerender);
}
}
function doSomethingAgain(e) {
const offsetX = e.pageX - myDiv.current.offsetLeft;
const offsetY = e.pageY - myDiv.current.offsetTop;
offset.current = { x: offsetX, y: offsetY };
}
return (
<div className="App">
<DIV ref={myDiv} off={offset.current} pos={pos.current}></DIV>
</div>
);
}
const DIV = styled.div`
display: inline-block;
width: 100px;
height: 100px;
background-color: green;
position: absolute;
top: ${({ pos, off }) => pos.y - off.y}px;
left: ${({ pos, off }) => pos.x - off.x}px;
`;

Property 'current' does not exist on type '[boolean, Dispatch<SetStateAction<boolean>>]'.ts(2339)

I am adding cursor animations to a React/Typescript project and in researching came across a CodePen (Animated Cursor
React Component) that works perfectly well.
However, when converting to a Typescript file I come across the error Property 'current' does not exist on type '[boolean, Dispatch<SetStateAction<boolean>>]'.ts(2339) on cursorVisible.current in
const onMouseEnter = () => {
cursorVisible.current = true;
toggleCursorVisibility();
};
Property cursorVisible is from const cursorVisible = useState(false);
What does Typescript need me to do so current works in Typescript? Reading the React Hooks docs, I could not see reference to current on useState and interestingly this works as a js file, only not in ts.
In the past I have used current with ref but never across useState hook.
Full file is
import React, { useEffect, useRef, useState } from 'react';
import MobileDetect from './MobileDetect';
interface CursorProps {
color: string;
outlineAlpha: number;
dotSize: number;
outlineSize: number;
outlineScale: number;
dotScale: number;
}
function AnimatedCursor({
color = '220, 90, 90',
outlineAlpha = 0.3,
dotSize = 8,
outlineSize = 8,
outlineScale = 5,
dotScale = 0.7,
}: CursorProps) {
// Bail if Mobile
if (typeof navigator !== 'undefined' && MobileDetect!.anyMobile())
return <></>;
const cursorOutline = useRef();
const cursorDot = useRef();
const requestRef = useRef();
const previousTimeRef = useRef();
const [width, setWidth] = useState(window.innerWidth);
const [height, setHeight] = useState(window.innerHeight);
const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });
const cursorVisible = useState(false);
const cursorEnlarged = useState(false);
const styles = {
cursors: {
zIndex: 999,
pointerEvents: 'none',
position: 'absolute',
top: '50%',
left: '50%',
borderRadius: '50%',
opacity: 0,
transform: 'translate(-50%, -50%)',
transition: 'opacity 0.15s ease-in-out, transform 0.15s ease-in-out',
},
cursorDot: {
width: dotSize,
height: dotSize,
backgroundColor: `rgba(${color}, 1)`,
},
cursorOutline: {
width: outlineSize,
height: outlineSize,
backgroundColor: `rgba(${color}, ${outlineAlpha})`,
},
};
// Hide default cursor
document.body.style.cursor = 'none';
// Mouse Events
const onMouseMove = (event: { pageX: number; pageY: number }) => {
const { pageX: x, pageY: y } = event;
setMousePosition({ x, y });
positionDot(event);
};
const onMouseEnter = () => {
cursorVisible.current = true;
toggleCursorVisibility();
};
const onMouseLeave = () => {
cursorVisible.current = false;
toggleCursorVisibility();
};
const onMouseDown = () => {
cursorEnlarged.current = true;
toggleCursorSize();
};
const onMouseUp = () => {
cursorEnlarged.current = false;
toggleCursorSize();
};
// Set window hxw
const onResize = () => {
setWidth(window.innerWidth);
setHeight(window.innerHeight);
};
/**
* Hooks
*/
useEffect(() => {
// Bail if mobile
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseenter', onMouseEnter);
document.addEventListener('mouseleave', onMouseLeave);
document.addEventListener('mousedown', onMouseDown);
document.addEventListener('mouseup', onMouseUp);
window.addEventListener('resize', onResize);
requestRef.current = requestAnimationFrame(animateDotOutline);
handleLinkEvents();
return () => {
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseenter', onMouseEnter);
document.removeEventListener('mouseleave', onMouseLeave);
document.removeEventListener('mousedown', onMouseDown);
document.removeEventListener('mouseup', onMouseUp);
window.removeEventListener('resize', onResize);
cancelAnimationFrame(requestRef.current);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
let { x, y } = mousePosition;
const winDimensions = { width, height };
let endX = winDimensions.width / 2;
let endY = winDimensions.height / 2;
/**
* Toggle Cursor Visiblity
*/
function toggleCursorVisibility() {
if (cursorVisible.current) {
cursorDot.current.style.opacity = 1;
cursorOutline.current.style.opacity = 1;
} else {
cursorDot.current.style.opacity = 0;
cursorOutline.current.style.opacity = 0;
}
}
/**
* Position Dot (cursor)
* #param {event}
*/
function positionDot(e: { pageX: number; pageY: number }) {
cursorVisible.current = true;
toggleCursorVisibility();
// Position the dot
endX = e.pageX;
endY = e.pageY;
cursorDot.current.style.top = `${endY}px`;
cursorDot.current.style.left = `${endX}px`;
}
/**
* Toggle Cursors Size/Scale
*/
function toggleCursorSize() {
if (cursorEnlarged.current) {
cursorDot.current.style.transform = `translate(-50%, -50%) scale(${dotScale})`;
cursorOutline.current.style.transform = `translate(-50%, -50%) scale(${outlineScale})`;
} else {
cursorDot.current.style.transform = 'translate(-50%, -50%) scale(1)';
cursorOutline.current.style.transform = 'translate(-50%, -50%) scale(1)';
}
}
/**
* Handle Links Events
* Applies mouseover/out hooks on all links
* to trigger cursor animation
*/
function handleLinkEvents() {
document.querySelectorAll('a').forEach((el) => {
el.addEventListener('mouseover', () => {
cursorEnlarged.current = true;
toggleCursorSize();
});
el.addEventListener('mouseout', () => {
cursorEnlarged.current = false;
toggleCursorSize();
});
});
}
/**
* Animate Dot Outline
* Aniamtes cursor outline with trailing effect.
* #param {number} time
*/
const animateDotOutline = (time: undefined) => {
if (previousTimeRef.current !== undefined) {
x += (endX - x) / 8;
y += (endY - y) / 8;
cursorOutline.current.style.top = `${y}px`;
cursorOutline.current.style.left = `${x}px`;
}
previousTimeRef.current = time;
requestRef.current = requestAnimationFrame(animateDotOutline);
};
return (
<>
<div
ref={cursorOutline}
id="cursor-outline"
style={{ ...styles.cursors, ...styles.cursorOutline }}
/>
<div
ref={cursorDot}
id="cursor-inner"
style={{ ...styles.cursors, ...styles.cursorDot }}
/>
</>
);
}
export default AnimatedCursor;
Posting here in case someone else ran into this issue:
My problem was that i was using curly braces instead brackets when destructuring. Brain fart moment, but basically I was attempting to use the Object destructure notation on the array that's returned from useState.
const { someState, setSomeState } = useState(false);
should be
const [ someState, setSomeState ] = useState(false);
You'll have to ask the author of the code you're using. useState returns an array with the current value and a setter function to change the value. Normally you would use it like this:
let [cursorVisible, setCursorVisible] = useState(false);
// instead of cursorVisible.current = true
setCursorVisible(true);
There's no 'current' property on the array, unless maybe it is set by other code which would be bad form I think.

Draw Arrow on Canvas with React-Konva

I would like to create a canvas where the user can draw an Arrow by using his mouse.
What I'm trying to accomplish is exactly this: https://jsfiddle.net/w33e9fpa/
But I don't understand how to convert that to React code, and my implementation currently doesn't work. When I run this code it seems that an arrow is drawn on the top left of the canvas, but nothing happens if I click on it.
Here's my code:
class DrawArrow extends Component {
state = {
isDrawing: false,
mode: "brush"
};
componentDidMount() {
const canvas = document.createElement("canvas");
canvas.width = 300;
canvas.height = 300;
const context = canvas.getContext("2d");
this.setState({ canvas, context });
}
handleMouseDown = () => {
this.setState({ isDrawing: true });
// TODO: improve
const stage = this.arrow.parent.parent;
this.lastPointerPosition = stage.getPointerPosition();
this.setState({
posX: this.lastPointerPosition.x,
poxY: this.lastPointerPosition.y
})
}
handleMouseUp = () => {
this.setState({ isDrawing: false });
};
handleMouseMove = () => {
if (this.state.drawing === true) {
const stage = this.arrow.parent.parent;
this.lastPointerPosition = stage.getPointerPosition();
var pos = stage.getPointerPosition();
var oldPoints = this.arrow.points();
this.arrow.points([oldPoints[0], oldPoints[1], pos.x, pos.y])
this.arrow.getLayer().draw();
}
}
render() {
return (
<Arrow
points= {[this.state.posX,this.state.posY, this.state.posX, this.state.posY]}
pointerLength= {20}
pointerWidth= {20}
fill= 'black'
stroke= 'black'
strokeWidth= {4}
onMouseDown={this.handleMouseDown}
onMouseUp={this.handleMouseUp}
onMouseMove={this.handleMouseMove}
/>
);
}
}
class NewWhite extends Component {
render() {
return (
<Stage width={900} height={700}>
<Layer>
<DrawArrow />
</Layer>
</Stage>
);
}
}
Thanks for you help !
Here you go:
import React, { Component } from "react";
import { Stage, Layer, Arrow, Circle, Line } from "react-konva";
import ReactDOM from "react-dom";
import "./styles.css";
class Drawable {
constructor(startx, starty) {
this.startx = startx;
this.starty = starty;
}
}
class ArrowDrawable extends Drawable {
constructor(startx, starty) {
super(startx, starty);
this.x = startx;
this.y = starty;
}
registerMovement(x, y) {
this.x = x;
this.y = y;
}
render() {
const points = [this.startx, this.starty, this.x, this.y];
return <Arrow points={points} fill="black" stroke="black" />;
}
}
class CircleDrawable extends ArrowDrawable {
constructor(startx, starty) {
super(startx, starty);
this.x = startx;
this.y = starty;
}
render() {
const dx = this.startx - this.x;
const dy = this.starty - this.y;
const radius = Math.sqrt(dx * dx + dy * dy);
return (
<Circle radius={radius} x={this.startx} y={this.starty} stroke="black" />
);
}
}
class FreePathDrawable extends Drawable {
constructor(startx, starty) {
super(startx, starty);
this.points = [startx, starty];
}
registerMovement(x, y) {
this.points = [...this.points, x, y];
}
render() {
return <Line points={this.points} fill="black" stroke="black" />;
}
}
class SceneWithDrawables extends Component {
constructor(props) {
super(props);
this.state = {
drawables: [],
newDrawable: [],
newDrawableType: "FreePathDrawable"
};
}
getNewDrawableBasedOnType = (x, y, type) => {
const drawableClasses = {
FreePathDrawable,
ArrowDrawable,
CircleDrawable
};
return new drawableClasses[type](x, y);
};
handleMouseDown = e => {
const { newDrawable } = this.state;
if (newDrawable.length === 0) {
const { x, y } = e.target.getStage().getPointerPosition();
const newDrawable = this.getNewDrawableBasedOnType(
x,
y,
this.state.newDrawableType
);
this.setState({
newDrawable: [newDrawable]
});
}
};
handleMouseUp = e => {
const { newDrawable, drawables } = this.state;
if (newDrawable.length === 1) {
const { x, y } = e.target.getStage().getPointerPosition();
const drawableToAdd = newDrawable[0];
drawableToAdd.registerMovement(x, y);
drawables.push(drawableToAdd);
this.setState({
newDrawable: [],
drawables
});
}
};
handleMouseMove = e => {
const { newDrawable } = this.state;
if (newDrawable.length === 1) {
const { x, y } = e.target.getStage().getPointerPosition();
const updatedNewDrawable = newDrawable[0];
updatedNewDrawable.registerMovement(x, y);
this.setState({
newDrawable: [updatedNewDrawable]
});
}
};
render() {
const drawables = [...this.state.drawables, ...this.state.newDrawable];
return (
<div>
<button
onClick={e => {
this.setState({ newDrawableType: "ArrowDrawable" });
}}
>
Draw Arrows
</button>
<button
onClick={e => {
this.setState({ newDrawableType: "CircleDrawable" });
}}
>
Draw Circles
</button>
<button
onClick={e => {
this.setState({ newDrawableType: "FreePathDrawable" });
}}
>
Draw FreeHand!
</button>
<Stage
onMouseDown={this.handleMouseDown}
onMouseUp={this.handleMouseUp}
onMouseMove={this.handleMouseMove}
width={900}
height={700}
>
<Layer>
{drawables.map(drawable => {
return drawable.render();
})}
</Layer>
</Stage>
</div>
);
}
}
function App() {
return <SceneWithDrawables />;
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Working example to play with:
https://codesandbox.io/s/w12qznzx5

Categories