Image not appearing in canvas - sometimes - javascript

This works great on all of my tests, but on the live system, I have a problem.
There are three separate but identical canvases. They are all initially painted with 640x480 jpg images. The third is then updated every second with a new 640x480 jpg image.
For some reason, the original static image for the third canvas - and that canvas only - doesn't load from the live server, only on the tests.
Here's the html:
<div style="padding: 1vw;">
<a href="/virtualscribe" class="camLink">
<div class="camDiv">
<div class="camBox" id="picBoxLeft">
<canvas id="canvasLeft" class="camBorder"></canvas>
</div>
</div>
</a>
<a href="/videos" class="camLink">
<div class="camDiv">
<div class="camBox" id="picBoxCenter">
<canvas id="canvasCenter" class="camBorder"></canvas>
</div>
</div>
</a>
<div class="camDiv">
<div class="camBox" id="picBoxRight">
<canvas id="canvasRight" class="camBorder"></canvas>
</div>
</div>
</div>
Here's the CSS:
<style>
.camBox {
max-width: 28vw;
width: 28vw;
height: 21vw;
max-height: 21vw;
display: inline-block;
}
.camDiv {
padding: 1.5vw;
display: inline-block;
}
.camBorder {
border: 0.6vw solid #fe890f;
border-top-left-radius: 3.3vw;
border-bottom-right-radius: 3.3vw;
}
.camLink {
color: transparent;
}
</style>
And here's the JavaScript:
var refreshTimer;
var imgLiveCam;
function drawPictureBox(img, canvas, text) {
var context = canvas.getContext("2d");
context.drawImage(img, 0, 0, canvas.width, canvas.height);
context.globalAlpha = 0.6;
context.fillStyle = "rgb(244,121,32)";
context.fillRect(0, canvas.height * 0.67, canvas.width, canvas.height * 0.33);
context.globalAlpha = 1;
var maxWidth = canvas.width;
var x = canvas.width / 2;
var y = canvas.height * 0.85;
context.font = canvas.width / 12 + 'px Oswald';
context.strokeStyle = 'black';
context.lineWidth = 2;
context.textAlign = "center";
context.strokeText(text, x, y, maxWidth);
context.fillStyle = 'white';
context.fillText(text, x, y, maxWidth);
};
function drawCamBox(img, logo, canvas) {
var context = canvas.getContext("2d");
context.drawImage(img, 0, 0, canvas.width, canvas.height);
context.globalAlpha = 0.6;
context.fillStyle = "rgb(244,121,32)";
context.fillRect(0, canvas.height * 0.67, canvas.width, canvas.height * 0.33);
var eSize = canvas.height / 10;
context.globalAlpha = 1;
context.drawImage(logo, 2, canvas.height * 0.67 - eSize, eSize, eSize);
var now = new Date();
var text = now.toLocaleDateString() + " " + now.toLocaleTimeString();
var maxWidth = canvas.width * 0.33;
var x = canvas.width - 10 - maxWidth;
var y = canvas.height * 0.67 - 10;
context.font = maxWidth / 10 + "px Arial";
context.strokeStyle = 'black';
context.lineWidth = 2;
context.strokeText(text, x, y, maxWidth);
context.fillStyle = 'white';
context.fillText(text, x, y, maxWidth);
text = 'View Our Production Floor';
context.textAlign = "center";
maxWidth = canvas.width;
x = canvas.width / 2;
y = canvas.height * 0.85;
context.font = canvas.width / 12 + 'px Oswald';
context.strokeText(text, x, y, maxWidth);
context.fillText(text, x, y, maxWidth);
}
function addResizeListener(fn) {
if (window.attachEvent) {
window.attachEvent('onresize', fn)
} else if (window.addEventListener) {
window.addEventListener('resize', fn, true);
};
}
function initCam() {
var imgLeft = new Image();
imgLeft.onload = function () {
var canvas = document.getElementById("canvasLeft");
var picBox = document.getElementById("picBoxLeft");
var drawFn = function () {
canvas.height = picBox.clientHeight;
canvas.width = picBox.clientWidth;
drawPictureBox(imgLeft, canvas, 'Looking for a Scribe?');
};
drawFn();
addResizeListener(drawFn);
}
var imgCenter = new Image();
imgCenter.onload = function () {
var canvas = document.getElementById("canvasCenter");
var picBox = document.getElementById("picBoxCenter");
var drawFn = function () {
canvas.height = picBox.clientHeight;
canvas.width = picBox.clientWidth;
drawPictureBox(imgCenter, canvas, 'Watch In-Depth Videos');
};
drawFn();
addResizeListener(drawFn);
}
imgLiveCam = new Image();
var logo = new Image();
logo.src = "e.png";
imgLiveCam.onload = function () {
var canvas = document.getElementById("canvasRight");
var picBox = document.getElementById("picBoxRight");
var drawFn = function () {
canvas.height = picBox.clientHeight;
canvas.width = picBox.clientWidth;
drawCamBox(imgLiveCam, logo, canvas);
};
drawFn();
imgLiveCam.onload = drawFn;
addResizeListener(drawFn);
}
imgLeft.src = "scribe.jpg";
imgCenter.src = "doc-with-spine.jpg";
imgLiveCam.src = "camloading.jpg";
refreshTimer = setTimeout(refresh, 499);
}
function refresh() {
clearTimeout(refreshTimer);
imgLiveCam.src = "http://cams.edataservices.com/17fcam.jpg?t=" + new Date().getTime();
refreshTimer = setTimeout(refresh, 1009);
}
Any idea why the third canvas starts out blank most of the time?

