downloading images of two different d3 graphs in single html page? - javascript

I created an html page for my tool which works offline(client side). This page is creating two different d3 based graph and I created two different buttons (save and save1)for each graph to downlaod images of these. These two image download button works fine, when tested separately in two different html pages.
Now, Problem in combined html page, is that each button is downloading the image of first d3 based graph only.
I defined two different svg variable (svg and svg1) for each graph creation but i donot know how to call it differently in downloadimage script.
**I think there is problem while calling "node( ).parentNode.innerHTML;" (mentioned in following svg downlaod script)?
But I don't know how to call different SVG in this script.
This is my first time, I am working on d3.
**
d3.select("#save1").on("click", function(){ //button save in first graph;
var html1 = d3.select("svg") //var html in first graph;
.attr("version", 1.1)
.attr("xmlns", "http://www.w3.org/2000/svg")
.node( ).parentNode.innerHTML;
//console.log(html);
var imgsrc = 'data:image/svg+xml;base64,'+ btoa(html1);
var image = new Image;
image.src = imgsrc;
image.onload = function() {
var canvas = document.createElement('canvas');
canvas.width = image.width;
canvas.height = image.height;
var context = canvas.getContext('2d');
context.fillStyle = "#FFFFFF";
context.fillRect(0,0,image.width,image.height);
context.drawImage(image, 0, 0);
var a = document.createElement('a');
a.download = "image.png";
a.href = canvas.toDataURL('image/png');
document.body.appendChild(a);
a.click();
}
});

This line:
var html1 = d3.select("svg")
Is always selecting the first SVG in the DOM, regardless the button you click.
Instead of that, give your SVGs unique IDs (like svg1 and svg2), and select by those IDs:
var html1 = d3.select("#svg1")
var html2 = d3.select("#svg2")

Related

Overlay two base64 image url and save them as single image in Javascript

I have a whiteboard option during a video call in my web application built in angularjs (1.x). Users can draw above the video in a canvas element. I need to take a screenshot of the current video position and drawing on the canvas. I am able to get the video frame as base64 URL(second image) and canvas drawing as base64 URL(third image) separately. But I need to get it as a combined single image in base64 URL like the first image.
HTML
<img id="img1">
<img id="img2">
<canvas id="mergedImage" width="382" height="510"></canvas>
JS
var drawingImg1 = document.getElementById('img1');
drawingImg1.setAttribute('src', img1);
var drawingImg2 = document.getElementById('img2');
drawingImg2.setAttribute('src', img2);
var c = document.getElementById('mergedImage');
var width = 382;
var height = 510;
var ctx = c.getContext("2d");
var imageObj2 = new Image();
imageObj2.onload = function (){
ctx.drawImage(imageObj2, 0, 0, width, height);
var imageObj1 = new Image();
imageObj1.onload = function (){
imageObj1.style.objectFit = "cover";
ctx.drawImage(imageObj1, 0, 0,width, height);
};
imageObj1.src = img2;
};
imageObj2.src = img1;
I tried the above code and it gives the output as video frame image only not the drawing included.
I want the output as the first image. Please, someone, guide me to do this.
I have created a jsfiddle here
The following solution worked for me to overlap 2 images and got a single image in a canvas.
Link

how to take a screenshot of piece of a webpage with phantomjs?

I understand how to take screenshot of entire webpage but how about capturing the view of an specific element using phantomjs.
I'm trying as follow
var page = require('webpage').create();
page.content = page.open('https://www.google.co.in/');
page.evaluate(function() {
var canvas = document.getElementById('hplogo');
var ctx = canvas.getContext('2d');
var img = new Image();
var imgdata = document.querySelectorAll('img');
img.src = imgdata[0].src;
var pattern = ctx.createPattern(img, 'repeat');
ctx.fillStyle = pattern;
ctx.fillRect(0, 0, 300, 300);
});
page.render('canvas.png');
phantom.exit();
Above code is not working, What 'm doing in above code is selecting the element of Google webpage img section though id then create an object of image and assign the src of query selected tag IMG and then fill the pattern, my hours of hard work did not yield any result.
WHAT I WANT: I want the screenshot of an img element rendered through 'page.open' which can be selected by query selector and output the png file. OTHER ALTERNATIVES OF PHANTOMJS ARE WELCOME.
Thanks in advance..

