How to overlay a canvas dynamically onto an image - javascript

I have an img tag and I need to draw on it with a transparent overlay.
I was thinking about a canvas mathing the image size and position, but because my context is dynamic I need to adjust there parameters with javascript.
I tried to work with canvas.style.left, canvas.style.top but they not seem to work as expected (canvas.style.left works only if I assign 0 to it).
Furthermore, when I assign the width and the height like this:
canvas.width = img.clientWidth
canvas.height = img.clientHeight
It seems not to get the right values.
I'm using DevExpress to dynamically load the BinaryImage from a Model fetched from a database, this is the portion of code:
<div class="container-fluid" style="margin: 10px; margin-bottom: 15px">
#if (Model.Image != null) {
Html.DevExpress().BinaryImage(
settings => {
settings.Name = "mapImage";
settings.Width = System.Web.UI.WebControls.Unit.Percentage(100);
}).Bind((Model.Image).ToArray()).GetHtml();
<canvas id="mapOverlay" ></canvas>
}
</div>
Note that the DevExpress code results in the following img element:
<img class="dxeImage_Material" id="mapImage" src="/DXB.axd?DXCache=e86a5e5f-7d8b-4704-9330-ec7b9fa2ad38" alt="" style="width:100%;">
Is there any DevExpress component to use I may not be aware of that I could use?
EDIT
Following this code:
function DrawPoint(x, y, z) {
$("#myModal").modal("show");
var canvas = document.getElementById("mapOverlay");
var c = canvas.getContext('2d');
console.log("Setting canvas stuff");
var img = document.getElementById('myMap');
console.log("Image x: " + img.x)
console.log("Image y: " + img.y)
canvas.width = img.width;
canvas.height = img.height;
canvas.style.left = img.x + "px";
canvas.style.top = img.y + "px";
clearCanvas();
c.beginPath();
c.arc(x, y, 10, 0, Math.PI * 2, false);
c.fillStyle = "red";
c.fill();
c.stroke();
c.closePath();
}
The console.logs inside the function tells me that img.x and img.y are both 0, but if I get their values from the console in my browser they have some value.
What can this be?

Note that the canvas width/height attributes are different from canvas width/height styles. Attributes effect drawing, while style effects rendering. See below:
document.addEventListener("DOMContentLoaded", function(event) {
var drawStuff = function(canvas, context) {
context.rect(0, 0, 100, 100);
context.stroke();
}
var imageMouseEnter = function(event) {
var image = event.target;
var canvas = document.getElementById("overlay");
var context = canvas.getContext("2d");
canvas.style.left = image.x + "px";
canvas.style.top = image.y + "px";
canvas.style.width = image.width + "px";
canvas.style.height = image.height + "px";
drawStuff(canvas, context);
};
var imageMouseExit = function(event) {
};
var images = document.getElementsByTagName('img');
for(var i = 0; i < images.length; i++) {
images[i].addEventListener('mouseover', imageMouseEnter);
images[i].addEventListener('mouseout', imageMouseExit);
}
});
<canvas id="overlay" width="100" height="100" style="position:absolute"></canvas>
<div style="width:350px">
<img src="http://via.placeholder.com/350x150" />
<img src="http://via.placeholder.com/145x100" />
<img src="http://via.placeholder.com/200x100" />
<img src="http://via.placeholder.com/350x65" />
</div>

Related

How to rotate dynamic text from input in Canvas and JS?