By adding a longer delay before starting the refresh cycle, the browsers had more time to load the initial, "default" image. I set it at 1500ms, and now it is pretty reliable.
(Thanks for the help...)

Related

How to make the matrix background render behind page content?

I wanted to use this cool matrix background for my web application but it covers all of my elements(div's, headers, paragraphs etc.).
I've tried to fix this with css but it doesn't work.
So now I'm stuck and asking you for help.
Here is my code from CodePen:
const canvas = document.getElementById('canv');
const ctx = canvas.getContext('2d');
const w = canvas.width = document.body.offsetWidth;
const h = canvas.height = document.body.offsetHeight;
const cols = Math.floor(w / 20) + 1;
const ypos = Array(cols).fill(0);
ctx.fillStyle = '#000';
ctx.fillRect(0, 0, w, h);
function matrix () {
ctx.fillStyle = '#0001';
ctx.fillRect(0, 0, w, h);
ctx.fillStyle = '#0f0';
ctx.font = '15pt monospace';
ypos.forEach((y, ind) => {
const text = String.fromCharCode(Math.random() * 128);
const x = ind * 20;
ctx.fillText(text, x, y);
if (y > 100 + Math.random() * 10000) ypos[ind] = 0;
else ypos[ind] = y + 20;
});
}
setInterval(matrix, 50);
body {
margin: 0;
height: 100vh;
width: 100vw;
}
.container{
background-color: white;
}
<canvas id='canv'>
<div class='container'>
<p>Some div with login in</p>
</div>
</canvas>
Is there someway to fix it?
Thanks for your attention and help.
Here's a possible solution:
const canvas = document.getElementById('canv');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const ctx = canvas.getContext('2d');
let cols = Math.floor(window.innerWidth / 20) + 1;
let ypos = Array(cols).fill(0);
ctx.fillStyle = '#000';
ctx.fillRect(0, 0, canvas.width, canvas.height);
function matrix () {
const w = window.innerWidth;
const h = window.innerHeight;
if (canvas.width !== w) {
canvas.width = w;
cols = Math.floor(window.innerWidth / 20) + 1;
ypos = Array(cols).fill(0);
}
if (canvas.height !== h) {
canvas.height = h;
}
ctx.fillStyle = '#0001';
ctx.fillRect(0, 0, w, h);
ctx.fillStyle = '#0f0';
ctx.font = '15pt monospace';
ypos.forEach((y, ind) => {
const text = String.fromCharCode(Math.random() * 128);
const x = ind * 20;
ctx.fillText(text, x, y);
if (y > 100 + Math.random() * 10000) ypos[ind] = 0;
else ypos[ind] = y + 20;
});
}
setInterval(matrix, 50);
body {
margin: 0;
background-color: #000;
}
.container {
background-color: rgba(255, 255, 255, 0.85);
margin: 50px 10%;
padding: 3rem;
position: relative;
z-index: 1;
}
#canv {
position: fixed;
top: 0;
left: 0;
}
<canvas id='canv'></canvas>
<div class='container'>
<p>Some div with login in</p>
</div>
Play around with the CSS of .container to make it look like you want. Don't remove the position and z-index (they are needed to keep it on top of the <canvas>).
Note: The CSS required to place .container on top is rather simple and it's not the reason I added the answer for.
The reason is because your matrix script was not responsive. I made minor mods to it and it now resizes when viewport size changes.
Welcome to SO.

