I have a app that shows coloured dots moving across the screen, following set routes. There is a save button the saves the current screen to a .png format.
The problem I am having is that if I click the save image button several times the images don't just show the current position of that click, they show all previous positions from when the save button was clicked.
E.g. if at click 1 the dot is as position 1 and click 2 it is at position 2. Image two will show positions 1 and 2. A third image would show positions 1,2 and 3.
Obviously there is an issue with layering or not clearing the canvas but I can't see the problem.
the save code (wrapped in an AngularJS app) is :
$scope.saveImage = function() {
var stageWidth = jQuery("#mainStage").width();
var stageHeight = jQuery("#mainStage").height();
var html = d3.select("#mainStage")
.attr("version", 1.1)
.attr("xmlns", "http://www.w3.org/2000/svg")
.attr("width",stageWidth)
.attr("height",stageHeight)
.node().parentNode.innerHTML;
var imgsrc = 'data:image/svg+xml;base64,' + btoa(html);
jQuery("#canvas").height(stageHeight);
jQuery("#canvas").width(stageWidth);
var canvas = document.getElementById("canvas");
var context = document.querySelector('canvas').getContext("2d");
var image = new Image;
image.src = imgsrc;
image.onload = function() {
context.drawImage(image,0,0);
var canvasdata = canvas.toDataURL("image/png");
var pngimg = '<img src="' + canvasdata + '">';
var a = document.createElement("a");
console.log(a);
a.download = "sample.png";
a.href = canvasdata;
a.click();
};
}
Thanks in advance.
This would mean that it has not been through the digest loop. A common problem with mixing jQuery and AngularJs. Add a watcher.
Related
I cannot get my image to display in an HTML canvas using drawImage(). I know the filepath is correct because the image displays just fine when I disable display: none;
I know this can occur when you attempt to draw an image before it is loaded, which you can avoid by using the onload property.
Here is the relevant HTML.
<canvas id='gameScreen'></canvas>
<img id="imgBall"src="assets/images/ball2.png" alt="ball">
<script type="module"src="src/index.js"></script>
Here is the relevant Javascript.
// CANVAS SETUP
let canvas = document.getElementById("gameScreen");
canvas.width = 800;
canvas.height = 600;
let ctx = canvas.getContext("2d");
// DISPLAY BALL
let imgBall = document.getElementById('imgBall');
imgBall.onload = function() {
console.log(imgBall.src + ' successfully loaded');
ctx.drawImage(imgBall, 10, 10);
}
imgBall.onerror = function() {
console.log(imgBall.src + ' failed to load');
}
What makes this so confusing to me is that I'm not getting any console messages from imgBall.onload, or from imgBall.onerror.
I'm pretty new to Javascript and canvas, so I apologize if the answer is extremely obvious.
To fix the issue I am dynamically creating an image tag and then giving it a src AFTER I have added the event handlers for error and onload.
This makes me think that the issue is due to the image loading BEFORE your script tag had a chance to add the event listeners to the img tag.
// CANVAS SETUP
let canvas = document.getElementById("gameScreen");
canvas.width = 800;
canvas.height = 600;
let ctx = canvas.getContext("2d");
// DISPLAY BALL
const imgBall = document.createElement("img");
imgBall.onload = function() {
console.log(imgBall.src + ' successfully loaded');
ctx.drawImage(fitImageOntoCanvas(imgBall,25,25), 10, 10);
}
imgBall.onerror = function() {
console.log(imgBall.src + ' failed to load');
}
imgBall.src = "https://pngimg.com/uploads/football/football_PNG52737.png"
// need to resize because my ball image is huge
// thanks #markE https://stackoverflow.com/questions/38664890/resize-images-with-canvas-before-uploading
function fitImageOntoCanvas(img,MAX_WIDTH,MAX_HEIGHT){
// calculate the scaling factor to resize new image to
// fit MAX dimensions without overflow
var scalingFactor=Math.min((MAX_WIDTH/img.width),(MAX_HEIGHT/img.height))
// calc the resized img dimensions
var iw=img.width*scalingFactor;
var ih=img.height*scalingFactor;
// create a new canvas
var c=document.createElement('canvas');
var ctx=c.getContext('2d');
// resize the canvas to the new dimensions
c.width=iw;
c.height=ih;
// scale & draw the image onto the canvas
ctx.drawImage(img,0,0,iw,ih);
// return the new canvas with the resized image
return(c);
}
<canvas id="gameScreen" height="500" width="500"></canvas>
I am trying to set up a generator to let people custom build wallpapers for their phones. At the moment I have them doing the customizing by editing an svg template by changing the colors and text through a form which is working perfectly.
Then once they click submit they are prompted to download their wallpaper as a png. Once the button is clicked I am drawing the svg to a hidden canvas and then the png begins downloading from there.
I am using a link to multiple Adobe fonts for the styling of the wallpaper. The problem is, every time I attempt to download the PNG from mobile or a smaller window size, if I was using one of the adobe fonts, the font gets swapped.
The hidden canvas is width 1125px and height 2536px and I have the custom svg fit to match the size. I have little experience with Canvas so I am not sure what to do but my best guess is that the problem lies in the size of the canvas.
This is the code I have for my download. If you need more information please let me know but my goal here is to get this to work so that the png will be downloaded in high quality from any size window.
var btn = document.getElementById('myBtn');
var svg = document.getElementById('bg2');
var canvas = document.querySelector('canvas');
function triggerDownload (imgURI) {
var evt = new MouseEvent('click', {
view: window,
bubbles: false,
cancelable: true
});
if(document.getElementById("name").value=="null" || document.getElementById("name").value=="") {
var un = "MakeAGraphic";
} else {
var enteredName = document.getElementById("name").value.replace(/[^a-zA-Z ]/g, "");
var un = `${enteredName}_MakeAGraphic`
}
var a = document.createElement('a');
a.setAttribute('download', `${un}.png`);
a.setAttribute('href', imgURI);
a.setAttribute('target', '_blank');
a.dispatchEvent(evt);
}
btn.addEventListener('click', function () {
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var data = (new XMLSerializer()).serializeToString(svg);
var DOMURL = window.URL || window.webkitURL || window;
var img = new Image();
var svgBlob = new Blob([data], {type: 'image/svg+xml;charset=utf-8'});
var url = DOMURL.createObjectURL(svgBlob);
img.onload = function () {
ctx.drawImage(img, 0, 0);
DOMURL.revokeObjectURL(url);
var imgURI = canvas
.toDataURL('image/png')
.replace('image/png', 'image/octet-stream');
triggerDownload(imgURI);
};
img.src = url;
});
I have svg-png almost working perfectly client side, just in javascript/d3 it all works, but it loses large amounts of detail. Can anyone shed light on why this might be?:
The original image is:
var svg = document.querySelector( "svg" );
var svgData = new XMLSerializer().serializeToString( svg );
var canvas = document.createElement("canvas");
canvas.width = d3.select("svg").attr("width");
canvas.height = d3.select("svg").attr("height");
ctx = canvas.getContext("2d");
var img = document.createElement( "img" );
img.setAttribute( "src", "data:image/svg+xml;base64," + btoa( svgData ) );
img.onload = function() {
ctx.drawImage( img, 0, 0 );
var canvasdata = canvas.toDataURL("image/png");
console.log(canvasdata)
var pngimg = '<img src="'+canvasdata+'">';
d3.select("#pngdataurl").html(pngimg);
var a = document.createElement("a");
a.download = "name"+".png";
a.href = canvasdata;
console.log(a.click())
};
The output of that is:
I also tried:
var html = d3.select("svg")
.attr("version", 1.1)
.attr("xmlns", "http://www.w3.org/2000/svg")
.node().parentNode.innerHTML;
var width = d3.select("svg").attr("width");
var height = d3.select("svg").attr("height");
image.src = 'data:image/svg+xml;base64,'+ btoa(unescape(encodeURIComponent(html)));
but that fails - on the image.onload() I get "HTMLImageElement provided is in the 'broken' state"
Saving an SVG to PNG in the browser will ignore all linked CSS styles applied to the SVG elements.
If you are using d3.js you can add the styles directly to the elements of a particular class using:
d3.selectAll(".mg-main-area").style("color","red");
For more details see this article, which I wrote about rasterising SVG in the browser.
From the comments it seems you have library applying the CSS, so if you don't want to override the styles manually using d3, you could use jQuery code like the below to pull all CSS elements from a class and apply them as inline styles:
$('.mg-main-area').each(function(i, e) {
var st = e.style;
var props = [];
for(var prop in st) {
if($(this).css(prop)) {
props.push(prop + ':' + $(this).css(prop));
}
}
this.style.cssText = props.join(';');
$(this).children().makeCssInline();
});
I have an browse area in which the user browses and enters an image.
I need to know the height and width of the image to limit it.
var img= IWDatacapture.getItem("banners/mobile-banner/mobile-content[1]/main-image");
var params = new Object();
if(img.length==undefined)
{
var savnm = IWDatacapture.getWorkarea() + img.getValue();
params.savnm = savnm;
var server = window.location.hostname;
IWDatacapture.callServer("http://"+server+"/iw-bin/iw_cgi_wrapper.cgi/getFileSize.ipl", params,true);
}
After I make a server call, I didn't understand how to access the image's attributes.
Try something like:
// Get the full image URL:
var img = IWDatacapture.getItem("banners/mobile-banner/mobile-content[1]/main-image");
// Note: I'm not sure if the following will generate the correct URL, but it should be close. Double check the "workarea" part.
var fullImagePath = "/iw/cci/meta/no-injection/iw-mount/" + IWDatacapture.getWorkarea() + img.getValue();
// Then load the image in the browser to get the dimensions:
var image = new Image();
image.onload = function(){
var height = image.height;
var width = image.width;
// Whatever you want to do
}
image.src = fullImagePath;
In Javascript, what's the best way to draw an image to a canvas only if you have the link to the image, like this: http://www.mydomain.com/folder/car.png?
Note: the link will be on the same domain incase you were wondering.
Instantiate an Image(), set the url, and call context.drawImage(params).
http://www.html5canvastutorials.com/tutorials/html5-canvas-images/
http://jsfiddle.net/dYupU/
You just need to define a js Image object, and use drawImage()
var d_canvas = document.getElementById('canvas');
var context = d_canvas.getContext('2d');
var ballon = new Image();
ballon.src = "http://i.imgur.com/6l6v2.png";
context.drawImage(ballon, 100, 1)
Here's an example with multiple links, and an alert inside the loop to show you each link's value
var can = document.getElementById('pictures');
var ctx = can.getContext('2d');
var img = ['http://placekitten.com/200/300','http://placekitten.com/100/100','http://placekitten.com/125/125','http://placekitten.com/50/50','http://placekitten.com/150/300'];
for(var i = 0; i <= img.length - 1; i ++){
var cat = new Image();
cat.src = img[i];
ctx.drawImage(cat, 50, 50);
alert('drew ' + cat.src);
}
DEMO