I'm working on a box styling project with Canvas and Javascript, and I can't rotate the text the way I want (written from bottom to the top).
(source: hostpic.xyz)
I followed a tutorial (https://newspaint.wordpress.com/2014/05/22/writing-rotated-text-on-a-javascript-canvas/) and tried to adapt it in my code, but I couldn't make it.
You can find the code on the JSFiddle link below, there's an input where you can type your text and it should be written as the "brand" word in the JSFiddle example.
https://jsfiddle.net/ParkerIndustries/mgne9x5u/5/
Everything is in the init() function:
function init() {
var elem = document.getElementById('elem');
var circle_canvas = document.createElement("canvas");
var context = circle_canvas.getContext("2d");
var img = new Image();
img.src = "https://unblast.com/wp-content/uploads/2018/11/Vertical-Product-Box-Mockup-1.jpg";
context.drawImage(img, 0, 0, 500, 650);
circle_canvas.width = 500;
circle_canvas.height = 650;
context.fillStyle = "#000000";
//context.textAlign = 'center';
var UserInput = document.getElementById("UserInput");
context.save();
context.translate( circle_canvas.width - 1, 0 );
UserInput.oninput = function() {
context.clearRect(0, 0, 500, 650);
context.drawImage(img, 0, 0, 500, 650);
var text = UserInput.value;
console.log(text);
if (text.length < 12) {
context.rotate(3*Math.PI/2);
console.log("-12");
context.font = "50px Righteous";
context.fillText(text, -350, -170);
context.restore();
} else {
context.rotate(3*Math.PI/2);
context.font = "25px Righteous";
context.fillText(text, -350, -170);
context.restore();
}
}
elem.appendChild(circle_canvas);
}
init();
I tried a lot a values in the context.rotate() function but in any way my text is upside down.
(source: hostpic.xyz)
You're pretty close here. I suggest performing the canvas translation to the middle of the screen (width / 2, height / 2) and then rotating by 270 degrees:
context.translate(canvas.width / 2, canvas.height / 2);
context.rotate(270 * Math.PI / 180);
Beyond that, I recommend a round of code cleanup to avoid inconsistent variable names and hardcoded numbers (try to make everything proportional to img.width and img.height, then avoid literal values. This makes it easier to adjust your code dynamically without having to re-type all of the values. You can access img.width and img.height after the img.onload function fires.
Another useful function is context.measureText(text), which makes it simpler to proportionally scale text size.
Full example:
function init() {
var userInput = document.getElementById("user-input");
var elem = document.getElementById("elem");
var canvas = document.createElement("canvas");
var context = canvas.getContext("2d");
var img = new Image();
img.onload = function () {
canvas.width = img.width / 3;
canvas.height = img.height / 3;
context.drawImage(img, 0, 0, canvas.width, canvas.height);
context.fillStyle = "#000000";
context.textAlign = "center";
elem.appendChild(canvas);
userInput.oninput = function () {
var text = userInput.value;
var textSizePx = 50 - context.measureText(text).width / 10;
context.font = textSizePx + "px Righteous";
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(img, 0, 0, canvas.width, canvas.height);
context.save();
context.translate(canvas.width / 2, canvas.height / 2);
context.rotate(270 * Math.PI / 180);
context.fillText(text, 0, -canvas.width / 20);
context.restore();
}
};
img.src = "https://unblast.com/wp-content/uploads/2018/11/Vertical-Product-Box-Mockup-1.jpg";
}
init();
<div id="elem">
<input type="text" id="user-input" maxlength="15">
</div>
With that proof-of-concept working, one problem is that scaling the image on canvas causes visual artifacts. This problem can be overcome with JS or by scaling down the source image itself, but at this point, it's best to make the image as an element and circumvent the entire problem.
Similarly, there's no obvious reason to render text on canvas either; we can make an element for this as well. Moving text to HTML/CSS gives more power over how it looks (I didn't do much with style here, so it's an exercise to make it blend more naturally into the image).
Here's a rewrite without canvas that looks much cleaner and should be more maintainable:
function init() {
var userInput = document.querySelector("#user-input");
var img = document.querySelector("#product-img");
var imgRect = img.getBoundingClientRect();
var overlayText = document.querySelector("#overlay-text");
var overlay = document.querySelector("#overlay");
overlay.style.width = (imgRect.width * 0.86) + "px";
overlay.style.height = imgRect.height + "px";
userInput.addEventListener("input", function () {
overlayText.innerText = userInput.value;
overlayText.style.fontSize = (50 - userInput.value.length * 2) + "px";
});
}
init();
#product-img {
position: absolute;
}
#overlay {
position: absolute;
display: flex;
}
#overlay-text {
font-family: Verdana, sans-serif;
color: #333;
transform: rotate(270deg);
margin: auto;
cursor: default;
}
<div>
<input type="text" id="user-input" maxlength="15">
</div>
<div id="product-container">
<img id="product-img" src="https://unblast.com/wp-content/uploads/2018/11/Vertical-Product-Box-Mockup-1.jpg" width=666 height=500 />
<div id="overlay">
<div id="overlay-text"></div>
</div>
</div>

How to center the image inside of canvas in javascript?

