Canvas image not displaying until second attempt - javascript

I'm trying to use the element to draw a static Google Maps image that comes onscreen once a user clicks on a submit button. The html looks like this:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<script type="text/javascript"
src="https://maps.googleapis.com/maps/api/js?key=MYKEY&sensor=true">
</script>
<script type="text/javascript" src="createmap.js">
</script>
</head>
<body>
<form onsubmit="display_map(34.1,-76.08168); return false;">
<input type="submit" value="Submit"/>
</form>
<canvas id='map-canvas' />
</body>
</html>
And the display_map() function in createmap.js:
function display_map(center0, center1) {
var image = new Image();
image.src = 'http://maps.googleapis.com/maps/api/staticmap?center='
+ center0 + ',' + center1 + '&zoom=13&size=800x800&sensor=false';
var canvas = document.getElementById('map-canvas');
var context = canvas.getContext('2d');
context.drawImage(image, 0, 0);
}
The first time that the user clicks on the submit button, nothing happens. Every subsequent click, however, will load the image (even if the tab is closed and then reopened). Changing the center0 and center1 arguments will reset the page and again force two clicks to display the new image that Google generates. This behavior doesn't seem to be coming from Google Maps, as the same issue occurs when I load an image from my hard drive. This is happening in every browser I've tested (Firefox, IE and Chrome).

It's because the first time the image hasn't loaded properly so the canvas doesn't draw anything. The image loads asynchronous in the background so your function will continue regardless.
To handle this scenario try with:
function display_map(center0, center1) {
var image = new Image();
image.onload = function() {
var canvas = document.getElementById('map-canvas');
var context = canvas.getContext('2d');
context.drawImage(this, 0, 0);
}
image.src = 'http://maps.googleapis.com/maps/api/staticmap?center='
+ center0 + ',' + center1 + '&zoom=13&size=800x800&sensor=false';
}
That the function returns immediately is something that needs to be taken into account in case you do several draw operations to canvas (graphics on top for instance).
For these cases you need to use callbacks so when an image has finished loading you call the next step from within the onload handler with a single extra parameter:
function display_map(center0, center1, callback) {
var image = new Image();
image.onload = function() {
var canvas = document.getElementById('map-canvas');
var context = canvas.getContext('2d');
context.drawImage(this, 0, 0);
callback();
}
image.src = 'http://maps.googleapis.com/maps/api/staticmap?center='
+ center0 + ',' + center1 + '&zoom=13&size=800x800&sensor=false';
}
Now you can create a call chain:
function step1() {
display_map(center0, center1, step2);
}
function step2() {
/// called when step1 has finished
}

Related

How do i do to make wait the program untile an image is load ? (java script)

I have recently started to learn html and i'm currently working on java script. My problem is that i would to stop the program until a image as been load for, after that draw the image on a canvas (because if the image is not load and i want to draw it on a canvas, nothing would be display).
Here's my code (put in one file) :
<html>
<head>
<title>dog food</title>
<link rel = "icon" href = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQudx87gpctKJdgDyq5DpVlb12fI3_7XgbfXw&usqp=CAU">
<style>
canvas.GameWindow {
display : block;
margin-left : auto;
margin-right : auto;
}
</style>
</head>
<body>
<canvas width = 600 height = 350 class = GameWindow>Sorry but the canvas is not taken by your web browser</canvas>
<script>
var canvas = document.querySelector('canvas');
var ctx = canvas.getContext('2d');
//initialize canvas
/*ctx.fillStyle = 'black';
ctx.fillRect(0, 0, 600, 350);*/
//create function
function drawAnImage(positionX,positionY,width,height,image) {
ctx.drawImage(image, positionX, positionY, width, height);
console.log("an image has been drawn");
};
var img = new Image();
img.src = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQudx87gpctKJdgDyq5DpVlb12fI3_7XgbfXw&usqp=CAU";
img.onload = function() {
console.log("image load");
};
drawAnImage(0,0,100,100,img);
</script>
</body>
</html>
Actually when i run the code, nothing is display on the canvas because the image is load after i call the drawAnImage function.
Wait for it to load with a callback:
img.onload = function () {
drawImage(0, 0, 100, 100, img);
};
You can also do something if there was an error loading it:
img.onerror = function () {
alert("Oh no an error!");
};
Here it is with ES6 arrow functions and addEventListener:
img.addEventListener("load", () => {
drawImage(0, 0, 100, 100, img);
});
img.addEventListener("error", () => {
alert("Oh no an error!");
});
So i finaly use this little algorithm for image loading :
const imageToLoad = [];
var totalImage = imageToLoad.length;
let imageLoad = [];
for (var i = 0;i<totalImage;i++) {
var img = new Image();
img.src = imageToLoad[i];
imageLoad.push(img);
img.onload = function() {
if (i == totalImage) {
//here i start my game loop
gameLoop(imageLoad);
};
};
};
So what values is for? The first valu imageToLoad is where you would put the images you want to use and imageLoad is where you would find your loaded images. Finaly, for the peoples interested in the algorithm, the algorithm would every time an image is load see if it the last image to load, if yes, the algorithm would start in my case the gameloop of the game.

