how to drawimage same with red block - javascript

A red block on image, size is 50*50, and image origin size is 320*180, image element size is 200*113
now I want to get the red block and draw on canvas, but I have no idea how to calculate, please let me know why and how!!
my sample code here
window.onload = function() {
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var img = document.getElementById("scream");
const naturalWidth = img.naturalWidth;
const naturalHeight = img.naturalHeight;
const ratio = naturalWidth / img.offsetWidth;
const heightRatio = naturalHeight / img.offsetHeight;
const canvasRatio = naturalWidth / c.width;
const canvasYRatio = naturalHeight / c.height;
console.log(ratio, heightRatio, canvasRatio);
const r = 1/(naturalWidth/naturalHeight);
console.log(r);
const width = 50;
const height = 50;
const top = 50 * heightRatio;
const left = 90 * ratio;
ctx.drawImage(img, -left, -top);
};
body{
position: relative;
}
<img id="scream" src="https://img.youtube.com/vi/uwMQRAC1JE8/mqdefault.jpg" alt="The Scream" width="200">
<div style="
position: absolute;
left: 90px;
top: 50px;
width: 50px;
height: 50px;
border: 1px solid red;
"></div>
<canvas id="myCanvas" width="50" height="50" style="border:1px solid #d3d3d3;display:block" />

You need to use the long version of ctx.drawImage(image, sx, sy, swidth, sheight, dx, dy, dwidth, dheight) in order to be able to crop and resize the original image.
The short 2 arguments version is simply drawing the original image at the orignal size, with some offset on the destination, but you need to apply the resizing on your output too.
So using the long version you can do
ctx.drawImage(img,
// source
x * ratioW,
y * ratioH,
width * ratioW,
height * ratioH,
// destination
0,
0,
width,
height
);
window.onload = function() {
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var img = document.getElementById("scream");
const naturalWidth = img.naturalWidth;
const naturalHeight = img.naturalHeight;
const ratio = naturalWidth / img.offsetWidth;
const heightRatio = naturalHeight / img.offsetHeight;
const canvasRatio = naturalWidth / c.width;
const canvasYRatio = naturalHeight / c.height;
const r = 1/(naturalWidth/naturalHeight);
console.log(r);
const width = 50;
const height = 50;
const top = 50 * heightRatio;
const left = 90 * ratio;
ctx.drawImage(
img,
left, top, width * ratio, height * heightRatio,
0, 0, width, height
);
};
body{
position: relative;
}
<img id="scream" src="https://img.youtube.com/vi/uwMQRAC1JE8/mqdefault.jpg" alt="The Scream" width="200">
<div style="
position: absolute;
left: 90px;
top: 50px;
width: 50px;
height: 50px;
border: 1px solid red;
"></div>
<canvas id="myCanvas" width="50" height="50" style="border:1px solid #d3d3d3;display:block" />

Related

getting canvas pixel data is wrong after setting it with css