I have a problem with centring the image inside of the canvas. Canvas has to be full sized. The whole thing should create a web preloader. Styling image inside of css does not work in this case.
<style> canvas{
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #000000;
z-index: 99; }
</style> <body>
<canvas id="c"><img id="logo" width="800" height="150" src="imgsource" alt="logo"></canvas> <div> web content </div>
<script>
jQuery(window).on('load', function() {
jQuery('#c').delay(7000).fadeOut('slow');
jQuery('body').delay(7000).css({'overflow':'visible'});
})
window.onload = function() {
var c = document.getElementById("c");
var ctx = c.getContext("2d");
var img = document.getElementById("logo");
ctx.drawImage(img, 50, 0);
} </script>
The following only demonstrates the centering of an image inside a canvas with drawImg. Note that the image to the left is from the html <img> element while the other is from the drawImg call.
Outside of stackoverflow you'd have to wait for the image to load before drawing it, but as you also already use .on('load', ...) i assume you are aware of that.
To avoid having two images, create the image element in javascript and don't add it to the document but only use it for rendering.
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
let img = document.getElementById("i");
//just to make the area the canvas occupies visible
ctx.fillStyle = 'grey';
ctx.fillRect(0, 0, canvas.width, canvas.height);
//draw the image centered
ctx.drawImage(
img,
canvas.width / 2 - img.width / 2,
canvas.height / 2 - img.height / 2
);
<html>
<body>
<img id="i" src="http://i.imgur.com/kdJicdy.png"/>
<canvas id="canvas" width="320" height="240">Your browser doesn't support canvas</canvas>
</body>
</html>
var canvas = document.getElementById('canvas');
var image = new Image();
image.src = 'http://placehold.it/300x550';
image.onload = function () {
var canvasContext = canvas.getContext('2d');
var wrh = image.width / image.height;
var newWidth = canvas.width;
var newHeight = newWidth / wrh;
if (newHeight > canvas.height) {
newHeight = canvas.height;
newWidth = newHeight * wrh;
}
var xOffset = newWidth < canvas.width ? ((canvas.width - newWidth) / 2) : 0;
var yOffset = newHeight < canvas.height ? ((canvas.height - newHeight) / 2) : 0;
canvasContext.drawImage(image, xOffset, yOffset, newWidth, newHeight);
};
<canvas id="canvas" width="500" height="500" style="border: 1px solid black" />

How can I make multiple overlaying canvases go fullscreen together and stay overlayed?

I want to make all overlapped HTML5 canvases full-screen when a button is clicked and I want them to stay overlapped when in full-screen mode.
For example I have 3 overlapped canvases. This example came from this site:
HTML
<section>
<div id="canvasesdiv" style="position:relative;width:400px;height:300px">
<canvas id="layer1" style="z-index: 1;position:absolute;left:0px;top:0px;" height="300px" width="400">
This text is displayed if your browser does not support HTML5 Canvas.
</canvas>
<canvas id="layer2" style="z-index: 2;position:absolute;left:0px;top:0px;" height="300px" width="400">
This text is displayed if your browser does not support HTML5 Canvas.
</canvas>
<canvas id="layer3" style="z-index: 3;position:absolute;left:0px;top:0px;" height="300px" width="400">
This text is displayed if your browser does not support HTML5 Canvas.
</canvas>
</div>
<div>
<p>
<button onclick="goFullScreen();">Go Fullscreen</button>
</p>
</div>
...
JavaScript
var layer1;
var layer2;
var layer3;
var ctx1;
var ctx2;
var ctx3;
var x = 400;
var y = 300;
var dx = 2;
var dy = 4;
var WIDTH = 400;
var HEIGHT = 300;
var city = new Image();
function init() {
city.src = "http://html5.litten.com/layers/city.png";
layer1 = document.getElementById("layer1");
ctx1 = layer1.getContext("2d");
layer2 = document.getElementById("layer2");
ctx2 = layer2.getContext("2d");
layer3 = document.getElementById("layer3");
ctx3 = layer3.getContext("2d");
setInterval(drawAll, 20);
}
function drawAll() {
draw1();
draw2();
draw3();
}
function draw1() {
ctx1.clearRect(0, 0, WIDTH, HEIGHT);
ctx1.fillStyle = "#FAF7F8";
ctx1.beginPath();
ctx1.rect(0, 0, WIDTH, HEIGHT);
ctx1.closePath();
ctx1.fill();
ctx1.fillStyle = "#444444";
ctx1.beginPath();
ctx1.arc(x, y, 10, 0, Math.PI * 2, true);
ctx1.closePath();
ctx1.fill();
if (x + dx > WIDTH || x + dx < 0)
dx = -dx;
if (y + dy > HEIGHT || y + dy < 0)
dy = -dy;
x += dx;
y += dy;
}
function draw2() {
ctx2.clearRect(0, 0, WIDTH, HEIGHT);
ctx2.drawImage(city, 0, 0);
}
function draw3() {
ctx3.clearRect(0, 0, WIDTH, HEIGHT);
ctx3.fillStyle = "#444444";
ctx3.save();
ctx3.translate(200, 200);
ctx3.rotate(x / 20);
ctx3.fillRect(-15, -15, 30, 30);
ctx3.restore();
}
function goFullScreen() {
var canvas1 = document.getElementById("layer1");
var canvas2 = document.getElementById("layer2");
var canvas3 = document.getElementById("layer3");
if (canvas1.requestFullScreen){
canvas1.requestFullScreen();
canvas2.webkitRequestFullScreen();
canvas3.webkitRequestFullScreen();
}
else if (canvas1.webkitRequestFullScreen){
canvas1.webkitRequestFullScreen();
canvas2.webkitRequestFullScreen();
canvas3.webkitRequestFullScreen();
}
else if (canvas1.mozRequestFullScreen){
canvas1.mozRequestFullScreen();
canvas2.webkitRequestFullScreen();
canvas3.webkitRequestFullScreen();
}
}
init();
I have tried to implement what discussed in this answer.
I tried to modify the goFullScreen() function is you can see above. But this only make the first canvas full-screen.
Thank your very much for your help.
You will have to request the fullscreen from the parent div and set canvas elements' width to 100% in CSS :
Style :
div:-webkit-full-screen>canvas {
width: 100% !important;
}
div:-moz-full-screen>canvas {
width: 100% !important;
}
div:-ms-fullscreen>canvas {
width: 100% !important;
}
div:fullscreen>canvas {
width: 100% !important;
}
Js :
function goFullScreen() {
var parentDiv = document.getElementById("canvasesdiv");
if (parentDiv.requestFullscreen){
parentDiv.requestFullscreen();}
else if(parentDiv.webkitRequestFullscreen){
parentDiv.webkitRequestFullscreen();
} else if(parentDiv.mozRequestFullScreen){
parentDiv.mozRequestFullScreen();
}
}