How to render HTML pages as PNG/JPEG images on single click using URLs Tabs array in Javascript only?

I am building a chrome extension using Javascript which gets URLs of the opened tabs and saves the html file, but the problem with html is that it does not render images on webpages fully. So i changed my code to loop each URLs of the tabs and then save each html pages as image file automatically in one click on the download icon of the chrome extension. I have been researching for more than 2 days but nothing happened. Please see my code files and guide me. I know there is library in nodejs but i want to perform html to jpeg/png maker using chrome extension only.
Only icons i have not attached which i have used in this extension, all code i have and the text in popup.js which is commented i have tried.
Current output of the attached code
Updated popup.js
File popup.js - This file has functions which gets all the URLs of the opened tabs in the browser window
// script for popup.html
window.onload = () => {
// var html2obj = html2canvas(document.body);
// var queue = html2obj.parse();
// var canvas = html2obj.render(queue);
// var img = canvas.toDataURL("image/png");
let btn = document.querySelector("#btnDL");
btn.innerHTML = "Download";
function display(){
// alert('Click button is pressed')
window.open("image/url");
}
btn.addEventListener('click', display);
}
chrome.windows.getAll({populate:true}, getAllOpenWindows);
function getAllOpenWindows(winData) {
var tabs = [];
for (var i in winData) {
if (winData[i].focused === true) {
var winTabs = winData[i].tabs;
var totTabs = winTabs.length;
console.log("Number of opened tabs: "+ totTabs);
for (var j=0; j<totTabs;j++) {
tabs.push(winTabs[j].url);
// Get the HTML string in the tab_html_string
tab_html_string = get_html_string(winTabs[j].url)
// get the HTML document of each tab
tab_document = get_html_document(tab_html_string)
console.log(tab_document)
let canvasref = document.querySelector("#capture");
canvasref.appendChild(tab_document.body);
html2canvas(document.querySelector("#capture")).then(canvasref => {
document.body.appendChild(canvasref)
var img = canvasref.toDataURL("image/png");
window.open(img)
});
}
}
}
console.log(tabs);
}
function get_html_document(tab_html_string){
/**
* Convert a template string into HTML DOM nodes
*/
var parser = new DOMParser();
var doc = parser.parseFromString(tab_html_string, 'text/html');
return doc;
}
function get_html_string(URL_string){
/**
* Convert a URL into HTML string
*/
let xhr = new XMLHttpRequest();
xhr.open('GET', URL_string, false);
try {
xhr.send();
if (xhr.status != 200) {
alert(`Error ${xhr.status}: ${xhr.statusText}`);
} else {
return xhr.response
}
} catch(err) {
// instead of onerror
alert("Request failed");
}
}
File popup.html - This file represent icon and click functionality on the chrome browser search bar
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> -->
<script src= './html2canvas.min.js'></script>
<script src= './jquery.min.js'></script>
<script src='./popup.js'></script>
<title>Capture extension</title>
<!--
- JavaScript and HTML must be in separate files: see our Content Security
- Policy documentation[1] for details and explanation.
-
- [1]: http://developer.chrome.com/extensions/contentSecurityPolicy.html
-->
</head>
<body>
<button id="btnDL"></button>
</body>
</html>
File manifest.json - This file is used by the chrome browser to execute the chrome extension
{
"manifest_version": 2,
"name": "CIP screen capture",
"description": "One-click download for files from open tabs",
"version": "1.4.0.2",
"browser_action": {
"default_popup": "popup.html"
},
"permissions": [
"downloads", "tabs", "<all_urls>"
],
"options_page": "options.html"
}
You can use the library html2canvas which renders any html element, particularly the body element, and from the resulted canvas you can have your image
<script type="text/javascript" src="https://github.com/niklasvh/html2canvas/releases/download/v1.0.0-rc.7/html2canvas.min.js"></script>
<script>
html2canvas(document.body).then(
(canvas) => {
var img = canvas.toDataURL("image/png");
}
);
</script>
You can get html2canvas from any public CDN, like this one. You don't need nodeJS. Or perhaps directly from the original git repo
<script type="text/javascript" src="https://github.com/niklasvh/html2canvas/releases/download/v1.0.0-rc.7/html2canvas.min.js"></script>
You can also save canvas as a blob
html2canvas(document.body).then(function(canvas) {
// Export canvas as a blob
canvas.toBlob(function(blob) {
// Generate file download
window.saveAs(blob, "yourwebsite_screenshot.png");
});
});
It's possible with vanilla JS, I guess vanilla is more likely to be used on a extension, the drawback is the end result, when a 3rd party library my already fixed the issues you will encounter with fonts and style (html2canvas or whatever).
So, vanilla js, for some reason stack overflow snippet does not permit window.open, demo here: https://jsfiddle.net/j67nqsme/
Few words on how it was implemented:
using html to svg transformation, a 3rd party library can be used here
using canvas to transform svg into pdg or jpg
example can export html or page to svg, png, jpg
it is not bullet proof - rendering can suffer, style, fonts, ratios, media query
Disclaimer: I won't help you debug or find solution of your problem, it is an answer to your question using vanilla js, from there on is your decision what you are using or how you are using it.
Source code bellow:
<html>
<body>
<script>
function export1() {
const html = '<div style="color:red">this is <br> sparta </div>';
renderHtmlToImage(html, 800, 600, "image/png");
}
function export2() {
renderDocumentToImage(window.document, 800, 600, "image/png");
}
// format is: image/jpeg, image/png, image/svg+xml
function exportImage(base64data, width, height, format) {
var img = new Image();
img.onload = function () {
if ("image/svg+xml" == format) {
var w = window.open("");
w.document.write(img.outerHTML);
w.document.close();
}
else {
const canvas = document.createElement("Canvas");
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
ctx.fillStyle = "white";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, 0, 0);
var exportImage = new Image();
exportImage.onload = function () {
var w = window.open("");
w.document.write(exportImage.outerHTML);
w.document.close();
}
exportImage.src = canvas.toDataURL(format);
}
}
img.src = base64data;
}
// format is: image/jpeg, image/png, image/svg+xml
function renderHtmlToImage(html, width, height, format) {
var svgData = '<svg xmlns="http://www.w3.org/2000/svg" width="' + width + '" height="' + height + '">'
+ '<foreignObject width="100%" height="100%">'
+ html2SvgXml(html)
+ '</foreignObject>'
+ '</svg>';
var base64data = "data:image/svg+xml;base64," + btoa(svgData);
exportImage(base64data, width, height, format);
}
function renderDocumentToImage(doc, width, height, format) {
var svgData = '<svg xmlns="http://www.w3.org/2000/svg" width="' + width + '" height="' + height + '">'
+ '<foreignObject width="100%" height="100%">'
+ document2SvgXml(doc)
+ '</foreignObject>'
+ '</svg>';
var base64data = "data:image/svg+xml;base64," + btoa(svgData);
exportImage(base64data, width, height, format);
}
// plain html to svgXml
function html2SvgXml(html) {
var htmlDoc = document.implementation.createHTMLDocument('');
htmlDoc.write(html);
// process document
return document2SvgXml(htmlDoc);
}
// htmlDocument to
function document2SvgXml(htmlDoc) {
// Set the xmlns namespace
htmlDoc.documentElement.setAttribute('xmlns', htmlDoc.documentElement.namespaceURI);
// Get XML
var svcXml = (new XMLSerializer()).serializeToString(htmlDoc.body);
return svcXml;
}
</script>
<div>
<h3 style="color:blue">My Title</h3>
<div style="color:red">
My Text
</div>
<button onclick="export1()">Export Plain Html</button>
<button onclick="export2()">Export Entire Document</button>
</div>
</body>
</html>
There are 3 ways this could be approached:
Render this in client javascript using an API like HTML2Canvas. It's isolated, runs in the browser, but relies on a re-render that could get details of the captured page wrong (see most issues with H2C). That might be fine if you just want a small preview and don't mind the odd difference. Also be careful as the render is slow and somewhat heavyweight - background renders of large pages may be noticeable by users, but so will waits for the images to render.
Use a service that runs Chrome to visit the page and then screenshot it. You could write this or buy in a service like Site-Shot to do it for you. This requires a service which will have a cost, but can guarantee the render is accurate and ensures the load on the users' machines is minimal.
Use the Chrome tab capture API to screenshot the tab. This is probably the best option for an extension, but currently you can only capture the current active tab. captureOffscreenTab is coming soon, but currently only in Canary behind a flag.
I'd recommend option 3, as by the time you have finished the component you could have access to the new features. If you need to release soon you could use 1 or 2 as a short term solution.

