Canvas scale with dpr redraw issues - javascript

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>
);
}

Related

Audio element not bubbling to body

I have troubles connecting an audio element with an analyser in Safari. Safari expects the user to interact with the browser before allowing an audio context to start, which is needed to connect an analyser with the audio element. For that I wait for a click event to connect, but the click on the audio element itself is not bubbled up to the body so that it cannot be caught. Any ideas what could be missing?
Here's some code:
import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import {
getAudioElement,
loadAudio,
getNextTrack,
} from '../../helpers/common/audio';
import { isTouch } from '../../helpers/common/screen';
import { captureKeys } from '../../helpers/common/control';
import './Player.css';
const drawAnalyser = (canvas, analyser, mode = 'frequency') => {
const bufferLength = analyser.frequencyBinCount;
const dataArray = new Uint8Array(bufferLength);
canvas.width = bufferLength;
canvas.height = 256;
const ctx = canvas.getContext('2d');
const barWidth = 1;
const barDistance = 1.375;
const paintCanvas = () => {
if (mode === 'waveform') {
analyser.getByteTimeDomainData(dataArray);
} else {
analyser.getByteFrequencyData(dataArray);
}
ctx.clearRect(0, 0, canvas.width, canvas.height);
dataArray.forEach((item, index) => {
const barHeight = item * 3 / 4;
if (mode === 'waveform') {
ctx.fillStyle = 'rgba(255, 170, 0, 1)';
ctx.fillRect(index, canvas.height - barHeight, barWidth, 1);
} else {
ctx.fillStyle = `rgba(255, ${255 - item}, 0, ${1 - (item / canvas.height)})`;
ctx.fillRect(index * barDistance, canvas.height, barWidth, 0 - barHeight);
}
});
window.requestAnimationFrame(paintCanvas);
};
paintCanvas();
};
const connect = (audio, canvas) => {
try {
const AudioContext = window.AudioContext;
const audioContext = new AudioContext();
const analyser = audioContext.createAnalyser();
const source = audioContext.createMediaElementSource(audio);
source.connect(analyser);
analyser.connect(audioContext.destination);
drawAnalyser(canvas, analyser);
} catch (error) {
}
};
export const attachEvents = () => {
document.addEventListener('click', handleClickBody);
};
export const unattachEvents = () => {
document.removeEventListener('click', handleClickBody);
};
const handleClickBody = e => {
connect(document.querySelector('.audio'), document.querySelector('.canvas'));
unattachEvents();
};
const Player = ({ initialTrack, trackList }) => {
const [currentTrack, setCurrentTrack] = useState(initialTrack);
useEffect(() => {
loadAudio(initialTrack);
if (!isTouch()) {
attachEvents();
return unattachEvents;
}
}, [initialTrack]);
useEffect(() => {
const handleKeydown = e => {
captureKeys(e, getAudioElement());
};
document.addEventListener('keydown', handleKeydown);
return () => {
document.removeEventListener('keydown', handleKeydown);
};
});
const handleAudioEnded = () => {
const nextTrack = getNextTrack(trackList, currentTrack);
loadAudio(nextTrack, true);
setCurrentTrack(nextTrack);
};
return (
<>
<canvas className="canvas" />
<div className="controls">
<audio
className="audio"
crossOrigin="anonymous"
controls
onEnded={handleAudioEnded}
/>
</div>
</>
);
};
Player.propTypes = {
initialTrack: PropTypes.object,
trackList: PropTypes.array,
};
export default Player;
Thanks in advance.

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.

moving an svg element on a page within a container

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,
});
}
};

Where clear canvas to receive fog effect in React

I'm trying to receive fog effect in React. The main idea is that I have two components: first component handles with updating of coordinates of clouds and their velocity, the second component is responsible for one cloud. I have problem with moving of clouds, if I don't clear canvas I can see track of every cloud, if I apply canvas.clear I can't see anything. Do you have any tip, where I should place clear canvas.clear or do you have other ideas?
The first component:
import React from 'react';
import styled from 'styled-components';
import FogPiece from './Fog-Piece.jsx';
const CanvasContext = React.createContext();
const FogDiv = styled.div`
position: absolute;
width:100vw;
height:100vh;
`
class Fog extends React.Component{
constructor(props){
super(props);
this.canvas = React.createRef();
this.state = {
ctx: null,
parameters:[],
screenWidth : 0,
screenHeight: 0,
}
}
componentDidMount = () => {
Promise.all(this.newCoordinates()).then((paramArray) =>{
this.setState({
ctx: this.canvas.current.getContext('2d'),
screenWidth: this.canvas.current.parentNode.getBoundingClientRect().width,
screenHeight: this.canvas.current.parentNode.getBoundingClientRect().height,
parameters: paramArray
});
window.requestAnimationFrame(this.update)
})
}
newCoordinates = () => {
return(Array.from(Array(this.props.density).keys()).map(elem =>{
return new Promise (resolve => {
const params = {
x: this.random(0,this.state.screenWidth),
y: this.random(0,this.state.screenHeight),
velocityX: this.random(-this.props.maxVelocity, this.props.maxVelocity),
velocityY: this.random(-this.props.maxVelocity, this.props.maxVelocity)
}
resolve(params)
})
}))
}
updateCoordinates = () => {
return(this.state.parameters.map(elem =>{
return new Promise (resolve => {
elem = this.ifCross(elem.x, elem.y, elem.velocityX, elem.velocityY);
const params = {
x: elem.x + elem.velocityX,
y: elem.y + elem.velocityY,
velocityX: elem.velocityX,
velocityY: elem.velocityY
}
resolve(params)
})
}))
}
random = (min,max) => {
return Math.random()*(max - min) + min
}
ifCross = (x,y, velocityX, velocityY) => {
if (x > this.state.screenWidth){
x = this.state.screenWidth
velocityX = - velocityX
}
if (x < 0){
x = 0
velocityX = - velocityX
}
if (y > this.state.screenHeight){
y = this.state.screenHeight
velocityY = - velocityY
}
if (y < 0){
y = 0
velocityY = - velocityY
}
return {x:x, y:y, velocityX:velocityX, velocityY:velocityY }
}
update = () => {
Promise.all(this.updateCoordinates()).then((paramArray) =>{
//here is the problem
// this.state.ctx.clearRect(0,0,this.state.screenWidth, this.state.screenHeight)
this.setState({
parameters: paramArray,
});
window.requestAnimationFrame(this.update)
})
}
render(){
return(
<FogDiv>
<canvas width={this.state.screenWidth} height={this.state.screenHeight} ref = {this.canvas} >
{this.state.ctx && (
<CanvasContext.Provider value = {this.state.ctx}>
{this.state.parameters.map(param =>(
<FogPiece
x = {param.x}
y = {param.y}
/>
))}
</CanvasContext.Provider>
)}
</canvas>
</FogDiv>
)
}
}
export default Fog;
export {
CanvasContext
}
the second one:
import React from 'react';
import styled from 'styled-components';
import {CanvasContext} from './Fog.jsx';
class FogPiece extends React.Component{
constructor(props){
super(props);
this.state = {
image:'https://media.istockphoto.com/vectors/sample-red-square-grunge-textured-isolated-stamp-vector-id471401412',
}
}
random(min,max){
return Math.random()*(max - min) + min
}
render(){
return(
<CanvasContext.Consumer>
{ctx => {
console.log("x", "y", this.props)
const img = new Image();
img.src = this.state.image;
img.onload = () => {
ctx.drawImage(img,
this.props.x,
this.props.y,
40,
40)
}
}}
</CanvasContext.Consumer>
)
}
}
export default FogPiece;

Categories