I am implementing Draw function, to draw a line in canvas. The Draw function is activated on the first double click and on mouse move the line is being drawn and on the second double click, the draw function is deactivated.
When I double click the third time the previously drawn line is disappearing. My requirement is I want to retain all of the lines. How do I do that?
Below is my draw function:
handleMouseMove(event){
if(this.state.isDouble)
{
this.Draw(event)
}
else{
}
}
Draw(event){
x2=event.offsetX
y2=event.offsetY
const canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.lineWidth = 3;
//Deleting The State
ctx.canvas.width = ctx.canvas.width;
console.log("First" + this.state.previousPointX,this.state.previousPointY)
console.log("Second" + x2,y2)
xtemp=x2
ytemp=this.state.previousPointY
console.log("Temp" + xtemp,ytemp)
ctx.beginPath()
ctx.moveTo(xtemp,ytemp);
ctx.lineTo(x2,y2);
ctx.stroke();
ctx.moveTo(xtemp,ytemp);
ctx.lineTo(this.state.previousPointX,this.state.previousPointY);
ctx.strokeStyle = "black";
ctx.stroke();
}
I have read here that you can save the canvas by converting it to json
for Redux store, I have tested using state for my Fabric canvas instance, its a 3rd party library that is a wrapper on a HTML canvas DOM element.
import React, { useEffect, useState } from 'react';
import './WallToDecorate.css';
import { fabric } from 'fabric';
const WallToDecorate = ({templateList=[]}) => {
const [wallCanvas, setCanvas] = useState();
useEffect(() => {
const canvas = new fabric.Canvas('fabric-canvas-to-decorate', {
width: rect.width,
height: rect.height
});
canvas.setBackgroundImage(
originalWallImage.src,
canvas.renderAll.bind(canvas),
{
backgroundImageOpacity: 1,
backgroundImageStretch: false,
top: top,
left: left,
}
);
setCanvas(canvas);
}, []);
const addImageToCanvas = (event) => {
fabric.util.loadImage(
event.target.src,
function (img) {
var fab_image = new fabric.Image(img, {
});
wallCanvas.add(fab_image);
wallCanvas.renderAll();
},
{ left: 100, top: 100, angle: 0, opacity: 1 }
);
};
return (
<>
<div id="select-image-dimensions" className="placeholder canvas-size">
<canvas id="fabric-canvas-to-decorate" />
</div>
</>
);
}
export default WallToDecorate;
In my case the wallCanvas.renderAll() refreshes the canvas element.
Related
I'm trying to render canvas and draw rectangle on it using svelte.js, but it does not work if I write rendering code on the component side.
Here is the reproduction REPL.
It works if I move entire code in Canvas.svelte to app.svelte.
App.svelte:
<script>
import Canvas from './Canvas.svelte';
</script>
<Canvas/>
Canvas.svelte:
<script>
import { onMount } from 'svelte';
let canvasEl;
const canvas = {
width: 1000,
height: 1000
};
const drawRect = (context) => {
context.beginPath();
context.fillStyle = '#000000';
context.rect(0, 0, 40, 10);
context.fill();
};
onMount(() => {
console.log('Onmount');
const context = canvasEl.getContext('2d');
canvas.width = document.body.clientWidth;
canvas.height = document.body.clientHeight;
drawRect(context);
});
</script>
<canvas bind:this={canvasEl} width={canvas.width} height={canvas.height} />
Does anyone know the solution?
Thank you,
Didn't find a reason of error, but found the source:
onMount(() => {
//...
// this 2 lines cause silent error
canvas.width = document.body.clientWidth;
canvas.height = document.body.clientHeight;
//...
});
Remove them and you will see the canvas and rect
I tried to add an onclick function called Test to the button "Click me" that will alert a message once I click on it. So far, I have had little success, i.e. nothing happened when I clicked on the button. Here is my code inside App.js:
import logo from './logo.svg';
import './App.css';
import React, {useState, useEffect, useCallback} from 'react';
const canvas_style = {
border:"1px solid #000000",
position: "absolute",
top: 0,
left: 0,
}
function Coordinate(props) {
const [HorizontalLines, setHorizontalLines] = useState({"start": [], "end": []}); //store start/end points of original horizontal lines
const [VerticalLines, setVerticalLines] = useState({"start": [], "end": []}); // store start/end points of original vertical lines
const [TransformedHorizontalLines, setTransformedHorizontalLines] = useState({"start": [], "end": []}); //store start/end points of original horizontal lines
const [TransformedVerticalLines, setTransformedVerticalLines] = useState({"start": [], "end": []}); // store start/end points of original vertical lines
const [TransformedUnitVectors, setUnitVectors] = useState([[1,0], [0,1]])
useEffect(() => { //create coordinate plane on coordinate canvas once rendered
var grid_size = 40;
var x_axis_distance_grid_lines = 10;
var y_axis_distance_grid_lines = 10;
var canvas = document.getElementById("coordinates");
var ctx = canvas.getContext("2d");
// canvas width
var canvas_width = canvas.width;
// canvas height
var canvas_height = canvas.height;
// no of vertical grid lines
var num_lines_x = Math.floor(canvas_height/grid_size);
// no of horizontal grid lines
var num_lines_y = Math.floor(canvas_width/grid_size);
for(var i=0; i<=num_lines_x; i++) {
ctx.beginPath();
ctx.lineWidth = 2;
// If line represents X-axis draw in different color
if(i == x_axis_distance_grid_lines)
ctx.strokeStyle = "#000000";
else
ctx.strokeStyle = "#e9e9e9";
if(i == num_lines_x) {
ctx.moveTo(0, grid_size*i);
ctx.lineTo(canvas_width, grid_size*i);
var new_start_point = [0, grid_size*i];
var new_end_point = [canvas_width, grid_size*i];
var new_start = HorizontalLines["start"]
var new_end = HorizontalLines["end"]
new_start.push(new_start_point)
new_end.push(new_end_point)
setHorizontalLines({"start": new_start, "end": new_end})
}
else {
ctx.moveTo(0, grid_size*i);
ctx.lineTo(canvas_width, grid_size*i);
new_start_point = [0, grid_size*i];
new_end_point = [canvas_width, grid_size];
new_start = HorizontalLines["start"]
new_end = HorizontalLines["end"]
new_start.push(new_start_point)
new_end.push(new_end_point)
setHorizontalLines({"start": new_start, "end": new_end})
}
ctx.stroke();
}
// Draw grid lines along Y-axis
for(i=0; i<=num_lines_y; i++) {
ctx.beginPath();
ctx.lineWidth = 1;
// If line represents Y-axis draw in different color
if(i == y_axis_distance_grid_lines)
ctx.strokeStyle = "#000000";
else
ctx.strokeStyle = "#e9e9e9";
if(i == num_lines_y) {
ctx.moveTo(grid_size*i, 0);
ctx.lineTo(grid_size*i, canvas_height);
new_start_point = [grid_size*i, 0];
new_end_point = [grid_size*i, canvas_height];
new_start = VerticalLines["start"]
new_end = VerticalLines["end"]
new_start.push(new_start_point)
new_end.push(new_end_point)
setVerticalLines({"start": new_start, "end": new_end})
}
else {
ctx.moveTo(grid_size*i, 0);
ctx.lineTo(grid_size*i, canvas_height);
new_start_point = [grid_size*i, 0];
new_end_point = [grid_size*i, canvas_height];
new_start = VerticalLines["start"]
new_end = VerticalLines["end"]
new_start.push(new_start_point)
new_end.push(new_end_point)
setVerticalLines({"start": new_start, "end": new_end})
}
ctx.stroke();
}
console.log(HorizontalLines['start'])
console.log(HorizontalLines['end'])
console.log(VerticalLines['start'])
console.log(VerticalLines['end'])
}, []);
const Test = useCallback(() => {
alert("test"); //this function DOES NOT work.
})
return (
<div style = {{position: "relative"}}>
<canvas id="coordinates" width="800" height="800" style={canvas_style}> </canvas>
<canvas id="transformedCoordinates" width="800" height="800" style ={canvas_style}> </canvas>
<button onClick={Test}>Click Me </button>
</div>
)
}
function App() {
return (
<div> <Coordinate /> </div>
);
}
Inside index.js, I called the App component:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import Design from './test'
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
reportWebVitals();
I would appreciate if someone can suggest to me a solution to this problem. Thanks!
The button is behind of canvas. So click function is not act.
Please change canvas_style. Add z-index css;
const canvas_style = {
border:"1px solid #000000",
position: "absolute",
top: 0,
left: 0,
zIndex: -1,
}
Try
const Test = useCallback(() => {
alert("test"); //this function should work now.
}, []);
Reference : https://dmitripavlutin.com/dont-overuse-react-usecallback/
Maybe this will help : <button onClick={this.Test}> Click Me </button>
I can really use some help, my goal is to add few lines to the canvas in different places, it means to use the function drawText few times, for some reason if I don't use drawText inside the onload of drawImage the text does not rendering I am really stuck and can use some help, my main target it to make website that can edit pictures and make memes (e.g.: https://imgflip.com/memegenerator)and adding text line is what i am getting stuck on because I don't understand how to render new text line while save the old one, every time i start new line its like the image rendering all over again and start from the beginning.
// Function to load image on the canvas
function drawImg(url) {
gCurrLineIdx = getCurrLineIdx();
let currLine = gMeme.lines[gCurrLineIdx];
const img = new Image();
img.src = url;
img.onload = () => {
gCtx.drawImage(img, 0, 0, gElCanvas.width, gElCanvas.height);
//If you dont call drawText the text does not render to the canvas
drawText(currLine.txt, currLine.size, currLine.fontColor, currLine.strokeColor, currLine.align, currLine.font, gElCanvas.width / 2, currLine.y);
};
}
// Function to add text on the canvas
function drawText(text = '', fontSize = 20, fontColor = 'white', strokeColor = 'black', align = 'center', font = "ariel", x = gElCanvas.width / 2, y = 20) {
gCtx.strokeStyle = strokeColor;
gCtx.fillStyle = fontColor;
gCtx.font = `${fontSize}px ${font}`;
gCtx.textAlign = align;
gCtx.fillText(text, x, y);
gCtx.strokeText(text, x, y);
}
//Function to add new text line on the canvas.
function onAddTextLine() {
let textInput = document.getElementById('text-input');
textInput.value = '';
addTextLine();
gCurrLineIdx = getCurrLineIdx();
var currLine = gMeme.lines[gCurrLineIdx];
drawText(currLine.txt, currLine.size, currLine.fontColor, currLine.strokeColor, currLine.align, currLine.font, gElCanvas.width / 2, currLine.y);
}
The question I see here is:
how to render new text line while save the old one
Looks like in your code you are drawing things independently, below is a different approach the class Meme has a few functions to add text and image but every time anything change the entire canvas is cleared (clearRect) and every element is re-drawn, the magic is in the this.draw(), that is the call to the common function that does all the drawing.
To keep my sample small I hard-coded many of the things you had as parameters, it should be easy for you to reintroduce them if you need
class Meme {
constructor(ctx, width, height) {
this.ctx = ctx;
this.ctx.font = '80px Arial';
this.ctx.fillStyle = "blue"
this.ctx.textAlign = "center"
this.width = width;
this.height = height;
}
addHeadText(text) {
this.htext = text;
this.draw();
}
addFootText(text) {
this.ftext = text;
this.draw();
}
addImage(image_src) {
this.image = new Image();
this.image.src = image_src;
this.image.onload = () => {
this.draw()
};
}
draw() {
this.ctx.beginPath();
this.ctx.clearRect(0, 0, this.width, this.height)
if (this.image) {
this.ctx.drawImage(this.image, 0, 0, this.width, this.height);
}
if (this.htext) {
this.ctx.textBaseline = "top";
this.ctx.fillText(this.htext, this.width / 2, 0);
}
if (this.ftext) {
this.ctx.textBaseline = "bottom";
this.ctx.fillText(this.ftext, this.width / 2, this.height);
}
this.ctx.closePath();
}
}
const canvas = document.getElementById('c');
const ctx = canvas.getContext('2d');
meme = new Meme(ctx, canvas.width, canvas.height)
meme.addHeadText("Hello");
meme.addFootText("World");
meme.addImage("http://i.stack.imgur.com/UFBxY.png");
document.getElementById('htext').onkeyup = (event) => {
meme.addHeadText(event.srcElement.value);
};
document.getElementById('ftext').onkeyup = (event) => {
meme.addFootText(event.srcElement.value);
};
Head Text:<input type="text" id="htext" name="ftext" style="width: 140px;" value="Hello"><br>
Foot Text:<input type="text" id="ftext" name="ftext" style="width: 140px;" value="World"><br>
<canvas id="c" width=280 height=380 style="border:2px solid red;"></canvas>
I am trying to create a logo and try to add a logo in the middle of the qr code and i am able to generate the qr code but unable to get the qr code with logo on the middle i have tried this code but unable to get the result getting this error
Error: You need to specify a canvas element
and i am using this library https://github.com/soldair/node-qrcode
and here is the tried code
const QRCode = require("qrcode");
const getQRcodeImage = async () => {
try {
let canvas = await QRCode.toCanvas(`my sample text`);
//adding a log at center
const imgDim = { width: 30, height: 30 }; //logo dimention
var context = canvas.getContext("2d");
var imageObj = new Image();
imageObj.src = "./Capture.png";
imageObj.onload = function () {
context.drawImage(
imageObj,
canvas.width / 2 - imgDim.width / 2,
canvas.height / 2 - imgDim.height / 2,
imgDim.width,
imgDim.height
);
};
return canvas;
} catch (e) {
console.error(e);
return "";
}
};
getQRcodeImage();
const QRCode = require("qrcode");
const { createCanvas, loadImage } = require("canvas");
async function create(dataForQRcode, center_image, width, cwidth) {
const canvas = createCanvas(width, width);
QRCode.toCanvas(
canvas,
dataForQRcode,
{
errorCorrectionLevel: "H",
margin: 1,
color: {
dark: "#000000",
light: "#ffffff",
},
}
);
const ctx = canvas.getContext("2d");
const img = await loadImage(center_image);
const center = (width - cwidth) / 2;
ctx.drawImage(img, center, center, cwidth, cwidth);
return canvas.toDataURL("image/png");
}
async function main() {
const qrCode = await create(
"http://shauryamuttreja.com/qr/",
"data:image/png;base64,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",
150,
50
);
console.log(qrCode);
}
main();
I am capturing images through react-webcam package but it is in a horizontal manner.
I am trying to view the image in a vertical manner. so I want the captured image to rotate at 90 degrees.
capture image is using a method that is this.webcam.getScreenshot().
so I am trying to set properties in this method so that the captured image is in a vertical manner, that it is rotated at 90 degrees.
I tried rotating the preview and capturing the image whereas, that doesn't work.
as images still are in a horizontal manner.
I want to rotate the image on capture
I tried // imageSrc.css('transform','rotate(90deg)');
but that does not work.
the image is captured as a base64 image
here webcam is the preview and capture button gets triggered by a button
capture = () => {
const imageSrc = this.webcam.getScreenshot();
this.setState({
picsArray: [...this.state.picsArray, imageSrc],
})
};
expected result: The picture is rotated 90 degrees on capturing the image using this method.
actual result: The image is not rotated at 90 degrees and doesn't know how to do it on capture.
Thank you for your time.
import React, { Component } from 'react';
import { render } from 'react-dom';
import Webcam from "react-webcam";
class App extends Component {
state = {
url: '',
};
setRef = webcam => {
this.webcam = webcam;
};
capture = () => {
const imageSrc = this.webcam.getScreenshot();
this.rotateImage(imageSrc, 180, (url) => {
this.setState({ url});
console.log(url, imageSrc);
});
};
rotateImage = (imageBase64, rotation, cb) => {
var img = new Image();
img.src = imageBase64;
img.onload = () => {
var canvas = document.createElement("canvas");
// var canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext("2d");
ctx.setTransform(1, 0, 0, 1, img.width / 2, img.height / 2);
ctx.rotate(rotation * (Math.PI / 180));
ctx.drawImage(img, -img.width / 2, -img.height / 2);
cb(canvas.toDataURL("image/jpeg"))
};
};
render() {
const videoConstraints = {
width: 1280,
height: 720,
facingMode: "user"
};
return (
<div>
<Webcam
audio={false}
height={350}
ref={this.setRef}
screenshotFormat="image/jpeg"
width={350}
videoConstraints={videoConstraints}
/>
<button onClick={this.capture}>Capture photo</button>
<img src={this.state.url} width="200" height="100" />
<canvas id="canvas" style={{display: 'none'}}></canvas>
</div>
);
}
}
render(<App />, document.getElementById('root'));
Update
Below code work for any dimension, only need to adjust in this.dim to reflect your need
import React, { Component } from 'react';
import { render } from 'react-dom';
import Webcam from "react-webcam";
class App extends Component {
state = {
url: '',
};
dim = {
height: 300, // adjust your original height
width: 200, // adjust your original width
};
setRef = webcam => {
this.webcam = webcam;
};
capture = () => {
const imageSrc = this.webcam.getScreenshot();
this.rotateImage(imageSrc, (url) => {
this.setState({ url});
console.log(url, imageSrc);
});
};
rotateImage = (imageBase64, cb) => {
var img = new Image();
img.src = imageBase64;
img.onload = () => {
var canvas = document.createElement("canvas");
const maxDim = Math.max(img.height, img.width);
canvas.width = img.height;
canvas.height = img.width;
var ctx = canvas.getContext("2d");
ctx.setTransform(1, 0, 0, 1, maxDim / 2, maxDim / 2);
ctx.rotate(90 * (Math.PI / 180));
ctx.drawImage(img, -maxDim / 2, -maxDim / 2);
cb(canvas.toDataURL("image/jpeg"))
};
};
render() {
const videoConstraints = {
width: this.dim.width,
height: this.dim.height,
facingMode: "user"
};
return (
<div>
<Webcam
audio={false}
height={this.dim.height}
ref={this.setRef}
screenshotFormat="image/jpeg"
width={this.dim.width}
videoConstraints={videoConstraints}
/>
<button onClick={this.capture}>Capture photo</button>
<img src={this.state.url} width={this.dim.height} height={this.dim.width} />
<canvas id="canvas" style={{display: 'none'}}></canvas>
</div>
);
}
}
render(<App />, document.getElementById('root'));
You can rotate the image immediately in the preview using the style property:
90:
<Webcam style={{ transformOrigin: '0 0', transform: `translateX(${(480 + 640) / 2}px) rotate(90deg)` }} /> // height + width
180:
<Webcam style={{transform: 'rotate(180deg)'}} />,
270:
<Webcam style={{ transformOrigin: '0 0', transform: `translate(${(480 - 640) / 2}px, ${480}px) rotate(-90deg)` }} />
You should put your base64 image in an img tag in this way:
<img src="data:image/png;base64, YOUR_BASE_64" />
and then apply the CSS transform that you mentioned the img.