i am trying to get the rgb color data from a painted canvas.
with this function:
function pick(event) {
var x = event.layerX;
var y = event.layerY;
var pixel = ctx.getImageData(x, y, 1, 1);
var data = pixel.data;
$("#color").val(pixel.data.toString());
console.log(pixel.data.toString());
}
however, when i am setting the canvas element to any relative width (80%/100%), like this:
canvas {
/*width: 100%;*/ /*when i set the width, the rgb values are incorrect .... */
/*margin-left: auto;
margin-right: auto;
display: block;*/
}
i am no longer getting correct values from this function.
attaching my JS Fiddle:
https://jsfiddle.net/iliran11/ay9nf1p9/
You need to find the difference in width when you stretch and multiply that to the coordinates.
//color names
var basecolors = ["(255,0,0)",
"(255,128,0)",
"(255,255,0)",
"(128,255,0)",
"(0,255,0)",
"(0,255,128)",
"(0,255,255)",
"(0,128,255)",
"(0,0,255)",
"(128,0,255)",
"(255,0,255)",
"(255,0,128)",
"(128,128,128)"
];
//init
var ctx = canvas.getContext("2d");
var width = canvas.width;
var height = canvas.height;
var heightPerColor = height / basecolors.length;
//init cursor
var xCursor = 0;
var yCursor = 0;
drawPallete(width, height, "s");
function drawPallete(width, height, type) {
canvas.width = width;
canvas.height = height;
ctx.clearRect(0, 0, canvas.width, canvas.height);
var Grad = ctx.createLinearGradient(0, 0, canvas.width, 0);
Grad.addColorStop(0 / 6, '#F00');
Grad.addColorStop(1 / 6, '#FF0');
Grad.addColorStop(2 / 6, '#0F0');
Grad.addColorStop(3 / 6, '#0FF');
Grad.addColorStop(4 / 6, '#00F');
Grad.addColorStop(5 / 6, '#F0F');
Grad.addColorStop(6 / 6, '#F00');
ctx.fillStyle = Grad;
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
;
function pick(event) {
var canvas = document.getElementById("canvas");
//Here comes the stretch offset
//var off = (1 / canvas.width) * canvas.offsetWidth;
var off = (1 / canvas.offsetWidth) * canvas.width;
//Applying offset
var x = Math.floor(event.layerX * off) - Math.floor(canvas.offsetLeft * off);
var y = Math.floor(event.layerY * off) - Math.floor(canvas.offsetTop * off);
var pixel = ctx.getImageData(x, y, 1, 1);
var data = pixel.data;
$("#color").val([pixel.data[0], pixel.data[1], pixel.data[2], pixel.data[3]].join(','));
//console.log("offset between", canvas.width, "and", canvas.offsetWidth, "is", off);
console.log(off, canvas.offsetWidth, canvas.width, x);
}
// target the button
var btn = $("#myBtn");
var modal = $("#myModal");
btn.click(function () {
modal.css("display", "block");
var canvas = document.getElementById("canvas");
canvas.addEventListener('mousemove', pick);
});
#myModal {
display: none;
/* Hidden by default */
position: fixed;
/* Stay in place */
z-index: 1;
/* Sit on top */
padding-top: 100px;
/* Location of the box */
left: 0;
top: 0;
width: 100%;
/* Full width */
height: 100%;
/* Full height */
overflow: auto;
/* Enable scroll if needed */
background-color: rgb(0, 0, 0);
/* Fallback color */
background-color: rgba(0, 0, 0, 0.4);
}
.modal-content {
background-color: #fefefe;
margin: auto;
padding: 20px;
border: 1px solid #888;
width: 80%;
}
canvas {
width: 100%;
/*margin-left: auto;
margin-right: auto;
display: block;*/
}
<form action="" method="post">
<label for="POST-name">Name:</label>
<input id="color" type="text">
</form>
<button id="myBtn">Open Color</button>
<div id="myModal" class="modal">
<!-- Modal content -->
<div class="modal-content">
<!-- Set height and width -->
<canvas id="canvas" width="1000" height="1000"></canvas>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.1.1.js" integrity="sha256-16cdPddA6VdVInumRGo6IbivbERE8p7CQR3HzTBuELA=" crossorigin="anonymous"></script>
EDIT 1
Compensated for offsetLeft and offsetTop.

How can an element of a fixed size (canvas) be resized in a flex container?