Canvas zoom with stroke and text

I want zoom images, lines, and text drawn on a canvas
Click plus button > zoom in
Click minus button > zoom out
I tried scale but only the image got bigger.
test.html
<canvas id="img"></canvas>
<input type="button" id="plus" value="plus">
<input type="button" id="minus" value="minus">
<script>
const canvas = document.getElementById('img');
const ctx = canvas.getContext('2d');
const img = new Image();
img.src = 'test.PNG';
img.onload = function() {
canvas.height = img.height;
canvas.width = img.width;
ctx.drawImage(img, 0, 0);
ctx.lineWidth = 3;
ctx.strokeStyle = 'red';
ctx.strokeRect(28, 26, 50, 50);
ctx.textBaseline = 'top';
ctx.font="15px Verdana";
ctx.fillStyle = 'red';
ctx.fillText("TEXT", 28, 25 + 50 + 5);
ctx.fill();
ctx.scale(2,2);
ctx.restore();
};
</script>
<script>
const plus = document.getElementById('plus');
const minus = document.getElementById('minus');
</script>
The problem is - as Kaiido implied in his comment - that the scale() method doesn't affect anything thas has been drawn onto the canvas prior the call to scale.
If you really want a context.scale driven zoom function you will have to redraw anything after calling scale.
Here's an example:
const canvas = document.getElementById('img');
const ctx = canvas.getContext('2d');
function zoomIn() {
myScale = myScale < 2.5 ? myScale += 0.5 : 2.5;
draw();
}
function zoomOut() {
myScale = myScale > 0.5 ? myScale -= 0.5 : 0.5;
draw();
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();
ctx.translate(canvas.width / 2 - canvas.width / 2 * myScale, canvas.height / 2 - canvas.height / 2 * myScale);
ctx.scale(myScale, myScale);
ctx.drawImage(img, 0, 0);
ctx.lineWidth = 3;
ctx.strokeStyle = 'red';
ctx.strokeRect(28, 26, 50, 50);
ctx.textBaseline = 'top';
ctx.font = "15px Verdana";
ctx.fillStyle = 'red';
ctx.fillText("TEXT", 28, 25 + 50 + 5);
ctx.fill();
ctx.restore();
}
var img = new Image();
var myScale = 1;
img.onload = function() {
canvas.height = img.height;
canvas.width = img.width;
draw();
};
img.src = 'https://picsum.photos/id/1/200/300';
const plus = document.getElementById('plus');
const minus = document.getElementById('minus');
plus.addEventListener("click", zoomIn);
minus.addEventListener("click", zoomOut);
<canvas id="img"></canvas>
<input type="button" id="plus" value="plus">
<input type="button" id="minus" value="minus">

change shapre of img

