I'm working on a proyect and i need to draw in almost 5 canvas. I've created the first canvas successfully but when i put in the code the second i only can draw on this latest canvas.
I read than the problem can be the context("2d") i tryed to separate saving in a different ctx varaible like, ctx2 or things like this.
This is my code:
HTML
<!--First Canvas-->
<div class="col-sm-12 col-lg-6 mt-5 d-flex flex-column justify-content-center">
<div id="contenedor-pizarra-cervical" class="contenedor-pizarra mx-auto">
<canvas id="pizarra-cervical"></canvas>
</div>
</div>
<!--Second Canvas-->
<div class="col-sm-12 col-lg-6 mt-5 d-flex flex-column justify-content-center">
<div id="contenedor-pizarra-postural" class="contenedor-pizarra mx-auto">
<canvas id="pizarra-postural"></canvas>
</div>
</div>
JS OF THE FIRST CANVAS WORKING OK:
//Canvas Cervical
var canvasCervical = document.getElementById("pizarra-cervical");
var ctx = canvasCervical.getContext("2d");
var painting = document.getElementById("contenedor-pizarra-cervical");
var paintStyle = getComputedStyle(painting);
canvasCervical.width = parseInt(paintStyle.getPropertyValue("width"));
canvasCervical.height = parseInt(paintStyle.getPropertyValue("height"));
var mouse = {x: 0, y: 0};
canvasCervical.addEventListener('mousemove', function(e){
mouse.x = e.pageX - this.offsetLeft;
mouse.y = e.pageY - this.offsetTop
}, false);
ctx.lineWidth = 3;
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
ctx.strokeStyle = '#7baeb0';
canvasCervical.addEventListener('mousedown', function(e){
ctx.beginPath();
ctx.moveTo(mouse.x, mouse.y);
canvasCervical.addEventListener('mousemove', onPaint, false);
}, false);
canvasCervical.addEventListener('mouseup', function(){
canvasCervical.removeEventListener('mousemove', onPaint, false)
},false);
var onPaint = function (){
ctx.lineTo(mouse.x, mouse.y);
ctx.stroke();
};
If you require the same behaviour to happen on multiple canvasses, then you could define the configuration logic in its own function, providing the canvas element as an argument, like this:
let configureCanvas = canvas => {
let painting = canvas.parentNode;
let paintStyle = getComputedStyle(painting);
let mouse = { x: 0, y: 0 };
let onPaint = () => {
ctx.lineTo(mouse.x, mouse.y);
ctx.stroke();
};
canvas.width = parseInt(paintStyle.getPropertyValue("width"));
canvas.height = parseInt(paintStyle.getPropertyValue("height"));
let ctx = canvas.getContext("2d");
ctx.lineWidth = 3;
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
ctx.strokeStyle = '#7baeb0';
canvas.addEventListener('mousemove', function(e) {
mouse.x = e.pageX - this.offsetLeft;
mouse.y = e.pageY - this.offsetTop
}, false);
canvas.addEventListener('mousedown', function(e) {
ctx.beginPath();
ctx.moveTo(mouse.x, mouse.y);
canvas.addEventListener('mousemove', onPaint, false);
}, false);
canvas.addEventListener('mouseup', function() {
canvas.removeEventListener('mousemove', onPaint, false)
}, false);
canvas.nextElementSibling.addEventListener('click', function() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
});
}
configureCanvas(document.getElementById("pizarra-cervical"));
configureCanvas(document.getElementById("pizarra-postural"));
canvas {
border: 1px solid #CCC;
}
<!--First Canvas-->
<div class="col-sm-12 col-lg-6 mt-5 d-flex flex-column justify-content-center">
<div id="contenedor-pizarra-cervical" class="contenedor-pizarra mx-auto">
<canvas id="pizarra-cervical"></canvas>
<button class="clear">Clear</button>
</div>
</div>
<!--Second Canvas-->
<div class="col-sm-12 col-lg-6 mt-5 d-flex flex-column justify-content-center">
<div id="contenedor-pizarra-postural" class="contenedor-pizarra mx-auto">
<canvas id="pizarra-postural"></canvas>
<button class="clear">Clear</button>
</div>
</div>
Taking this a step further, I'd suggest defining your own Class to handle the initialisation, configuration and event handlers of your canvas elements, but that's well outside the remit of this question.
Related
I'm actually working on a project which overlay two image, with one that the user upload it and the second is by default.
My only problem is when the uploaded image is a rectangle and not a square, the canvas is resizing it. I need that the canvas crop my image, and be a square. Then I can apply the filter.
Here is my code:
$('.file1, .file2').on('change', function() {
var reader = new FileReader(),
imageSelector = $(this).data('image-selector');
if (this.files && this.files[0]) {
reader.onload = function(e) {
imageIsLoaded(e, imageSelector)
};
reader.readAsDataURL(this.files[0]);
}
});
$('.btn-merge').on('click', merge);
function imageIsLoaded(e, imageSelector) {
$(imageSelector).attr('src', e.target.result);
$(imageSelector).removeClass('hidden');
};
function merge() {
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d'),
imageObj1 = new Image(),
imageObj2 = new Image();
canvas.width = 300;
canvas.height = 300;
imageObj1.src = $('.image1').attr('src');
imageObj1.onload = function() {
ctx.globalAlpha = 1;
ctx.drawImage(imageObj1, 0, 0, 300, 300);
imageObj2.src = $('.image2').attr('src');
imageObj2.onload = function() {
ctx.globalAlpha = 1;
ctx.drawImage(imageObj2, 0, 0, 300, 300);
var img = canvas.toDataURL('img/png');
$('.merged-image').attr('src', img);
var mergedimage = document.getElementById('mergedimage');
$('.merged-image').removeClass('hidden');
$("#downloadfinal").attr("href", mergedimage.src);
}
};
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.0/jquery.min.js"></script>
<div class="container-fluid shadow">
<div class="container d-flex flex-column justify-content-center">
<div class="row mb-1 ">
<h2>Votre photo ici : </h2>
<label class="custom ml-3 hover-underline-animation"> <input class="ml-2 file1" type="file" data-image-selector=".image1" />Selectionner un fichier</label>
</div>
<img class="image1 hidden mb-4" alt="abs" width="200px" height="auto" />
<div class="row">
<h2 class="mr-2 ">Filtre par défaut : </h2>
<img alt="abs image3" width="200px" height="auto" src="img/filtre.png" />
</div>
<div class="otherfilter">
<div class="row mt-5 mb-5">
<h2 class="">Mettez un autre filtre ici : </h2>
<label class="custom ml-3 hover-underline-animation"> <input class="ml-2 file2" type="file" data-image-selector=".image2" />Selectionner un fichier</label>
</div>
<img class="hidden image2" alt="ab" width="200px" height="auto" src="img/filtre.png">
</div>
</div>
<br />
<div class="text-center mb-5">
<input class="btn-merge mb-3" type="button" value="Appliquer le filtre" />
<br />
<img class="merged-image hidden mb-3" id="mergedimage" alt="merged image" />
<canvas id="canvas" class="hidden"></canvas>
<br>
<a class="btn-dl" id="downloadfinal" role="button" href="#" download="photo_profil_modifie">
<i class="mr-2 bi bi-download"></i>Télécharger
</a>
</div>
Thanks for read this, hope my english is good, if you don't understand tell me.
To do this you need to scale the input image to fit the canvas either horizontally or vertically while maintaining it's aspect ratio.
That's not hard to do as things are a bit easier since the canvas is squarish. Say we have a canvas of 300 x 300 pixel and we want to draw a non-square image of 400 x 300 onto. First we take the width or height of the canvas - it does not really matter as it's the same - and divide it by the bigger side of the image - 400 in this case.
300 / 400 == 0.75
This is the scale we need to multiply both the width and height of the image before drawing it onto the canvas.
Here's an example:
let canvas = document.getElementById('canvas');
let context = canvas.getContext('2d');
let imageObj1 = new Image();
imageObj1.crossOrigin = 'anonymous';
imageObj1.crossOrigin = 'anonymous';
imageObj1.onload = () => {
let scale = imageObj1.width > imageObj1.height ? canvas.width / imageObj1.width : canvas.height / imageObj1.height;
context.drawImage(imageObj1, canvas.width / 2 - imageObj1.width * scale / 2, canvas.height / 2 - imageObj1.height * scale / 2, imageObj1.width * scale, imageObj1.height * scale);
}
imageObj1.src = 'https://api.codetabs.com/v1/proxy?quest=https://picsum.photos/id/237/300/400';
#canvas {
background: blue;
}
<canvas id="canvas" width="300" height="300"></canvas>
If you prefer to not have unused area on your canvas and stretch the image to the whole canvas and crop the exceess, you simply divide the smaller side of your image by the canvas width/height.
For example:
//ctx.drawImage(imageObj1, 0, 0, 300, 300);let image = new Image();
let canvas = document.getElementById('canvas');
let context = canvas.getContext('2d');
let imageObj1 = new Image();
imageObj1.crossOrigin = 'anonymous';
imageObj1.crossOrigin = 'anonymous';
imageObj1.onload = () => {
let scale = imageObj1.width < imageObj1.height ? canvas.width / imageObj1.width : canvas.height / imageObj1.height;
context.drawImage(imageObj1, canvas.width / 2 - imageObj1.width * scale / 2, canvas.height / 2 - imageObj1.height * scale / 2, imageObj1.width * scale, imageObj1.height * scale);
}
imageObj1.src = 'https://api.codetabs.com/v1/proxy?quest=https://picsum.photos/id/237/300/400';
<canvas id="canvas" width="300" height="300"></canvas>
I can Draw in canvas inside normal HTML page. But my question is when i put canvas inside Modal Dialog drawing function not working.
I added my code with this.
I don't know this is happening because of view overlapping.Any though about how to fix this would be appreciated.
var canvas, ctx, flag = false,
prevX = 0,
currX = 0,
prevY = 0,
currY = 0,
dot_flag = false;
var x = "black",
y = 2;
$('#edit-question-image').on('show.bs.modal', function (e) {
var QuestionId = $(e.relatedTarget).data('question-id');
var photo = $(e.relatedTarget).data('imgsrc');
$(e.currentTarget).find('input[id="questionId"]').val(QuestionId);
$(e.currentTarget).find('img[id="canvasimg"]').attr("src", photo);
canvas = document.getElementById('can');
ctx = canvas.getContext("2d");
var img = document.getElementById("canvasimg");
ctx.drawImage(img, 10, 10);
w = canvas.width;
h = canvas.height;
canvas.addEventListener("mousemove", function (e) {
findxy('move', e)
}, false);
canvas.addEventListener("mousedown", function (e) {
findxy('down', e)
}, false);
canvas.addEventListener("mouseup", function (e) {
findxy('up', e)
}, false);
canvas.addEventListener("mouseout", function (e) {
findxy('out', e)
}, false);
});
function color(obj) {
console.log("colour", obj.id)
switch (obj.id) {
case "red":
x = "red";
case "black":
x = "black";
break;
case "white":
x = "white";
break;
}
y==2
}
function draw() {
ctx.beginPath();
ctx.moveTo(prevX, prevY);
ctx.lineTo(currX, currY);
ctx.strokeStyle = x;
ctx.lineWidth = y;
ctx.stroke();
ctx.closePath();
}
function erase() {
var m = confirm("Want to clear");
if (m) {
ctx.clearRect(0, 0, w, h);
document.getElementById("canvasimg").style.display = "none";
}
}
function save() {
document.getElementById("canvasimg").style.border = "2px solid";
var dataURL = canvas.toDataURL();
document.getElementById("canvasimg").src = dataURL;
document.getElementById("canvasimg").style.display = "inline";
}
function findxy(res, e) {
if (res == 'down') {
prevX = currX;
prevY = currY;
currX = e.clientX - canvas.offsetLeft;
currY = e.clientY - canvas.offsetTop;
flag = true;
dot_flag = true;
if (dot_flag) {
ctx.beginPath();
ctx.fillStyle = x;
ctx.fillRect(currX, currY, 2, 2);
ctx.closePath();
dot_flag = false;
}
}
if (res == 'up' || res == "out") {
flag = false;
}
if (res == 'move') {
if (flag) {
prevX = currX;
prevY = currY;
currX = e.clientX - canvas.offsetLeft;
currY = e.clientY - canvas.offsetTop;
draw();
}
}
}
HTML Code
<div id="edit-question-image" class="modal fade" role="dialog">
<div class="modal-dialog">
<div class="modal-content" style="padding: 16px;">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 id="editPhoto-Title" class="sc-badge sc-safe" style="padding: 4px 3px !important;">Modify Photo</h4>
</div>
<div class="modal-body">
<div id="editPhoto-ImgContainer_Q">
<canvas id="can" width="400" height="400" style="top:10%;left:10%;border:2px solid;"></canvas>
<div style="top:12%;left:43%;">Choose Color</div>
<div style="top:15%;left:47%;width:10px;height:10px;background:red;" id="red" onclick="color(this)"></div>
<div style="top:17%;left:47%;width:10px;height:10px;background:black;" id="black" onclick="color(this)"></div>
<div style="top:20%;left:43%;">Eraser</div>
<div style="top:22%;left:45%;width:15px;height:15px;background:white;border:2px solid;" id="white" onclick="color(this)"></div>
<img id="canvasimg" style="position:absolute;top:10%;left:52%; display:none;" >
<input type="button" value="save" id="btn" size="30" onclick="save()" style="top:55%;left:10%;">
<input type="button" value="clear" id="clr" size="23" onclick="erase()" style="top:55%;left:15%;">
</div>
<div class="modal-footer">
<input type="button" id="btnCloseDialogEditPhoto" class="modal-button" style="margin: 8px;" value="Cancel" data-dismiss="modal" />
<input type="submit" id="btnSaveEditPhoto_Q" class="modal-button" style="margin: 8px; float: right;" value="Submit" data-dismiss="modal" />
</div>
</div>
</div>
I created a map where you can book bikes via Javascript.
The user is supposed to :
1) select a bike station (green station = bikes are available)
2) click on a button (reserver button)
3) sign in a canvas (in a modal)
The page is here :
http://p4547.phpnet.org/bikes/reservation.html
In my javascript, the Class Object is called this way :
document.addEventListener("DOMContentLoaded", event => {
new Signature();
This code is working fine if the canvas is located in the body of the page.
But the code is not working if the canvas is located in the modal.
I tried to code this way :
$('#bookingmodal').on('shown.bs.modal',function(event){
new Signature();
});
My modal ID is : #bookingmodal
Your problem is in the calculation of the coordinates for the mouse-position inside the canvas. If you resize the page to a really small window the drawing sometimes works (with an ugly offset).
I took your Signature-class and replaced the calculation for the mouse-position inside the canvas with a function that calculates the correct position of the mouse and also handles possible scaling of the bitmap used by the canvas:
updateMousePosition(mX, mY) {
let rect = this.canvas.getBoundingClientRect();
let scaleX = this.canvas.width / rect.width;
let scaleY = this.canvas.height / rect.height;
this.cursorX = (mX - rect.left) * scaleX;
this.cursorY = (mY - rect.top) * scaleY;
}
Example:
class Signature {
constructor() {
this.color = "#000000";
this.sign = false;
this.begin_sign = false;
this.width_line = 5;
this.canvas = document.getElementById('canvas');
this.offsetLeft = this.canvas.offsetLeft;
this.offsetTop = this.canvas.offsetTop;
this.context = canvas.getContext('2d');
this.context.lineJoin = 'round';
this.context.lineCap = 'round';
this.whenMouseDown();
this.whenMouseUp();
this.whenMouseMove();
this.createSignature();
this.clearCanvas();
this.resetCanvas();
}
updateMousePosition(mX, mY) {
let rect = this.canvas.getBoundingClientRect();
let scaleX = this.canvas.width / rect.width;
let scaleY = this.canvas.height / rect.height;
this.cursorX = (mX - rect.left) * scaleX;
this.cursorY = (mY - rect.top) * scaleY;
}
whenMouseDown() {
document.addEventListener("mousedown", ({
pageX,
pageY
}) => {
this.sign = true;
this.updateMousePosition(pageX, pageY);
})
}
whenMouseUp() {
document.addEventListener("mouseup", () => {
this.sign = false;
this.begin_sign = false;
})
}
whenMouseMove() {
this.canvas.addEventListener('mousemove', ({
pageX,
pageY
}) => {
if (this.sign) {
this.updateMousePosition(pageX, pageY);
this.createSignature();
}
})
}
createSignature() {
if (!this.begin_sign) {
this.context.beginPath();
this.context.moveTo(this.cursorX, this.cursorY);
this.begin_sign = true;
} else {
this.context.lineTo(this.cursorX, this.cursorY);
this.context.strokeStyle = this.color;
this.context.lineWidth = this.width_line;
this.context.stroke();
}
}
clearCanvas() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
resetCanvas() {
document.getElementById("reset").addEventListener("click", () => {
this.clearCanvas();
})
}
}
document.addEventListener("DOMContentLoaded", event => {
new Signature();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
<button type="button" class="btn btn-success" data-target="#bookingmodal" data-toggle="modal">Réserver</button>
<div aria-labelledby="exampleModalLongTitle" class="modal fade" id="bookingmodal" role="dialog" tabindex="-1" style="display: none;" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLongTitle">Réservation</h5><button aria-label="Close" class="close" data-dismiss="modal" type="button"><span aria-hidden="true">×</span></button>
</div>
<div class="modal-body">
<div class="guide">
<div class="row item">
<div class="col-md-12 order-md-2">
<h2 class="item-heading">Signature. <span class="text-muted">Signez pour valider votre réservation.</span></h2>
<canvas id="canvas" width="250" height="250">
</canvas>
<form>
<input type="button" id="reset" value="Réinitialiser" class="btn btn-danger">
</form>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" data-dismiss="modal" type="button">Fermer</button>
</div>
</div>
</div>
</div>
I can not able to draw the full image using canvas. Here is my code:
<div class="form-group">
<label for="exampleInputEmail1">Coupon Title</label>
<input type="text" name="emails" id="copTitle" class="form-control" placeholder="Add Coupon Title" value="<?php echo $email; ?>" required>
</div>
<div class="couponimg" style="display:none;" id="blankImagediv">
<img class="img-responsive thumbnail" style="margin-bottom:9px; display:none;" src="http://oditek.inimages/coupon-banner-blank.jpg" crossorigin="anonymous" id="requiredImage">
<canvas id="canvas" class="img-responsive thumbnail" style="margin-bottom:9px;"></canvas>
</div>
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d');
canvas.width = $('#requiredImage').width();
canvas.crossOrigin = "Anonymous";
canvas.height = $('#requiredImage').height();
ctx.drawImage($('#requiredImage').get(0), 0, 0);
ctx.font = ":26pt Calibri";
$(document).on('input','#copTitle',function(){
$('#blankImagediv').css('display','block');
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.drawImage($('#requiredImage').get(0), 0, 0);
ctx.fillStyle = "#0D5F90";
ctx.fillText($(this).val(),40,80);
})
Here I am getting the half of the image of original image while drawing. The right hand side of the image is not displaying.
hi try with following code...
var canvas = document.getElementById('canvas'),
img = document.getElementById('requiredImage'),
ctx = canvas.getContext('2d');
img.onload = drawImage;
canvas.width = img.width;
canvas.height = img.height;
ctx.font = ":26pt Calibri";
$(document).on('input', '#copTitle', function() {
$('#blankImagediv').css('display', 'block');
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, 0, 0);
ctx.fillStyle = "#0D5F90";
ctx.fillText($(this).val(), 40, 80);
});
function drawImage()
{
ctx.drawImage(img, 0, 0);
}
Right now i have a form where i can enter some text and it appears in a canvas element,
however when i press backspace the text doesn't go away anymore and when i retype text it appears on top of the old text.
Is there a way to get the canvas element to respond to deleting text also?
<!DOCTYPE html>
<html>
<title>dropIn Print Generator</title>
<body>
<h1>dropIn Print Generator</h1>
<form method="post" action="run.php">
<p>brand name
<input type="text" id="brand" onkeyup="showBrand(this.value)" /></p>
<p>product name
<input type="text" id="product" onkeyup="showProductName(this.value)" /></p>
<p>product details
<input type="text" id="details" onkeyup="showProductDetail(this.value)" /></p>
<p>product sku
<input type="text" id="sku" /></p>
<p>product image
<input type="file" id="image" /></p>
</form>
<canvas id="mainCanvas" width="400" height="600" style="border:1px solid #000000;"></canvas>
<script>
var canvas = document.getElementById('mainCanvas');
var context = canvas.getContext('2d');
// begin upper shape
context.beginPath();
context.moveTo(0, 0);
context.lineTo(400, 0);
context.lineTo(400, 300);
context.lineTo(380, 30);
context.lineTo(0, 50);
context.lineTo(0, 0);
// complete upper shape
context.closePath();
context.lineWidth = 1;
context.strokeStyle = 'black';
context.fillStyle = 'black';
context.fill();
context.stroke();
// begin bottom shape
context.beginPath();
context.moveTo(400, 600);
context.lineTo(200, 600);
context.lineTo(400, 585);
context.lineTo(400, 600);
// complete bottom shape
context.closePath();
context.lineWidth = 1;
context.strokeStyle = 'black';
context.fillStyle = 'black';
context.fill();
context.stroke();
function showBrand(str){
context.fillStyle = 'black';
context.font = '20px sans-serif';
context.textBaseline = 'bottom';
context.fillText(str, 30, 100);
}
function showProductName(str){
context.fillStyle = 'black';
context.font = '30px sans-serif';
context.textBaseline = 'bottom';
context.fillText(str, 30, 135);
}
function showProductDetail(str){
context.fillStyle = 'black';
context.font = '20px sans-serif';
context.textBaseline = 'bottom';
context.fillText(str, 30, 160);
}
</script>
</body>
</html>
You need to clear the canvas before each time you paint some new text onto it, otherwise anything you've already drawn on the canvas will remain and you'll be drawing on top of it.
function clearCanvas() {
// Redraw the background color over the top of the old text to 'clear' it.
context.fillStyle = '#fff';
context.fillRect(0, 0, canvas.width, canvas.height);
}
Add a call to this function to the start of your other 3 drawing functions.