An HTML canvas element can be automatically resized by the dynamics of a HTML page: Maybe because its style properties are set to a percentage value, or maybe because it is inside a flex container.
Thereby the content of the canvas gets resized as well: Because of the interpolation the canvas content looks blurred (loss of resolution).
In order to keep the resolution to the maximum, one must render the canvas content based on the current pixel size of the element.
This fiddle shows how this can be done with the help of the function getComputedStyle: https://jsfiddle.net/fx98gmu2/1/
setInterval(function() {
var computed = getComputedStyle(canvas);
var w = parseInt(computed.getPropertyValue("width"), 10);
var h = parseInt(computed.getPropertyValue("height"), 10);
canvas.width = w;
canvas.height = h;
// re-rendering of canvas content...
}, 2000); // intentionally long to see the effect
With a setTimeout function I'm updating the width and height of the canvas to the computed values of these properties.
As the fiddle shows, this works only when increasing the size of the window. Whenever the window size gets decreased, the canvas (item of the flexbox) stays fixed.
Set its flex-basis to 0, allow it to shrink with flex-shrink, and don't force any minimum width:
#canvas {
flex: 1 1 0;
min-width: 0;
}
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d");
setInterval(function() {
var computed = getComputedStyle(canvas),
w = parseInt(computed.width, 10),
h = parseInt(computed.height, 10);
canvas.width = w;
canvas.height = h;
ctx.clearRect(0, 0, w, h);
ctx.beginPath();
ctx.arc(w/2, h/2, h/2, 0, Math.PI*2, true);
ctx.stroke();
}, 2000); // intentionally long to see the effect
#container {
border: 1px solid blue;
width: 100%;
display: flex;
}
#canvas {
border: 1px solid red;
flex: 1 1 0;
min-width: 0;
height: 150px;
}
<div id="container">
<canvas id="canvas"></canvas>
<div>something else...</div>
</div>
You need to place the canvas into a container with overflow:hidden and set canvas dimensions to dimensions of that container:
window.setTimeout( function() {
var div = $("div");
div.find("canvas").attr( { width:div.width(), height:div.height()} );
})
canvas { background:gold; display:block; }
div { width:50%; height:50%; border:1px solid; overflow:hidden; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<canvas width="200" height="100" />
</div>

How to get device size (mobile)?

I try to draw a circle in the middle of the device browsers width and height. But the canvas element disturb. The circle become draw in the middle of the devices width and height, if I make the canvas big enough, but the canvas size should fit in the device size.
Is there any way to fit the canvas width and height the device width and height?
thats the solution:
<html>
<head>
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1, maximum-scale=1">
<style>
/* Remove padding and margin */
* {
margin:0;
padding:0;
}
html, body, .myCanvas {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<canvas id="myCanvas" class="myCanvas"/>
<script>
var canvas = document.getElementById('myCanvas');
var width = canvas.width;
var height = canvas.height;
var context = canvas.getContext('2d');
var centerX = width / 2;
var centerY = height / 2;
var radius = 70;
context.beginPath();
context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
context.fillStyle = 'green';
context.fill();
context.lineWidth = 5;
context.strokeStyle = '#FF3300';
context.stroke();
console.log("width: " + width);
console.log("height: " + height);
</script>
</body>
</html>
Just add this to your code, right after getting the canvas:
canvas.width = width;
canvas.height = height;
You can also remove width and height attributes from the html part
Use css % size
HTML:
<canvas id="myCanvas" class="myCanvas"/>
CSS:
/* Remove padding and margin */
* {
margin:0;
padding:0;
}
html, body, .myCanvas {
width: 100%;
height: 100%;
}
Edit:
Get the width/height of your canvas instead of the window.
<html>
<head>
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1, maximum-scale=1">
<style>
/* Remove padding and margin */
* {
margin:0;
padding:0;
}
html, body, .myCanvas {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<canvas id="myCanvas" class="myCanvas"/>
<script>
var canvas = document.getElementById('myCanvas');
var width = canvas.width;
var height = canvas.height;
var context = canvas.getContext('2d');
var centerX = width / 2;
var centerY = height / 2;
var radius = 70;
context.beginPath();
context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
context.fillStyle = 'green';
context.fill();
context.lineWidth = 5;
context.strokeStyle = '#FF3300';
context.stroke();
console.log("width: " + width);
console.log("height: " + height);
</script>
</body>
</html>

Resize function for HTML5 Canvas

I managed to put together a dynamically resizing HTML5 Canvas but it has issues. For instance, it only scales the height, not the width too. My canvas has width of 900px and height of 850px. Another issue is that it enlarges the canvas too, way beyond it's defined width and height.
What am I doing wrong?
Here's what I tried so far:
var canvas, stage, exportRoot;
function init() {
createjs.MotionGuidePlugin.install();
canvas = document.getElementById("canvas");
exportRoot = new lib.Hat_finale();
stage = new createjs.Stage(canvas);
stage.addChild(exportRoot);
stage.update();
createjs.Ticker.setFPS(24);
createjs.Ticker.addEventListener("tick", stage);
}
function resize() {
var height = window.innerHeight;
var ratio = canvas.width / canvas.height;
var width = height * ratio;
canvas.style.width = width + 'px';
canvas.style.height = height + 'px';
}
window.addEventListener('load', resize, false);
window.addEventListener('resize', resize, false);
#container {
margin: 0 auto;
max-width: 900px;
max-height: 850px;
}
<div id="container">
<canvas id="canvas" width="900" height="850" style="background-color:#ffffff"></canvas>
</div>
UPDATE:
If I try what #havex said, changing the attributes like so: canvas.width = width; and canvas.height = height; instead of canvas.style.width = width+'px'; and canvas.style.height = height+'px'; what I get is a resizable box BUT NOT the animation. See picture for reference :
I can't explain why that is happening because it's 4:30 in the morning and I haven't slept yet, but change these and it should work (you can remove the borders):
HTML
<div id="container">
<canvas id="canvas" style="background-color:#ffffff"></canvas>
</div>
CSS
#container{
margin:0 auto;
width:900px;
height:850px;
border: 1px solid black;
}
canvas { width: 900px; height: 850px; border: 1px solid red; }
http://jsfiddle.net/Ln5z1zab/

Drawing in canvas become offset

I'm trying to draw into a canvas, but the more I go right, the more offset my drawing become.
Anyone have an idea why?
I have included the relevant code below:
CSS
html,body {
width:100%;
height:100%;
background:rgba(0,0,0,.2);
}
#container {
position:relative;
width:700px;
height:450px;
background:#fff;
overflow:hidden;
}
* {
-webkit-user-select: none;
}
canvas {
position: absolute;
top: 0;
left: 0;
background: #ccc;
width: 500px;
height: 200px;
}
HTML
<div id='adContainer'>
<canvas></canvas>
</div>
Javascript
var ctx;
var can = $('canvas');
$(document).ready(function() {
ctx = can[0].getContext('2d');
ctx.strokeStyle = "rgba(255,0,0,1)";
ctx.lineWidth = 5;
ctx.lineCap = 'round';
can.on("touchstart", function(event) {
event.preventDefault();
var e = event.originalEvent;
if(e.touches.length == 1) {
var posX = e.touches[0].pageX;
var posY = e.touches[0].pageY;
ctx.moveTo(posX, posY);
}
});
can.on("touchmove", function(event) {
event.preventDefault();
var e = event.originalEvent;
if(e.touches.length == 1) {
var posX = e.touches[0].pageX;
var posY = e.touches[0].pageY;
ctx.lineTo(posX, posY);
ctx.stroke();
}
});
});
Demo: http://jsfiddle.net/8Wtf8/
That is because you define the size of the canvas using CSS.
What happens is that when you don't explicitly define the size of the canvas using its width and height attributes the canvas defaults to size 300 x 150.
In your CSS you are then stretching the canvas element (look at it as an image) to 500px etc. - the content of the canvas is still 300 x 150.
You need to set the width and height on the canvas element itself:
<canvas width=500 height=200 id="myCanvas"></canvas>
and remove the definition from the CSS:
canvas {
position: absolute;
top: 0;
left: 0;
background: #ccc;
/*width: 500px;
height: 200px;*/
}
Also notice that background set by CSS will not be part of the canvas content.

Categories