How to wait until onload event completes its work in JavaScript?

I'm developing a printing tool using HTML5 canvas. As a test, I've tried to draw an image and a rectangle on the canvas, and then copy it to a new window for printing, using the code below. But all I'm getting in the new window is a blank page.
<!DOCTYPE HTML>
<html>
<head>
</head>
<body>
<canvas id="pageCanvas"></canvas>
<script type="text/javascript">
var canvas = document.getElementById("pageCanvas");
canvas.height="700";
canvas.width="1000";
var ctx = canvas.getContext("2d");
var imageData="data:image/png;base64,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";
var imageObj = new Image();
imageObj.src = imageData;
imageObj.addEventListener("load", function() {
ctx.drawImage(imageObj, 50, 100,1000,600);
ctx.beginPath();
ctx.rect(100, 101, 200, 100);
ctx.lineWidth = 7;
ctx.strokeStyle = 'black';
ctx.stroke();
}, false);
var printWindow = window.open('');
printWindow.document.write('<html><BODY>');
printWindow.document.write('<center>');
printWindow.document.write('<img src="' + canvas.toDataURL()+'"/>');
printWindow.document.write('</center></body></html>');
printWindow.document.close();
printWindow.print();
</script>
</body>
</html>
Can you please guide me to overcome this issue?
You're opening the new window and trying to copy the content of the canvas onto it immediately after attaching the load event handler to the image, before the handler has actually had a chance to execute.
Just move all the JS code starting with the var printWindow = window.open(''); line inside the event handler, and it should work.
Oh, and please indent your code, especially if you expect anyone else to read it.
Addendum: If you want to wait until multiple images have loaded, the simplest way is to count the load events and call a function when all of them have fired, like this:
var imageURLs = [ ... image URLs here ... ];
var imageObjs = [];
var imagesLoaded = 0;
for (var i = 0; i < imageURLs.length; i++) {
var image = new Image();
image.addEventListener( "load", function() {
imagesLoaded++;
if (imagesLoaded == imageURLs.length) allImagesLoaded();
} );
image.src = imageURLs[i];
imageObjs.push(image);
}
function allImagesLoaded() {
// now do something with imageObjs
};
You could also get fancy and play with things like ES6 promises, but ultimately, the end result is the same.
See also:
Can I sync up multiple image onload calls?
Javascript - wait images to be loaded