Angular 6 - Export SVG from DOM [duplicate]

I currently have a website using D3 and I'd like the user to have the option to save the SVG as an SVG file. I'm using crowbar.js to do this, but it only works on chrome. Nothing happens of safari and IE gives an access denied on the click() method used in crowbar.js to download the file.
var e = document.createElement('script');
if (window.location.protocol === 'https:') {
e.setAttribute('src', 'https://raw.github.com/NYTimes/svg-crowbar/gh-pages/svg-crowbar.js');
} else {
e.setAttribute('src', 'http://nytimes.github.com/svg-crowbar/svg-crowbar.js');
}
e.setAttribute('class', 'svg-crowbar');
document.body.appendChild(e);
How do I download an SVG file based on the SVG element on my website in safari, IE and chrome?
There are 5 steps. I often use this method to output inline svg.
get inline svg element to output.
get svg source by XMLSerializer.
add name spaces of svg and xlink.
construct url data scheme of svg by encodeURIComponent method.
set this url to href attribute of some "a" element, and right click this link to download svg file.
//get svg element.
var svg = document.getElementById("svg");
//get svg source.
var serializer = new XMLSerializer();
var source = serializer.serializeToString(svg);
//add name spaces.
if(!source.match(/^<svg[^>]+xmlns="http\:\/\/www\.w3\.org\/2000\/svg"/)){
source = source.replace(/^<svg/, '<svg xmlns="http://www.w3.org/2000/svg"');
}
if(!source.match(/^<svg[^>]+"http\:\/\/www\.w3\.org\/1999\/xlink"/)){
source = source.replace(/^<svg/, '<svg xmlns:xlink="http://www.w3.org/1999/xlink"');
}
//add xml declaration
source = '<?xml version="1.0" standalone="no"?>\r\n' + source;
//convert svg source to URI data scheme.
var url = "data:image/svg+xml;charset=utf-8,"+encodeURIComponent(source);
//set url value to a element's href attribute.
document.getElementById("link").href = url;
//you can download svg file by right click menu.
I know this has already been answered, and that answer works well most of the time. However I found that it failed on Chrome (but not Firefox) if the svg image was large-ish (about 1MB). It works if you go back to using a Blob construct, as described here and here. The only difference is the type argument. In my code I wanted a single button press to download the svg for the user, which I accomplished with:
var svgData = $("#figureSvg")[0].outerHTML;
var svgBlob = new Blob([svgData], {type:"image/svg+xml;charset=utf-8"});
var svgUrl = URL.createObjectURL(svgBlob);
var downloadLink = document.createElement("a");
downloadLink.href = svgUrl;
downloadLink.download = "newesttree.svg";
document.body.appendChild(downloadLink);
downloadLink.click();
document.body.removeChild(downloadLink);
October 2019 edit:
Comments have indicated that this code will work even without appending downloadLink to document.body and subsequently removing it after click(). I believe that used to work on Firefox, but as of now it no longer does (Firefox requires that you append and then remove downloadLink). The code works on Chrome either way.
Combining Dave's and defghi1977 answers. Here is a reusable function:
function saveSvg(svgEl, name) {
svgEl.setAttribute("xmlns", "http://www.w3.org/2000/svg");
var svgData = svgEl.outerHTML;
var preface = '<?xml version="1.0" standalone="no"?>\r\n';
var svgBlob = new Blob([preface, svgData], {type:"image/svg+xml;charset=utf-8"});
var svgUrl = URL.createObjectURL(svgBlob);
var downloadLink = document.createElement("a");
downloadLink.href = svgUrl;
downloadLink.download = name;
document.body.appendChild(downloadLink);
downloadLink.click();
document.body.removeChild(downloadLink);
}
Invocation example:
saveSvg(svg, 'test.svg')
For this snippet to work you need FileSaver.js.
function save_as_svg(){
var svg_data = document.getElementById("svg").innerHTML //put id of your svg element here
var head = '<svg title="graph" version="1.1" xmlns="http://www.w3.org/2000/svg">'
//if you have some additional styling like graph edges put them inside <style> tag
var style = '<style>circle {cursor: pointer;stroke-width: 1.5px;}text {font: 10px arial;}path {stroke: DimGrey;stroke-width: 1.5px;}</style>'
var full_svg = head + style + svg_data + "</svg>"
var blob = new Blob([full_svg], {type: "image/svg+xml"});
saveAs(blob, "graph.svg");
};
I tryed every solution here and nothing worked for me. My picture was always smaller than my d3.js canvas.
I had to set the canvas width, height then do a clearRect on the context to make it works. Here is my working version
Export function:
var svgHtml = document.getElementById("d3-canvas"),
svgData = new XMLSerializer().serializeToString(svgHtml),
svgBlob = new Blob([svgData], {type:"image/svg+xml;charset=utf-8"}),
bounding = svgHtml.getBoundingClientRect(),
width = bounding.width * 2,
height = bounding.height * 2,
canvas = document.createElement("canvas"),
context = canvas.getContext("2d"),
exportFileName = 'd3-graph-image.png';
//Set the canvas width and height before loading the new Image
canvas.width = width;
canvas.height = height;
var image = new Image();
image.onload = function() {
//Clear the context
context.clearRect(0, 0, width, height);
context.drawImage(image, 0, 0, width, height);
//Create blob and save if with FileSaver.js
canvas.toBlob(function(blob) {
saveAs(blob, exportFileName);
});
};
var svgUrl = URL.createObjectURL(svgBlob);
image.src = svgUrl;
It use FileSaver.js to save the file.
This is my canvas creation, note that i solve the namespace issue here
d3.js canvas creation:
var canvas = d3.select("body")
.insert("svg")
.attr('id', 'd3-canvas')
//Solve the namespace issue (xmlns and xlink)
.attr("xmlns", "http://www.w3.org/2000/svg")
.attr("xmlns:xlink", "http://www.w3.org/1999/xlink")
.attr("width", width)
.attr("height", height);
While this question has been answered, I created a small library called SaveSVG which can help save D3.js generated SVG which use external stylesheets or external definition files (using <use> and def) tags.
Based on #vasyl-vaskivskyi 's answer.
<script src="../../assets/FileSaver.js"></script>
<script>
function save_as_svg(){
fetch('path/../assets/chart.css')
.then(response => response.text())
.then(text => {
var svg_data = document.getElementById("svg").innerHTML
var head = '<svg title="graph" version="1.1" xmlns="http://www.w3.org/2000/svg">'
var style = "<style>" + text + "</style>"
var full_svg = head + style + svg_data + "</svg>"
var blob = new Blob([full_svg], {type: "image/svg+xml"});
saveAs(blob, "graph.svg");
})
};
save_as_svg();
</script>
The above code read your chart.css and then embed the css code to your svg file.
I try this and worked for me.
function downloadSvg() {
var svg = document.getElementById("svg");
var serializer = new XMLSerializer();
var source = serializer.serializeToString(svg);
source = source.replace(/(\w+)?:?xlink=/g, 'xmlns:xlink='); // Fix root xlink without namespace
source = source.replace(/ns\d+:href/g, 'xlink:href'); // Safari NS namespace fix.
if (!source.match(/^<svg[^>]+xmlns="http\:\/\/www\.w3\.org\/2000\/svg"/)) {
source = source.replace(/^<svg/, '<svg xmlns="http://www.w3.org/2000/svg"');
}
if (!source.match(/^<svg[^>]+"http\:\/\/www\.w3\.org\/1999\/xlink"/)) {
source = source.replace(/^<svg/, '<svg xmlns:xlink="http://www.w3.org/1999/xlink"');
}
var preface = '<?xml version="1.0" standalone="no"?>\r\n';
var svgBlob = new Blob([preface, source], { type: "image/svg+xml;charset=utf-8" });
var svgUrl = URL.createObjectURL(svgBlob);
var downloadLink = document.createElement("a");
downloadLink.href = svgUrl;
downloadLink.download = name;
document.body.appendChild(downloadLink);
downloadLink.click();
document.body.removeChild(downloadLink);
}
In my scenario, I had to use some svg images created using D3.js in other projects. So I opened dev tools and inspected those svg and copied their content. Then created a new blank svg file and pasted the copied content there. Then I used those new svg files in other areas.
And if you want to do it programmatically, then we can use document.getElementById('svgId')
I know this is a basic approach but in case anyone find it useful.

