Make Html5 Canvas and Its contained image responsive across browsers - javascript

I have a canvas object that I want to put an image in for a web application. I can get the image loaded, but I've run into 2 problems: The image won't stretch to the canvas, and the canvas won't stretch to cover the entire div in any browser but Firefox.
http://jsfiddle.net/LFJ59/1/
var canvas = $("#imageView");
var context = canvas.get(0).getContext("2d");
$(document).ready(drawImage());
$(window).resize(refreshCanvas());
refreshCanvas();
function refreshCanvas() {
//canvas/context resize
canvas.attr("width", $(window).get(0).innerWidth / 2);
canvas.attr("height", $(window).get(0).innerHeight / 2);
drawImage();
};
function drawImage() {
//shadow
context.shadowBlur = 20;
context.shadowColor = "rgb(0,0,0)";
//image
var image = new Image();
image.src = "http://www.netstate.com/states/maps/images/ca_outline.gif";
$(image).load(function () {
image.height = canvas.height();
image.width = canvas.width();
context.drawImage(image);
});
};
Is there a solution to making the canvas responsive? Or do I just need to lock the canvas and image down to predefined sizes?

width and height of image are read-only so that won't work.
Try instead:
context.drawImage(image, 0, 0, canvas.width, canvas.height);
This will draw the image the same dimension as the canvas is (you don't need to reload the image every time btw. - just load it once globally and reuse the image variable.)

<canvas id="imageView" width="1000" height="1000" style="width:100%; height:100%"></canvas>
Both CSS and height and width attributes can be used and do not need to agree in size. The CSS style will determine the displayed size, you asked for a canvas that can stretch. The width and height control the number of pixels the canvas uses for drawing.
for example this will be scaled 10 to 1, and with anti-aliasing scrolling an drawing in this canvas would be as smooth as silk.
<canvas id="imageView" width="1000" height="1000" style="width:100px; height:100px"></canvas>
If CSS is not used, their defaults will be the width and height attributes of the canvas element.

Related

Is it possible to scale a drag image

I am doing drag and drop and want to use a different drag image than the default. But I would also like to scale the size of the drag image depending on the size of the element where the drag starts. I have tried doing the following:
<div id="drag-with-image" draggable="true">drag me</div>
<script>
document.getElementById("drag-with-image").addEventListener("dragstart", function(e) {
var img = document.createElement("img");
img.src = "https://www.w3schools.com/css/paris.jpg";
img.style.width = "60px";
img.style.height = "40px";
e.dataTransfer.setDragImage(img, 0, 0);
}, false);
</script>
But the drag image is always displayed as full size.
Is there any way the drag image size can be scaled dynamically?
Yes, it is possible to scale a custom drag image.
The Problem
If you're using setDragImage with an image element, what will be drawn is the image in its intrinsic size (content size before any modification). This means that setting the image size doesn't help. However, as mentioned in MDN Docs, you can also set a drag image to be something else:
If Element is an img element, then set the drag data store bitmap to the element's image (at its intrinsic size); otherwise, set the drag data store bitmap to an image generated from the given element (the exact mechanism for doing so is not currently specified).
Furthermore, it also mentions that the "other elements" can be any visible element or even a <canvas>:
However, if a custom image is desired, the DataTransfer.setDragImage() method can be used to set the custom image to be used. The image will typically be an element but it can also be a or any other visible element.
Solution
To draw an image that is smaller than its intrinsic size and setting it to drag image, you can:
Load the image to an image element
Create a canvas to be drawn with the image
When drawing to the canvas, adjust the width and height of the drawn image accordingly
Here's a working example.
document.getElementById('drag-with-image').addEventListener('dragstart', function(e) {
var img = document.createElement('img')
var canvas = document.createElement('canvas')
var ctx = canvas.getContext('2d')
// Setting img src
img.src = 'https://www.w3schools.com/css/paris.jpg'
// Drawing to canvas with a smaller size
canvas.width = img.width * 0.1
canvas.height = img.height * 0.1
ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
// Setting drag image with drawn canvas image
e.dataTransfer.setDragImage(canvas, 0, 0)
}, false)
<div id="drag-with-image" draggable="true">drag me</div>

How to scale my canvas in reason, with the zoom scale?

I am working on a multiple web game using JavaScript. My canvas is currently set to the width and the height of my screen.
html
<canvas id = "canvas"></canvas>
javascript
var c=document.getElementById("canvas");
var ctx = c.getContext("2d");
//Making canvas scale;
c.width = window.innerWidth;
c.height = window.innerHeight;
function resize(){
//Add some code
}
My problem is, I do not want my players to zoom out, well not by default. It will make the game look bad and give the players an edge over everyone else. So I need to add some code to go into the resize method, that regardless of scale, the canvas will not be zoomed out. If the end result is something blurry at 300%+ that is fine.
IMPORTANT: the resize function cannot remove or reset the canvas back to default.
There are various ways to scale a canvas.
First off, there are 2 main parameters for the canvas size:
-Canvas Pixel Count. Set via canvas.width = 1000
-Canvas Display Pixel Size. Set via canvas.style.width = '1000px'
If you want all players to see a 1000x1000 region but displaying it fullscreen:
canvas.width = 1000;
canvas.height = 1000;
canvas.style.width = window.innerWidth + 'px';
canvas.style.height = window.innerHeight + 'px';
There is also another option with canvas.style.transform = 'scale(2,2)'.
This method is the closest thing to the browser zoom done via Ctrl+ or Ctrl-.
The big advantage of transform is that the scaling is applied to all DOM children elements. If your game is using HTML for its interface, then this is the way to go. (By applying the scaling on the div containing the canvas + HTML interface.

HTML canvas coordinates are different when created using JS versus embed in HTML

Playing with HTML5 canvas and JS, I found a strange behaviour when a canvas is added to the HTML body directly versus creating a canvas using JS.
<!DOCTYPE html>
<html>
<head></head>
<body>
<canvas id="test" width="200" height="200" style="border:1px solid #000000;">
</canvas>
<script>
var c=document.getElementById("test");
ctx=c.getContext("2d");
ctx.fillStyle = "#9ea7b8";
ctx.fill();
ctx.moveTo(0,0);
ctx.lineTo(200,200);
ctx.stroke();
// creating canvas using JS
c = document.createElement("canvas");
c.id="MyCanvas";
c.style.width="200px";
c.style.height="200px";
c.style.border="1px solid #000000";
ctx=c.getContext("2d");
ctx.fillStyle = "#9ea7b8";
ctx.fill();
ctx.moveTo(0,0);
ctx.lineTo(200,200);
ctx.stroke();
document.body.appendChild(c);
</script>
</body>
</html>
Please see the code & ouput here
I expected the line (stroke) to be a consistent diagonal across the canvas but alas!. Please help me know where am I going wrong!
Note: I forgot to mention, I tried this on Chrome only not sure if the behaviour is consistent for other browsers.
So, basically if you change from style to attribute it works.
Why ?
It seems that the width and height attributes determine the width or height of the canvas's coordinate system, whereas the CSS properties just determine the size of the box in which it will be shown.
Source
Like this it will work fine:
var c = document.getElementById("test");
ctx = c.getContext("2d");
ctx.fillStyle = "#9ea7b8";
ctx.fill();
ctx.moveTo(0, 0);
ctx.lineTo(200, 200);
ctx.stroke();
// creating canvas using JS
c = document.createElement("canvas");
c.id = "MyCanvas";
c.setAttribute("width", "200px")
c.setAttribute("height", "200px")
c.style.border = "1px solid #000000";
ctx = c.getContext("2d");
ctx.fillStyle = "#9ea7b8";
ctx.fill();
ctx.moveTo(0, 0);
ctx.lineTo(200, 200);
ctx.stroke();
document.body.appendChild(c);
<canvas id="test" width="200" height="200" style="border:1px solid #000000;"></canvas>
Canvas width and height attributes are not the same as its CSS width and height. Setting canvas.width/height attributes determines the total drawable pixel area, which can be (but does not need to be) scaled with CSS to be larger or smaller on the screen.
Normal scenario: Make canvas attribute bounds larger than CSS bounds
In fact, to make a high density display canvas it is necessary to set canvas.width and canvas.height twice as large as the css. In other words you might do:
// Two canvas pixels per screen pixel so it looks nice
// on a high density (in this case pixel ratio: 2) display
canvas.width = 800;
canvas.height = 800;
canvas.style.width = '400px';
canvas.style.height = '400px';
Normal scenario: Make canvas attribute bounds smaller than CSS bounds
On the flip side in order to make some apps like games fast canvas.width and canvas.height might be restricted to 640x480 (or something small) and then scaled with CSS to take up the whole screen. Since the total number of pixels handled on the canvas is small, the game will be faster than if you used a really large canvas and filled the screen. Obviously the game will look different, since CSS will be scaling the graphics (for better or worse).

Big image drawn on small canvas become blurrier

In my project i have a canvas (200*150) and i want to draw an image of size (800*600) . The result is that image become bluer (not smooth and clear) , but if we put that image on img tag it look well. So how can we deal with this? thanks.
<img src="http://www.drivingkids.com/wp-content/uploads/2010/07/preschool-math-game-for-kids-math-racing-equatations.jpg"
width="200" heigh="150" />
<canvas id="my_canvas" width="200" height="150"></canvas>
<script type="text/javascript">
window.onload = function () {
var context = document.getElementById("my_canvas").getContext("2d");
var image = new Image();
image.src = "http://www.drivingkids.com/wp-content/uploads/2010/07/preschool-math-game-for-kids-math-racing-equatations.jpg";
image.onload = function () {
context.drawImage(image, 0, 0, context.canvas.width, context.canvas.height); //dx-30, GY-28, GW+50, GH+35
}
}
</script>
Cause
Browsers can prioritize quality or performance depending on the current scenario.
For images quality is typically prioritized over performance for most pages. But for canvas performance is not as good as with for instance direct browser rendering and CSS so the interpolation with canvas may have performance prioritized before quality. Depending on browser implementation.
Solution
Luckily there is a way to work around this by sort of splitting the burden with the resizing and interpolation by doing it in two (or more) steps, or one intermediate step if you like.
The intermediate step will first scale the image 50% to an off-screen canvas. Then use that canvas to draw to the final size. For larger images more steps will perhaps be needed.
The time spent in sum is about the same due to the sum of the operations to get the new sizes (more simply put: less to interpolate with intermediate step x2, versus more to interpolate x1) so you won't notice much performance reduction.
But most importantly: the result will be better than with just a single step.
Implementation
This is how you can implement an intermediate step:
image.onload = function () {
/// create an extra step for re-sizing image
var tmpCanvas = document.createElement('canvas'),
tmpContext = c.getContext('2d');
/// set this canvas to 50% of image
tmpCanvas.width = image.width * 0.5;
tmpCanvas.height = image.height * 0.5;
/// draw image step 1
tmpContext.drawImage(image, 0, 0, image.width * 0.5, image.height * 0.5);
/// draw image step 2
context.drawImage(tmpCanvas, 0, 0, canvas.width, canvas.height);
}
Demo (proof-of-concept)
ONLINE DEMO HERE
The result will be:
Left image: IMG element. Right image: canvas two steps (rendered in Firefox)
As you can see there is now no noticeable difference between image and canvas element.

Drawing image on canvas - larger than real

I want to draw an image from jpg file on canvas.
My code:
var canvas = document.getElementById('my_canvas');
var ctx = canvas.getContext('2d');
var imageObj = new Image();
imageObj.onload = function() {
ctx.drawImage(imageObj, 0, 0);
};
imageObj.src = 'img/my_image.jpg';
The problem is that the image on canvas is much bigger than in file. Why? How can I draw image real size?
UPDATE:
result: http://jsfiddle.net/AJK2t/
This is your problem:
<canvas style="width: 700px; height: 400px;" id="konf"></canvas>
You are setting the visual size of your canvas, but not the number of pixels. Consequently the browser is scaling the canvas pixels up.
The simplest fix is:
<canvas width="700" height="400" id="konf"></canvas>
The width and height parameters control the number of pixels in the canvas. With no CSS styling, the default visual size of the canvas will also be this size, resulting in one canvas pixel per screen pixel (assuming you have not zoomed the web browser).
Copy/pasting from my answer to a related question:
Think about what happens if you have a JPG that is 32x32 (it has exactly 1024 total pixels) but specify via CSS that it should appear as width:800px; height:16px. The same thing applies to HTML Canvas:
The width and height attributes of the canvas element itself decide how many pixels you can draw on. If you don't specify the height and width of the canvas element, then per the specs:
"the width attribute defaults to 300, and the height attribute defaults to 150."
The width and height CSS properties control the size that the element displays on screen. If the CSS dimensions are not set, the intrinsic size of the element is used for layout.
If you specify in CSS a different size than the actual dimensions of the canvas it must be stretched and squashed by the browser as necessary for display. You can see an example of this here: http://jsfiddle.net/9bheb/5/
Working Example: http://jsfiddle.net/jzF5R/
In order to scale an image you need to provide the scaled width and height you want to ctx.drawImage():
// x, y, width, height
ctx.drawImage(imageObj, 0, 0, 100, 50);
Maintain original image size:
ctx.drawImage(imageObj, 0, 0, imageObj.width, imageObj.height);
Keep canvas from overflowing off the page:
ctx.canvas.width = document.body.clientWidth;
You can easily scale the image width and height to 70% of original:
ctx.drawImage(imageObj, 0, 0, imageObj.width * 0.7, imageObj.height * 0.7);
To display a MJPEG stream on a canvas (or something else) without define the width and the height of the canvas in HTML, so only using CSS to get a responsive canvas and fit with the page, I use that:
//get size from CSS
var sizeWidth = context.canvas.clientWidth;
var sizeHeight = context.canvas.clientHeight;
//here the solution, it replaces HTML width="" height=""
canvas.width = sizeWidth;
canvas.height = sizeHeight;
...........
context.drawImage(imageObj, 0, 0, imageObj.width, imageObj.height, 0, 0, sizeWidth, sizeHeight);
The picture is entirely contained in the canvas whatever the size of the canvas (the rate between height and width is not kept but it doesn't matter, an height:auto; in css can fix that).
Et voilĂ  !

Categories

Resources