Save canvas and use it as background img

Any-Kind-Soul-Out-there,
I spending hours figuring out how could i done the coding in such a way that when after user drawn on the canvas, they can click a btn called "save". After which the canvas's image will appear as a BG img of the webpage.
Even after user close the web browser, the bg img is still there when user open it again. I'm not sure is it possible to do it or not.
Need some help here, if need my full coding i can provide.
Below is my current coding when user clicked "save" btn. (Open new window as an image.)
// Save image
var saveImage = document.createElement("button");
saveImage.innerHTML = "Save canvas";
saveImage.addEventListener("click", function (evt) {
window.open(canvas.toDataURL("image/png"));
evt.preventDefault();
}, false);
document.getElementById("main-content").appendChild(saveImage);
You might use toDataURL to set the background, and localStorage to store 'permanently' the image :
http://jsbin.com/japekuzi/1/
use draw to fill the canvas with random rects, and set button to set and store current canvas as background.
Notice that when you (re)run the jsbin, it stills keeps its latest background.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<canvas id='cv'></canvas>
<button id='dr'>draw</button>
<button id='st'>set</button>
</body>
</html>
JS :
var $=document.getElementById.bind(document);
var cv = $('cv');
var ctx = cv.getContext('2d');
function randFill() {
ctx.clearRect(0,0,cv.width, cv.height);
for(var i=0; i<10; i++) {
var c= 0 | ( Math.random()* 360);
ctx.fillStyle = 'hsl('+c+',75%,75%)';
ctx.fillRect(Math.random()*cv.width*0.8,
Math.random()*cv.height*0.8, 20, 20);
}
}
function set() {
localStorage.setItem("bg", cv.toDataURL());
retrieve();
}
function retrieve() {
var cvURL = localStorage.getItem("bg", cv.toDataURL());
if (!cvURL) return;
document.body.style. backgroundImage ='url('+ cvURL+')';
}
randFill();
retrieve();
$('dr').onclick=randFill;
$('st').onclick=set;

