HTML5 canvas (only using the drawImage function) is not showing up on mobile devices, but is on my laptop.
You can see here : mmhudson.com/index.html (reload once)
I get no errors or anything, but it doesn't display in chrome on iOS or the default browser on android..
EDIT:
This problem only occurs when the following meta tag is included in the document:
<meta name="viewport" content="width=device-width, initial-scale=1"></meta>
Your init() function is called by imgLoad(), but you're loading images only when the window width is greater than or equal to 480px:
window.onload = function(){
s.dL = true;
s.width = window.innerWidth;
s.height = window.innerHeight;
if(s.width < 320){
//too small
}
else if(s.width >= 320 && s.width < 480){
s.scWidth = 296;
}
else{
s.scWidth = 456;
b_border.src = "res/480/b_border.png";
r_border.src = "res/480/r_border.png";
l_border.src = "res/480/l_border.png";
t_border.src = "res/480/t_border.png";
br_corner.src = "res/480/br_corner.png";
tr_corner.src = "res/480/tr_corner.png";
bl_corner.src = "res/480/bl_corner.png";
tl_corner.src = "res/480/tl_corner.png";
h_wall.src = "res/480/h_wall.png";
v_wall.src = "res/480/v_wall.png";
box.src = "res/480/box.png";
crosshair.src = "res/480/crosshair.png";
player1.src = "res/480/player1.png";
player2.src = "res/480/player2.png";
}
}
When you omit the meta viewport tag, the browser assumes a page / window width of 980px, and so your code runs normally.
When you include a meta viewport tag with width=device-width, the browser sets the page / window width to the width of the screen (e.g. 320px on iPhone), and so imgLoad() and init() is never called.
It looks like you are trying to draw the images before they have loaded. I'm not sure why the mobile browsers would fail more often, possibly they are slower to load them all in?
In fact, when i open your page on my desktop, sometimes the canvas does not draw, but if I open the console and enter draw() it appears (because by then the images have loaded).
If you were dealing with just a single image, the simplified code would be:
var img = new Image();
img.onload = function(){
// drawing code goes here
}
img.src = 'myfile.png';
But because of the large number of images you have here, I would look into a resource loading library of some sort.
Related
I'm creating an image gallery and I need to know the size of the div containing the image or the image itself after it loads. How can I get that? I've tried everything but it gives me the size of the DIV before it loads, which is 1px X 1px.
Basically everything is hidden, you click a link and the image displays, so the div goes from 1px by 1px to for example, say 419px by 1000px. How do I get that final size after the DIV or Image loads? the size can change depending on the device used and the image loaded. Is there anyway to get this information using just JavaScript?
Here's the function. If possible I would like to get the height of the image or the DIV after the image loads in the same function.
here's the function that i am testing
function ShowArt(nam,imgs,)
{
var currentPosition = parseInt(movingDivObj.style.top);
var scrollPos = window.scrollY || window.scrollTop || document.getElementsByTagName("html")[0].scrollTop;
movingDivObj.style.top = currentPosition + scrollPos + "px";
movingDivObj.style.display = "block";
document.getElementById("close").style.display = "block";
document.getElementById("selectedart").style.display = "block";
document.getElementById("artname").style.display = "block";
document.getElementById("background").style.display = "block";
display.src = imgs;
document.getElementById("artname").textContent= nam;
scrollPosition = window.pageYOffset;
document.body.style.position = "fixed";
document.body.style.top = `-${scrollPosition}px`;
}
Thanks!
Try using this DOM event listener, in the callback function you can write the necessary code to get your value I presume:here
In the same way that the "load" event works for the body, it works for images. So you could attach an "load" event on the image and when it triggers, measure the width/height.
const img = document.querySelector('#img')
img.addEventListener('load', (event) => {
console.log('width', event.target.width)
console.log('height', event.target.height)
})
img.src = 'https://via.placeholder.com/900x1000'
Have you tried:
<script>
var myImg = document.getElementById('image');
var realWidth = myImg.naturalWidth;
var realHeight = myImg.naturalHeight;
console.log(realWidth);
</script>
Solution 1:
Use this Solution in your JS file
JavaScript:
window.onload = () => {};//enter the code that gets the image or divs width and height in the {} brackets`
The window.onload function waits till the DOM is loaded and then executes a function. It is used mostly when you need to get default values from a predefined and static element.
Further Readings: https://www.w3schools.com/jsref/event_onload.asp
Solution 2:
NOTE: Use this only if you are using a 'script' tag to use the JS code in your HTML.
Use the script tag at the end of your HTML document
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!--Your code goes here-->
<script src="myScript.js"></script>
</body>
</html>
Thanks guys I appreciate all the help. I finally found an answer that worked though I got some great ideas. The answer was to have the images preload and when I did that it gave me the height of the image I needed for the next steps. Again thanks very much! I appreciate it. The code I used for this is below. After the images are preloaded I am able to get the width / height of the images so they work in the gallery as planned. It worked like a charm.
var images = new Array()
function preload() {
for (i = 0; i < preload.arguments.length; i++) {
images[i] = new Image()
images[i].src = preload.arguments[i]
}
}
preload(
"Photos/AloneInTheStorm.jpg",
"Photos/deepinthought.jpg",
"Photos/68degrees.jpg",
"Photos/forgotten.jpg",
"Photos/babylycan2.jpg",
"Photos/americancoot.jpg"
)
Ok, so a little bit of background... I'm trying to generate animated gifs from animations done on an HTML5 canvas using JavaScript. Specifically, I'm adding data layers to a Mapbox GL JS map and looping through them.
On each iteration, I save the canvas element and transform it to a blob before calling URL.createObjectURL(blob) and setting that as the source to a new image. After the loop is finished I generate a gif using gifshot (https://github.com/yahoo/gifshot) and the images I previously created.
This process works perfectly in all browsers (mobile too!) EXCEPT on iPhone ios. On ios the gif has weird stutters and transparency issues. I have tried other gif creation libraies but all have the same issue on ios. Could it be a memory problem or something? I'm at my wit's end on this, so any help is greatly appreciated!
This is the code inside each loop:
var cv = map.getCanvas()
var oneImage = new Image();
cv.toBlob(function(blob) {
url = URL.createObjectURL(blob);
oneImage.src = url
images_arr.push(oneImage)
i++;
setTimeout(function(){
gifLoop(images_arr);
},1000)
})
and this is the code I call when the loop is finished:
var w = window.innerWidth;
var h = window.innerHeight;
recalculated_size = calculateAspectRatioFit(w, h, maxWidth, maxHeight)
w = recalculated_size.width
h = recalculated_size.height
gifshot.createGIF({
'images': images_arr,
'gifWidth': w,
'gifHeight':h,
},function(obj) {
if(!obj.error) {
var image = dataURItoBlob(obj.image)
image = URL.createObjectURL(image);
var animatedImage = document.getElementById('gif');
animatedImage.src = image
var link = $('#gif-link');
link.attr('href',image);
filename = curr_layer_id + '_' + curr_time +'.gif'
link.attr('download', filename);
}
});
I am trying to do a not so simple task. I would like to have in a HTML5 page a video element with constant width and height (those of the window), that can manages the dimensions and aspect ratio of the source video to display at best that is to say with the window fully covered with the video and with no scroll bars.
I wrote this javascript code:
$("video").bind("loadedmetadata", function () {
var screenSize = {}, videoSize = {};
videoSize["width"] = this.videoWidth;
videoSize["height"] = this.videoHeight;
screenSize["height"] = $( window ).height();
screenSize["width"] = $( window ).width();
var ratio_screen = screenSize["width"]/screenSize["height"];
var ratio_video = videoSize["width"]/videoSize["height"];
if (ratio_video > ratio_screen) {
$("video").height(screenSize["height"]);
$("video").width(screenSize["height"]*ratio_screen);
}
else
{
$("video").width(screenSize["width"]);
$("video").height(screenSize["width"]/ratio_screen);
}
});
At the moment, I have a video element, almost fitting the window (I still have a border or margin that inspector says to be part of html element). But the source video is fitting inside the video element! As an example for my test video which is wider than the screen, I have a black strip over and under the video.
How can I manage this to "zoom" the video. Do I have to apply a scaling factor to the video element or somenthing can be done at source video level.
Thanks
Finally this piece of code worked:
$("video").on('canplay',function() {
$("video").bind("loadedmetadata", function () {
var screenSize = {}, videoSize = {};
videoSize["width"] = this.videoWidth;
videoSize["height"] = this.videoHeight;
screenSize["height"] = $( window ).height();
screenSize["width"] = $( window ).width();
var ratio_screen = screenSize["width"]/screenSize["height"];
var ratio_video = videoSize["width"]/videoSize["height"];
if (ratio_video > ratio_screen) {
$("video").css("-webkit-transform", "scale("+ratio_video/ratio_screen+")");
$("video").height(screenSize["height"]);
$("video").width(screenSize["height"]*ratio_screen);
} else {
$("video").css("-webkit-transform", "scale("+ratio_video/ratio_screen+")");
$("video").width(screenSize["width"]);
$("video").height(screenSize["width"]/ratio_screen);
}
});
});
This results in displaying a video, filling the whole screen, without stretching the video if the aspect ratio is not fitting the one of the screen.
Note that my video element plays several sources in a loop. The first video played does not apply this resizing function (I have to work on that to ensure the at start up this works).
After being a long time lurker, this is my first post here! I've been RTFMing and searching everywhere for an answer to this question to no avail. I will try to be as informative as I can, hope you could help me.
This code is for my personal webpage.
I am trying to implement some sort of a modern click-map using HTML5 and jQuery.
In the website you would see the main image and a hidden canvas with the same size at the same coordinates with this picture drawn into it.
When the mouse hovers the main picture, it read the mouse pixel data (array of r,g,b,alpha) from the image drawn onto the canvas. When it sees the pixel color is black (in my case I only check the RED value, which in a black pixel would be 0) it knows the activate the relevant button.
(Originally, I got the idea from this article)
The reason I chose this method, is for the page to be responsive and dynamically change to fit different monitors and mobile devices. To achieve this, I call the DrawCanvas function every time the screen is re-sized, to redraw the canvas with the new dimensions.
Generally, this works OK. The thing is ,there seems to be an inconsistent behavior in Chrome and IE(9). When I initially open the page, I sometimes get no pixel data (0,0,0,0), until i re-size the browser. At first I figured there's some loading issues that are making this happen so I tried to hack it with setTimeout, it still doesn't work. I also tried to trigger the re-size event and call the drawCanvas function at document.ready, still didn't work.
What's bothering me is most, are the inconsistencies. Sometimes it works, sometimes is doesn't. Generally, it is more stable in chrome than in IE(9).
Here is the deprecated code:
<script type="text/javascript">
$(document).ready(function(){setTimeout(function() {
// Get main image object
var mapWrapper = document.getElementById('map_wrapper').getElementsByTagName('img').item(0);
// Create a hidden canvas the same size as the main image and append it to main div
var canvas = document.createElement('canvas');
canvas.height = mapWrapper.clientHeight;
canvas.width = mapWrapper.clientWidth;
canvas.fillStyle = 'rgb(255,255,255)';
canvas.style.display = 'none';
canvas.id = 'hiddencvs';
$('#map_wrapper').append(canvas);
// Draw the buttons image into the canvas
drawCanvas(null);
$("#map_wrapper").mousemove(function(e){
var canvas = document.getElementById('hiddencvs');
var context = canvas.getContext('2d');
var pos = findPos(this);
var x = e.pageX - pos.x;
var y = e.pageY - pos.y;
// Get pixel information array (red, green, blue, alpha)
var pixel = context.getImageData(x,y,1,1).data;
var red = pixel[0];
var main_img = document.getElementById('map_wrapper').getElementsByTagName('img').item(0);
if (red == 0)
{
...
}
else {
...
}
});
},3000);}); // End DOM Ready
function drawCanvas(e)
{
// Get context of hidden convas and set size according to main image
var cvs = document.getElementById('hiddencvs');
var ctx = cvs.getContext('2d');
var mapWrapper = document.getElementById('map_wrapper').getElementsByTagName('img').item(0);
cvs.width = mapWrapper.clientWidth;
cvs.height = mapWrapper.clientHeight;
// Create img element for buttons image
var img = document.createElement("img");
img.src = "img/main-page-buttons.png";
// Draw buttons image inside hidden canvas, strech it to canvas size
ctx.drawImage(img, 0, 0,cvs.width,cvs.height);
}
$(window).resize(function(e){
drawCanvas(e);
}
);
function findPos(obj)
{
...
}
</script>
I'd appreciate any help!
Thanks!
Ron.
You don't wait for the image to be loaded so, depending on the cache, you may draw an image or not in the canvas.
You should do this :
$(function(){
var img = document.createElement("img");
img.onload = function() {
var mapWrapper = document.getElementById('map_wrapper').getElementsByTagName('img').item(0);
...
// your whole code here !
...
}
img.src = "img/main-page-buttons.png";
});
It would be incredibly useful to be able to temporarily convert a regular element into a canvas. For example, say I have a styled div that I want to flip. I want to dynamically create a canvas, "render" the HTMLElement into the canvas, hide the original element and animate the canvas.
Can it be done?
There is a library that try to do what you say.
See this examples and get the code
http://hertzen.com/experiments/jsfeedback/
http://html2canvas.hertzen.com/
Reads the DOM, from the html and render it to a canvas, fail on some, but in general works.
Take a look at this tutorial on MDN: https://developer.mozilla.org/en/HTML/Canvas/Drawing_DOM_objects_into_a_canvas (archived)
Its key trick was:
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var data = '<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">' +
'<foreignObject width="100%" height="100%">' +
'<div xmlns="http://www.w3.org/1999/xhtml" style="font-size:40px">' +
'<em>I</em> like ' +
'<span style="color:white; text-shadow:0 0 2px blue;">' +
'cheese</span>' +
'</div>' +
'</foreignObject>' +
'</svg>';
var DOMURL = window.URL || window.webkitURL || window;
var img = new Image();
var svg = new Blob([data], {type: 'image/svg+xml;charset=utf-8'});
var url = DOMURL.createObjectURL(svg);
img.onload = function () {
ctx.drawImage(img, 0, 0);
DOMURL.revokeObjectURL(url);
}
img.src = url;
That is, it used a temporary SVG image to include the HTML content as a "foreign element", then renders said SVG image into a canvas element. There are significant restrictions on what you can include in an SVG image in this way, however. (See the "Security" section for details — basically it's a lot more limited than an iframe or AJAX due to privacy and cross-domain concerns.)
Sorry, the browser won't render HTML into a canvas.
It would be a potential security risk if you could, as HTML can include content (in particular images and iframes) from third-party sites. If canvas could turn HTML content into an image and then you read the image data, you could potentially extract privileged content from other sites.
To get a canvas from HTML, you'd have to basically write your own HTML renderer from scratch using drawImage and fillText, which is a potentially huge task. There's one such attempt here but it's a bit dodgy and a long way from complete. (It even attempts to parse the HTML/CSS from scratch, which I think is crazy! It'd be easier to start from a real DOM node with styles applied, and read the styling using getComputedStyle and relative positions of parts of it using offsetTop et al.)
You can use dom-to-image library (I'm the maintainer).
Here's how you could approach your problem:
var parent = document.getElementById('my-node-parent');
var node = document.getElementById('my-node');
var canvas = document.createElement('canvas');
canvas.width = node.scrollWidth;
canvas.height = node.scrollHeight;
domtoimage.toPng(node).then(function (pngDataUrl) {
var img = new Image();
img.onload = function () {
var context = canvas.getContext('2d');
context.translate(canvas.width, 0);
context.scale(-1, 1);
context.drawImage(img, 0, 0);
parent.removeChild(node);
parent.appendChild(canvas);
};
img.src = pngDataUrl;
});
And here is jsfiddle
Building on top of the Mozdev post that natevw references I've started a small project to render HTML to canvas in Firefox, Chrome & Safari. So for example you can simply do:
rasterizeHTML.drawHTML('<span class="color: green">This is HTML</span>'
+ '<img src="local_img.png"/>', canvas);
Source code and a more extensive example is here.
No such thing, sorry.
Though the spec states:
A future version of the 2D context API may provide a way to render fragments of documents, rendered using CSS, straight to the canvas.
Which may be as close as you'll get.
A lot of people want a ctx.drawArbitraryHTML/Element kind of deal but there's nothing built in like that.
The only exception is Mozilla's exclusive drawWindow, which draws a snapshot of the contents of a DOM window into the canvas. This feature is only available for code running with Chrome ("local only") privileges. It is not allowed in normal HTML pages. So you can use it for writing FireFox extensions like this one does but that's it.
You could spare yourself the transformations, you could use CSS3 Transitions to flip <div>'s and <ol>'s and any HTML tag you want. Here are some demos with source code explain to see and learn: http://www.webdesignerwall.com/trends/47-amazing-css3-animation-demos/
the next code can be used in 2 modes, mode 1 save the html code to a image, mode 2 save the html code to a canvas.
this code work with the library: https://github.com/tsayen/dom-to-image
*the "id_div" is the id of the element html that you want to transform.
**the "canvas_out" is the id of the div that will contain the canvas
so try this code.
:
function Guardardiv(id_div){
var mode = 2 // default 1 (save to image), mode 2 = save to canvas
console.log("Process start");
var node = document.getElementById(id_div);
// get the div that will contain the canvas
var canvas_out = document.getElementById('canvas_out');
var canvas = document.createElement('canvas');
canvas.width = node.scrollWidth;
canvas.height = node.scrollHeight;
domtoimage.toPng(node).then(function (pngDataUrl) {
var img = new Image();
img.onload = function () {
var context = canvas.getContext('2d');
context.drawImage(img, 0, 0);
};
if (mode == 1){ // save to image
downloadURI(pngDataUrl, "salida.png");
}else if (mode == 2){ // save to canvas
img.src = pngDataUrl;
canvas_out.appendChild(img);
}
console.log("Process finish");
});
}
so, if you want to save to image just add this function:
function downloadURI(uri, name) {
var link = document.createElement("a");
link.download = name;
link.href = uri;
document.body.appendChild(link);
link.click();
}
Example of use:
<html>
<head>
</script src="/dom-to-image.js"></script>
</head>
<body>
<div id="container">
All content that want to transform
</div>
<button onclick="Guardardiv('container');">Convert<button>
<!-- if use mode 2 -->
<div id="canvas_out"></div>
</html>
Comment if that work.
Comenten si les sirvio :)
The easiest solution to animate the DOM elements is using CSS transitions/animations but I think you already know that and you try to use canvas to do stuff CSS doesn't let you to do. What about CSS custom filters? you can transform your elements in any imaginable way if you know how to write shaders. Some other link and don't forget to check the CSS filter lab.
Note: As you can probably imagine browser support is bad.
function convert() {
dom = document.getElementById('divname');
var script,
$this = this,
options = this.options,
runH2c = function(){
try {
var canvas = window.html2canvas([ document.getElementById('divname') ], {
onrendered: function( canvas ) {
window.open(canvas.toDataURL());
}
});
} catch( e ) {
$this.h2cDone = true;
log("Error in html2canvas: " + e.message);
}
};
if ( window.html2canvas === undefined && script === undefined ) {
} else {.
// html2canvas already loaded, just run it then
runH2c();
}
}