How to export multiple html tables and multiple d3 generated graphs into a single pdf

Basically I have multiple tables that are generated in html (also the data may vary depends on how much data are in the database, so I want the tables on pdf to be scalable as well, meaning no fixed size.) In addition, I have a d3 generated graph too on the same page.
What I want to know is..is there any way to turn everything displayed on the page into a pdf like a screenshot? I know there is phantomJS but it requires you to install and deploy on the local environment, and our project won't allow it.. so is there any 3rd party libraries that I can import and use to export them into a single PDF?
Please help
Using SaveSvg.js
https://gist.github.com/enjoylife/0ae74717a29862c5d8c5
and using jspdf was able to make it work
d3.select("#save").on("click", function(){
var html = d3.select("svg")
.attr("version", 1.1)
.attr("xmlns", "http://www.w3.org/2000/svg")
.node().parentNode.innerHTML;
//console.log(html);
var imgsrc = 'data:image/svg+xml;base64,'+ btoa(html);
var img = '<img src="'+imgsrc+'">';
d3.select("#svgdataurl").html(img);
var canvas = document.querySelector("canvas"),
context = canvas.getContext("2d");
var image = new Image;
image.src = imgsrc;
image.onload = function() {
context.drawImage(image, 0, 0);
//save and serve it as an actual filename
binaryblob();
var a = document.createElement("a");
a.download = "sample.png";
a.href = canvas.toDataURL("image/png");
/* Added as png to jspdf */
var doc = new jsPDF();
doc.addImage( a.href, "png", 0,0);
doc.save("test.pdf");
var pngimg = '<img src="'+a.href+'">';
d3.select("#pngdataurl").html(pngimg);
a.click();
};
});
jspdf alignment and css is good
http://plnkr.co/edit/nNSvHL8MZcT6nNKg9CG9?p=preview