I need help with Transform moving square image to circle in html canvas
I have imported a image that is a square. I want that image be round and still move.
Goal:
square image to circle image, and still able to move.
I have tried alot of tutorial on stackoverflow mainly with c. stroke and c.split but when I apply those the image doesnt move anymore.
Does someone have any suggestions?
var canvas = document.querySelector('canvas');
var c = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
function Circle() {
//Give var for circle
this.x = 10;
this.y = 100;
this.dx = 1;
this.dy = 1;
this.radius = 50;
this.diameter = 2 * this.radius;
//Get external square picture (Needs to be converted in circle)
var image = new Image();
image.src = "https://assets.coingecko.com/coins/images/2607/large/molecular_future.png?1547036754";
//Draw circle on canvas
this.draw = function () {
//Circle
c.beginPath();
c.arc(this.x, this.y, (this.radius*1), 0, Math.PI * 2, false);
c.closePath();
//TODO: cut square to circle
//Place square (image) on top of the circle
c.drawImage(image, (this.x-this.diameter/2) , (this.y-this.diameter/2), this.diameter, this.diameter);
};
//Update position
this.update = function () {
this.x += this.dx;
this.draw()
}
}
//Animate canvas
function animate() {
requestAnimationFrame(animate);
c.clearRect(0, 0, innerWidth, innerHeight);
this.update();
}
//Start
Circle();
animate();
canvas {
border: 1px solid black;
background: black;
}
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<canvas></canvas>
</body>
</html>
The answer is to use context.clip(); in your case c.clip(); this creates a clipping filter on the canvas that you can then draw in. Before you make a clip you must make a save and then restore after you draw with c.save(); and c.restore() respectively.
var canvas = document.querySelector('canvas');
var c = canvas.getContext('2d');
var circles = [];
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
function Circle() {
//Give var for circle
this.x = 100;
this.y = 100;
this.dx = 1;
this.dy = 1;
this.radius = 50;
this.diameter = 2 * this.radius;
this.size = null;
this.c = null;
//Get external square picture (Needs to be converted in circle)
var image = new Image();
image.src = "https://assets.coingecko.com/coins/images/2607/large/molecular_future.png?1547036754";
//Draw circle on canvas
this.draw = function () {
//Circle
this.c.beginPath();
this.c.arc(this.x, this.y, (this.radius*1), 0, Math.PI * 2, false);
this.c.closePath();
this.c.save();
this.c.clip();
//TODO: cut square to circle
//Place square (image) on top of the circle
this.c.drawImage(image, (this.x-this.diameter/2) , (this.y-this.diameter/2), this.diameter, this.diameter);
this.c.restore();
};
//Update position
this.update = function () {
if(this.x - this.radius <= 0 || this.x + this.radius >= this.size.x){this.dx = -this.dx}
this.x += this.dx;
this.draw()
}
this.init = function(options) {
Object.keys(options).forEach((key)=>{
this[key]=options[key];
})
}
}
//Animate canvas
function animate() {
requestAnimationFrame(animate);
c.clearRect(0, 0, innerWidth, innerHeight);
for(let i = 0; i < circles.length; i++){ circles[i].update(); }
}
//Start
for(let i = 0; i < 100; i-=-1){
let circle = new Circle();
circle.init({
x: Math.random() * window.innerWidth,
y: Math.random() * window.innerHeight,
size: {x: window.innerWidth,y: window.innerHeight},
c
})
circles.push(circle)
}
animate();
canvas {
border: 1px solid black;
background: black;
}
body {
margin: 0;
padding: 0;
overflow-x: hidden;
}
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<canvas></canvas>
</body>
</html>
Start by generating your composed image and then use it in your animation code.
To make such a compositing, you'd better use compositing than clipping, because clipping is an all or nothing operation, it won't deal well with the antialiasing required by a circle.
To store this composed image in a convenient way, you can either use a second canvas, or in newest browsers an ImageBitmap, both will then be drawable by drawImage.
Here is an ES5 implementation, using a second canvas and a callback:
// older browsers version
function makeCircleImage(radius, src, success, failure) {
var canvas = document.createElement('canvas');
canvas.width = canvas.height = radius * 2;
var ctx = canvas.getContext("2d");
var img = new Image();
img.src = src;
img.onload = function() {
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
// we use compositing, offers better antialiasing than clip()
ctx.globalCompositeOperation = 'destination-in';
ctx.arc(radius, radius, radius, 0, Math.PI*2);
ctx.fill();
success(canvas);
};
img.onerror = failure;
}
var url = "https://assets.coingecko.com/coins/images/2607/large/molecular_future.png?1547036754";
makeCircleImage( 50, url, function( canvas ) {
document.body.appendChild(canvas);
}, console.error );
canvas {
border: 1px solid black;
background: black;
}
And here is one that you can use in newest browsers which will store an ImageBitmap (preferable when available for memory and theoretical speed of drawing).
// newest browsers version
function makeCircleImage( radius, src ) {
return new Promise( (resolve, reject) => {
// this canvas will get Garbage Collected
const canvas = document.createElement( 'canvas' );
canvas.width = canvas.height = radius * 2;
const ctx = canvas.getContext( "2d" );
const img = new Image();
img.src = src;
img.onload = function() {
ctx.drawImage( img, 0, 0, canvas.width, canvas.height );
// we use compositing, offers better antialiasing than clip()
ctx.globalCompositeOperation = 'destination-in';
ctx.arc( radius, radius, radius, 0, Math.PI*2 );
ctx.fill();
resolve( createImageBitmap( canvas ) );
};
img.onerror = reject;
});
}
async function init() {
const url = "https://assets.coingecko.com/coins/images/2607/large/molecular_future.png?1547036754";
const img = await makeCircleImage(50, url);
document.querySelector('canvas')
.getContext('2d')
.drawImage(img, 0,0);
};
init().catch( console.error );
canvas {
border: 1px solid black;
background: black;
}
<canvas></canvas>
Now that we have a clear source ready to use, all our we have to do in the animation code is to put these pixels, without any heavy computation:
// older browsers version
function makeCircleImage(radius, src, callback) {
var canvas = document.createElement('canvas');
canvas.width = canvas.height = radius * 2;
var ctx = canvas.getContext("2d");
var img = new Image();
img.src = src;
img.onload = function() {
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
// we use compositing, offers better antialiasing than clip()
ctx.globalCompositeOperation = 'destination-in';
ctx.arc(radius, radius, radius, 0, Math.PI*2);
ctx.fill();
callback(canvas);
};
}
function Circle( x, y, radius ) {
//Give var for circle
this.x = x;
this.y = y;
this.dx = 1;
this.dy = 1;
this.radius = radius;
}
// use prototyping if you wish to make it a class
Circle.prototype = {
//Draw circle on canvas
draw: function () {
var
x = (this.x - this.radius),
y = (this.y - this.radius);
// draw is a single call
c.drawImage( this.image, x, y );
},
update: function () {
var
max_right = canvas.width + this.radius,
max_left = this.radius * -1;
this.x += this.dx;
if( this.x > max_right ) {
this.x += max_right - this.x;
this.dx *= -1;
}
if( this.x < max_left ) {
this.x += max_left - this.x;
this.dx *= -1;
}
},
init: function(callback) {
var url = "https://assets.coingecko.com/coins/images/2607/large/molecular_future.png?1547036754";
makeCircleImage( this.radius, url, function(img) {
this.image = img;
callback();
}.bind(this));
}
};
//Animate canvas
function animate() {
c.clearRect(0, 0, window.innerWidth, window.innerHeight);
circles.forEach(function( circle ) {
circle.update();
});
circles.forEach(function( circle ) {
circle.draw();
});
requestAnimationFrame(animate);
}
var canvas = document.querySelector('canvas');
var c = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var circles = [
new Circle(10, 100, 50),
new Circle(10, 200, 30),
new Circle(10, 300, 50)
];
var ready = 0;
circles.forEach(function(circle) {
circle.init(oncircledone);
});
function oncircledone() {
if(++ready === circles.length) {
animate()
}
}
canvas {
border: 1px solid black;
background: black;
}
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<canvas></canvas>
</body>
</html>
And for newest browsers:
// newest browsers version
function makeCircleImage( radius, src ) {
return new Promise( (resolve, reject) => {
// this canvas will get Garbage Collected
const canvas = document.createElement( 'canvas' );
canvas.width = canvas.height = radius * 2;
const ctx = canvas.getContext( "2d" );
const img = new Image();
img.src = src;
img.onload = function() {
ctx.drawImage( img, 0, 0, canvas.width, canvas.height );
// we use compositing, offers better antialiasing than clip()
ctx.globalCompositeOperation = 'destination-in';
ctx.arc( radius, radius, radius, 0, Math.PI*2 );
ctx.fill();
resolve( createImageBitmap( canvas ) );
};
img.onerror = reject;
});
}
class Circle {
constructor( x, y, radius ) {
this.x = x;
this.y = y;
this.dx = 1;
this.dy = 1;
this.radius = radius;
}
draw() {
const x = (this.x - this.radius);
const y = (this.y - this.radius);
c.drawImage( this.image, x, y );
}
update() {
const max_right = canvas.width + this.radius;
const max_left = this.radius * -1;
this.x += this.dx;
if( this.x > max_right ) {
this.x += max_right - this.x;
this.dx *= -1;
}
if( this.x < max_left ) {
this.x += max_left - this.x;
this.dx *= -1;
}
}
async init() {
const url = "https://assets.coingecko.com/coins/images/2607/large/molecular_future.png?1547036754";
this.image = await makeCircleImage( this.radius, url );
}
}
//Animate canvas
function animate() {
c.clearRect(0, 0, window.innerWidth, window.innerHeight);
circles.forEach( (circle) => circle.update() );
circles.forEach( (circle) => circle.draw() );
requestAnimationFrame(animate);
}
const canvas = document.querySelector('canvas');
const c = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const circles = [
new Circle(10, 50, 50),
new Circle(10, 150, 30),
new Circle(450, 250, 80)
];
Promise.all(circles.map( (circle) => circle.init() ))
.then(animate)
.catch(console.error);
canvas {
border: 1px solid black;
background: black;
}
<canvas></canvas>
But if you are going to have a lot of Circle instances and that they will only differ in their radius, but share the same original image's source, then you might prefer to store a single high quality version of the composed image and just rescale it in each instance's draw call.
// newest browsers version
function makeCircleImage( radius, src ) {
return new Promise( (resolve, reject) => {
// this canvas will get Garbage Collected
const canvas = document.createElement( 'canvas' );
canvas.width = canvas.height = radius * 2;
const ctx = canvas.getContext( "2d" );
const img = new Image();
img.src = src;
img.onload = function() {
ctx.drawImage( img, 0, 0, canvas.width, canvas.height );
// we use compositing, offers better antialiasing than clip()
ctx.globalCompositeOperation = 'destination-in';
ctx.arc( radius, radius, radius, 0, Math.PI*2 );
ctx.fill();
resolve( createImageBitmap( canvas ) );
};
img.onerror = reject;
});
}
(async () => {
const url = "https://assets.coingecko.com/coins/images/2607/large/molecular_future.png?1547036754";
const image = await makeCircleImage(250, url); // original size of the png image
class Circle {
constructor( x, y, radius ) {
this.x = x;
this.y = y;
this.dx = 1;
this.dy = 1;
this.radius = radius;
}
draw() {
const x = (this.x - this.radius);
const y = (this.y - this.radius);
// now they all use the same image
// with a bit more computation though due to resizing
c.drawImage( image, x, y , this.radius * 2, this.radius * 2);
}
update() {
const max_right = canvas.width + this.radius;
const max_left = this.radius * -1;
this.x += this.dx;
if( this.x > max_right ) {
this.x += max_right - this.x;
this.dx *= -1;
}
if( this.x < max_left ) {
this.x += max_left - this.x;
this.dx *= -1;
}
}
}
//Animate canvas
function animate() {
c.clearRect(0, 0, window.innerWidth, window.innerHeight);
circles.forEach( (circle) => circle.update() );
circles.forEach( (circle) => circle.draw() );
requestAnimationFrame(animate);
}
const canvas = document.querySelector('canvas');
const c = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const rand = (n) => Math.random() * n;
const circles = Array.from({ length: 50 })
.map( () =>
new Circle(
rand(canvas.width),
rand(canvas.height),
rand(125)
)
);
animate();
})()
.catch(console.error);
canvas {
border: 1px solid black;
background: black;
}
<canvas></canvas>