Trouble with getting Canvas Data after Drawing image

This code works well as it shoulds:
<script type="text/javascript">
var canvas = document.createElement("canvas");
canvas.id = "myCanvas";
canvas.style.height = "640px";
canvas.style.width = "384px";
canvas.style.position = "absolute";
canvas.style.border = "1px solid black";
document.body.appendChild(canvas);
var context = canvas.getContext('2d');
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
canvas.addEventListener('mousemove', function(evt) {
var mousePos = getMousePos(canvas, evt);
var message = 'Mouse position: ' + mousePos.x + ',' + mousePos.y;
var imgd = context.getImageData(mousePos.x, mousePos.y, 1, 1);
var pix = imgd.data;
document.getElementById("listener").innerHTML = "<b><i>" + message + "<br>" + pix[3] + "</i></b>";
}, false);
</script>
<div id="listener" >
</div>
It basically writes the mouse Position to the "listener" div and the alpha of the current pixel (as long as there is no content, it's - of course - 0)
But when i add this code:
var img = new Image();
img.src = 'http://www.animefighters.de/images/armor_leatherbelly.png';
context.drawImage(img, 0, 0);
There wouldn't happen anything...
What am i doing wrong? Where is the mistake?
I want to draw some images to the canvas and, after that, get the pixel data (including mouse Position and alpha of the pixel) ...
how can i realize that?
You're trying to draw the image on the canvas before it is loaded, you need to draw it onload:
var img = new Image();
img.onload = function() {
context.drawImage(img, 0, 0);
}
img.src = 'http://www.animefighters.de/images/armor_leatherbelly.png';

draw on image using canvas

I have a picture which which is loaded like this:
<img src="map/racetrack.jpg" id="map">
And here is my drawing function:
this.drawRoute = function(){
var pos = [];
var canvas = $('<canvas/>')[0];
var img = $('#map')[0];
var ctx = canvas.getContext("2d");
canvas.width = img.width;
canvas.height = img.height;
$(window).on('mousedown', function(e){
pos.push({
x: e.clientX,
y: e.clientY
});
});
if (positions.length > 1) {
ctx.beginPath();
ctx.moveTo(pos[0].x, pos[0].y);
for (var i = 1; i < pos.length; i++) {
ctx.lineTo(pos[i].x, pos[i].y);
}
ctx.stroke();
}
}
But nothing is drawn on the picture. I can't see where the mistake is. I know usually I'm supposed to use <canvas> element, but I only need this particular part done in canvas, nothing else.
Here's the fiddle
Well a few things first you have no canvas element. Secondly I didnt see where you were calling the draw portion.
Live Demo
What I ended up doing was adding a canvas element, hiding the image, and then every time you draw it draws the image to the canvas, and then draws the points over it. This should hopefully be enough to get you started.
var pos = [];
var canvas = $('#canvas')[0];
var img = $('#map')[0];
var ctx = canvas.getContext("2d");
canvas.width = img.width;
canvas.height = img.height;
function render() {
ctx.drawImage(img, 0, 0);
if (pos.length > 1) {
ctx.beginPath();
ctx.moveTo(pos[0].x, pos[0].y);
for (var i = 1; i < pos.length; i++) {
ctx.lineTo(pos[i].x, pos[i].y);
}
ctx.stroke();
}
}
$(window).on('mousedown', function (e) {
pos.push({
x: e.clientX,
y: e.clientY
});
render();
});
render();

Categories

Resources