Save multiple images in canvas JQuery

Can we save the image in canvas. Like as shown in the JSFiddle.
I want to save the image in such a way the balloon should come over the image
$(document).ready(function() {
var d_canvas = document.getElementById('canvas');
var context = d_canvas.getContext('2d');
var background = document.getElementById('background');
var ballon = document.getElementById('ballon')
context.drawImage(background, 0, 0);
$('#ballon').draggable();
$('#draw').click(function() {
var $ballon = $('#ballon'),
$canvas = $('#canvas');
var ballon_x = $ballon.offset().left - $canvas.offset().left,
ballon_y = $ballon.offset().top - $canvas.offset().top;
context.drawImage(ballon, ballon_x, ballon_y);
$ballon.hide();
$(this).attr('disabled', 'disabled');
});
});
There are generally two ways to get an image from a canvas:
using getImageData() to get the rgba value for every pixel for a given rectangle of the canvas.
using toDataURL() to get a Base64 string of the entire canvas.
The second method is probably most useful, and combined with some HTML5 magic, and the download attribute, we can create a downloadable image or send the string to the server and save it as an image :
var base64 = d_canvas.toDataURL("image/png");
var a = document.createElement('a');
a.href = base64,
a.target = '_blank';
a.download = 'myImage.png';
document.body.appendChild(a);
a.click();
If you need the baloon to be in a specific place, moving that should be trivial.
Here's a
FIDDLE
Note that I had to remove the external images and use base64 to avoid cross-origin images in the canvas.

Categories

Resources