javaScript multiple time image not loading

I am drawing image which is loaded using loader method in two different places. But it only displays the second one. (I am following this http://www.html5canvastutorials.com/tutorials/html5-canvas-image-loader/)
If I add an alert() it works in Fx but not in Chrome. I want it to work everywhere without alert()
If I try drawing Image without using preloaded image I am getting the desired result. But I am thinking it is extra load (http://www.html5canvastutorials.com/tutorials/html5-canvas-images/)
ImageOnload("O",120,120); //This image not displaying
alert("If i add alert it works only in Fx but not in Chrome")
ImageOnload("O",120,20);//only this is displaying ???
<html>
<head>
</head>
<script type="text/javascript" >
var ctx;
var ImageVariable={};
window.onload= function()
{
var canvas = document.getElementById("gameLoop");
ctx = canvas.getContext("2d");
ImageBuilder(ImageSourceDB);
ImageOnload("O",120,120); //This image is not displaying
//alert("If i add alert it works only in FFox but not in chrome")
ImageOnload("O",120,20);
}
var ImageSourceDB=
{
X:"./Images/X.gif",
O:"./Images/O.gif"
}
function ImageBuilder(ImageSrcDB)
{
for (iSrc in ImageSrcDB)
{
ImageVariable[iSrc]= new Image();
ImageVariable[iSrc].src = ImageSrcDB[iSrc];
}
}
function ImageOnload(ImageSrc,x,y)
{
ImageVariable[ImageSrc].onload= function ()
{
ctx.drawImage(ImageVariable[ImageSrc],x,y);
};
ImageVariable[ImageSrc].src = ImageSourceDB[ImageSrc];
}
</script>
<body>
<canvas class ="pattern" id="gameLoop" height="300" width="300" />
</body>
</html>
List item
ImageOnload("O",120,120); //This image not displaying
ImageOnload("O",120,20);//only this is displaying ???
You forgot to change the id of the object:
ImageOnload("O",120,120);
ImageOnload("X",120,20); // Use "X", not "O"!!!
If you still want to show "O" twice, then you should draw it twice, but with only one onload function. See example below:
<script type="text/javascript" >
var ctx;
var ImageVariable={};
var ImageSourceDB = {
X:"./Images/X.gif",
O:"./Images/O.gif"
}
window.onload = function() {
var canvas = document.getElementById("gameLoop");
ctx = canvas.getContext("2d");
ImageBuilder(ImageSourceDB);
ImageVariable["O"].onload = function() {
// this will be executed when the image "O" is loaded
// this is a pointer to ImageVariable["O"]
ctx.drawImage(this, 120, 120);
ctx.drawImage(this, 120, 20);
}
ImageVariable["X"].onload = function() {
// this will be executed when the image "X" is loaded
ctx.drawImage(this, 30, 30);
}
}
function ImageBuilder(ImageSrcDB) {
for (iSrc in ImageSrcDB) {
ImageVariable[iSrc]= new Image();
ImageVariable[iSrc].src = ImageSrcDB[iSrc];
}
}
</script>

Categories