Unable to draw on the image after rotation it is drawing on the original canvas orientation

var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
var rw = 1560;
var rh = 2080;
var cw = "null";
var lw = "null";
var lh = "null";
var fh = "null";
var drag = false;
var last_mousex = last_mousey = 0;
var mousex = mousey = 0;
var mousedown = false;
var image = new Image();
image.src = "https://s3-us-west-2.amazonaws.com/s.cdpn.io/222579/darwin300.jpg"
image.onload = function(e) {
ctx.canvas.width = image.width;
ctx.canvas.height = image.height;
c.width = image.width;
c.height = image.height;
ctx.save();
if(rw) {
c.width = rh;
c.height = rw;
ctx.canvas.width = rh;
ctx.canvas.height = rw;
ctx.translate(rh, 0);
ctx.rotate((90 * Math.PI) / 180);
ctx.drawImage(image,0,0,rw,rh);
ctx.save();
}
else if(lw) {
c.width = lh;
c.height = lw;
ctx.canvas.width = lh;
ctx.canvas.height = lw;
ctx.translate(lw-lh, lw);
ctx.rotate((-90 * Math.PI) / 180);
ctx.translate(0,-(lw-lh));
ctx.drawImage(image,0,0,lw,lh);
ctx.save();
}
else if(fh) {
var maxsize = image.width;
var w = maxsize;
var ratio = (image.width / w);
var h = (image.height / ratio);
c.width = w;
c.height = h;
ctx.canvas.width = w;
ctx.canvas.height = h;
ctx.translate(w, h);
ctx.rotate(Math.PI);
ctx.drawImage(image,0,0,w,h);
ctx.save();
}
else {
ctx.canvas.width = image.width;
ctx.canvas.height = image.height;
c.width = image.width;
c.height = image.height;
ctx.drawImage(image, 0, 0);
ctx.save();
}
ctx.rect(200, 200, 550, 500);
ctx.strokeStyle = "green";
ctx.lineWidth = "5";
ctx.stroke();
};
function drawrect() {
$(c).on('mousedown', function(e) {
last_mousex = parseInt((image.width / c.scrollWidth) * e.offsetX);
last_mousey = parseInt((image.height / c.scrollHeight) * e.offsetY);
rx = last_mousex;
ry = last_mousey;
mousedown = true;
});
$(c).on('mouseup', function(e) {
last_mousex = parseInt((image.width / c.scrollWidth) * e.offsetX);
last_mousey = parseInt((image.height / c.scrollHeight) * e.offsetY);
mousedown = false;
if(!mousedown) {
redraw(last_mousex, last_mousey, ctx);
}
});
$(c).on('mousemove', function(e) {
mousex = parseInt((image.width / c.scrollWidth) * e.offsetX);
mousey = parseInt((image.height / c.scrollHeight) * e.offsetY);
if(mousedown) {
var width = mousex-last_mousex;
var height = mousey-last_mousey;
}
});
}
function redraw(tox, toy, ctx) {
ctx.beginPath();
ctx.restore();
ctx.rect(rx, ry, tox - rx, toy - ry);
ctx.strokeStyle = "black";
ctx.lineWidth = "3";
ctx.stroke();
ctx.closePath();
xMi = rx;
yMi = ry;
xMa = tox - rx;
yMa = toy - ry;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<canvas id="canvas" style="width:100%; height:80%; margin: 0; padding: 0;"></canvas>
<button type="button" id="drawrect" onclick="drawrect()" class="btn btn-default" style="float:left; margin-top: 20px;">Draw
<span class="glyphicon glyphicon-edit"> </span></button>
Rotation: 90 (right rotation), 180 (vertical rotation), -90 (left rotation).
Using canvas, added draw rectangle function which on using mouse event x and y coordinated draws rectangle on the canvas but it is unable to draw on the rotated canvas, it is able to correctly draw on the original image orientation.
The problem is that you transformed the canvas using the .translate() and .rotate() methods. The drawing still works though - it's just outside of the visible area.
To work around that you need to reset the transformation to the identity matrix.
Simply insert:
ctx.setTransform(1, 0, 0, 1, 0, 0);
at the end of your onload callback function.

Draw SVG on canvas [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 5 years ago.
I have a set of coordinates and for every pair I'd like to place a SVG on the canvas. The problem is in getCircle function. The SVG doesn't work, but if I draw a circle(see commented code) it works.
function getCircle() {
var circle = document.createElement("canvas"),
ctx = circle.getContext("2d"),
r2 = radius + blur;
circle.width = circle.height = r2 * 2;
/*
ctx.shadowOffsetX = ctx.shadowOffsetY = r2 * 2;
ctx.shadowBlur = blur;
ctx.shadowColor = "purple";
ctx.beginPath();
ctx.arc(-r2, -r2, radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
*/
var img = new Image();
img.onload = function() {
ctx.drawImage(img, 0, 0);
};
img.src = "https://upload.wikimedia.org/wikipedia/en/0/09/Circle_Logo.svg";
return circle;
}
var radius = 5;
var blur = 1;
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');
canvas.width = 400;
canvas.height = 200;
var circle = getCircle();
ctx.clearRect(0, 0, canvas.width, canvas.height);
var data = [[38,20,2]];
for (var i = 0, len = data.length, p; i < len; i++) {
p = data[i];
ctx.drawImage(circle, p[0] - radius, p[1] - radius);
}
#c {
width: 400px;
height: 200px;
}
<canvas id="c"></canvas>
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');
canvas.width = 400;
canvas.height = 200;
var data = [[0,20,2],[125,20,2],[250,20,2]];
drawImage();
function drawImage() {
var img = new Image();
img.onload = function() {
for (var i = 0, len = data.length, p; i < len; i++) {
p = data[i];
ctx.drawImage(this, p[0] , p[1] , 150, 150);
}
};
img.src = "https://upload.wikimedia.org/wikipedia/en/0/09/Circle_Logo.svg";
}
#c {
width: 400px;
height: 200px;
}
<canvas id="c"></canvas>
in img.onload() draw your image in specified position with widht and height using drawImage().

Categories

Resources