Convert SVG to image in PNG - angularjs

i am converting angular nvd3 chart to svg using html2canvas and canvg plugings but when i convert pie chart to png then i looks same as chart but when i convert line chart or area chart then its background goes to black and some circle drown on image.
My code is
var svgElements = $("#container").find('svg');
//replace all svgs with a temp canvas
svgElements.each(function () {
var canvas, xml;
// canvg doesn't cope very well with em font sizes so find the calculated size in pixels and replace it in the element.
$.each($(this).find('[style*=em]'), function (index, el) {
$(this).css('font-size', getStyle(el, 'font-size'));
});
canvas = document.createElement("canvas");
canvas.className = "screenShotTempCanvas";
//convert SVG into a XML string
xml = (new XMLSerializer()).serializeToString(this);
// Removing the name space as IE throws an error
xml = xml.replace(/xmlns=\"http:\/\/www\.w3\.org\/2000\/svg\"/, '');
//draw the SVG onto a canvas
canvg(canvas, xml);
$(canvas).insertAfter(this);
//hide the SVG element
////this.className = "tempHide";
$(this).attr('class', 'tempHide');
$(this).hide();
});
html2canvas($("#container"), {
onrendered: function (canvas) {
var a = document.createElement("a");
a.download = "Dashboard.png";
a.href = canvas.toDataURL("image/png");
a.click();
var imgData = canvas.toDataURL('image/png');
var doc = new jsPDF('p', 'mm','a4');
var width = doc.internal.pageSize.width;
var height = doc.internal.pageSize.height;
doc.addImage(imgData, 'PNG', 0, 0, width, height);
doc.save('Dashboard.pdf');
}
});
$("#container").find('.screenShotTempCanvas').remove();
$("#container").find('.tempHide').show().removeClass('tempHide');
Help me guys.
Thanks In Advance

Your svg elements are being styled by the external stylesheet nv.d3.min.css .
canvg seems unable to access external style sheets, so you need to append it directly in your svg node.
To do so, if your style sheet is hosted on the same domain as your scripts, you can do something like :
var sheets = document.styleSheets;
var styleStr = '';
Array.prototype.forEach.call(sheets, function(sheet){
try{ // we need a try-catch block for external stylesheets that could be there...
styleStr += Array.prototype.reduce.call(sheet.cssRules, function(a, b){
return a + b.cssText; // just concatenate all our cssRules' text
}, "");
}
catch(e){console.log(e);}
});
// create our svg nodes that will hold all these rules
var defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs');
var style = document.createElementNS('http://www.w3.org/2000/svg', 'style');
style.innerHTML = styleStr;
defs.appendChild(style);
// now append it in your svg node
thesvg[0].insertBefore(defs, thesvg[0].firstElementChild);
So now you can call the XMLSerializer, and canvg will be happy.
(note that this is not only a canvg limitation, the same applies for every way to draw an svg on a canvas).
Forked plunkr, where I copied the nv.d3.min.css's content to a same-origin style.css.

Very late to the conversation but I just wanted to add that the solution as described by Kaiido, put very simply, is to embed the styles into the SVG document directly.
In order to do this, you manipulate the DOM to make the SVG element look like this:
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="100" version="1.1">
<defs>
<style>
.rectangleStyle{
width:200px;
height:100px;
stroke:black;
stroke-width: 6;
fill: green;
}
</style>
</defs>
<rect class="rectangleStyle"/>
</svg>

Related

Upload Image Width and Height get in react

I am new to React and react hook I want to upload an image from anywhere but I want to know the width and height of a select image before storing it in the database. I want to store the original image metadata width and height. anyone can help me
One solution can be to use FileReader, something like this should work:
const image = new Image();
let fr = new FileReader();
fr.onload = function() {
if (fr !== null && typeof fr.result == "string") {
image.src = fr.result;
}
};
fr.readAsDataURL(inputFile);
image.onload = async function() {
const width = image.width;
};
You can take a look here: https://github.com/toncic/Image-Classification/blob/master/src/Components/ImageClassification.tsx#L45

Why jspdf seems to add padding to this image

I need the Image to fill the whole pdf and the pdf height and width have to come from the image
I tested the image and there is no problems with just the image file
exportToPDF = () => {
var imgData = this.state.canvasRef.toDataURL("image");
var image = new Image();
image.src = imgData;
document.body.appendChild(image)
var pdf = new jsPDF("l", "px", [this.state.canvasRef.getWidth(), this.state.canvasRef.getHeight()]);
pdf.addImage(image, 'png', 0, 0);
pdf.save("download.pdf");
console.log("export to PDF clicked");
}
I can't see where you are putting your image into the canvas but I assume you are doing something like this: https://www.w3schools.com/graphics/tryit.asp?filename=trycanvas_image. If so then the padding could be being added before you are using jspdf.
In this example the line ctx.drawImage(img, 10, 10); is adding padding to the image on the canvas. If this is whats happening to you then change this line to ctx.drawImage(img, 0, 0); and then change the height and width of your canvas tag to match the size of your img tag.

d3.js pie-chart is truncated

I've tried to copy a working pie-chart code from a simple single HTML file to an angular directive.
Loading chart using my directive works but the chart is truncated.
The code is a bit long so I attached a codepen demonstration
JS code:
var app = angular.module('chartApp', []);
app.controller('SalesController', ['$scope', function($scope){
$scope.salesData=[
{label: 'aa',value: 54},
{label: 'bb',value: 26},
{label: 'cc',value: 20}
];
}]);
app.directive('pieChart', function ($window) {
return {
restrict: 'EA',
template: "<svg></svg>",
link: function (scope, element, attr, ctrl) {
// render graph only when data avaliable
var data = scope[attr.chartData];
var w = 300,
h = 300 ;
var r = 150;
var d3 = $window.d3;
var color = d3.scale.category20(); //builtin range of colors
var svg = d3.select(element.find('svg')[0]);
svg.data([data])
.append('svg') //associate our data with the document
.attr("width", w) //set the width and height of our visualization (these will be attributes of the <svg> tag
.attr("height", h)
.append("svg:g")
//make a group to hold our pie chart
.attr("transform", "translate(" + r + "," + r + ")"); //move the center of the pie chart from 0, 0 to radius, radius
var arc = d3.svg.arc() //this will create <path> elements for us using arc data
.outerRadius(r);
var pie = d3.layout.pie() //this will create arc data for us given a list of values
.value(function(d) { return d.value; }); //we must tell it out to access the value of each element in our data array
var arcs = svg.selectAll("g.slice") //this selects all <g> elements with class slice (there aren't any yet)
.data(pie) //associate the generated pie data (an array of arcs, each having startAngle, endAngle and value properties)
.enter() //this will create <g> elements for every "extra" data element that should be associated with a selection. The result is creating a <g> for every object in the data array
.append("svg:g") //create a group to hold each slice (we will have a <path> and a <text> element associated with each slice)
.attr("class", "slice"); //allow us to style things in the slices (like text)
arcs.append("svg:path")
.attr("fill", function(d, i) { return color(i); } ) //set the color for each slice to be chosen from the color function defined above
.attr("d", arc); //this creates the actual SVG path using the associated data (pie) with the arc drawing function
arcs.append("svg:text") //add a label to each slice
.attr("transform", function(d) { //set the label's origin to the center of the arc
// we have to make sure to set these before calling arc.centroid
d.innerRadius = 0;
d.outerRadius = r;
return "translate(" + arc.centroid(d) + ")"; //this gives us a pair of coordinates like [50, 50]
})
.attr("text-anchor", "middle")
.style("font-size","20px")//center the text on it's origin
.text(function(d, i) { return data[i].label; }); //get the label from our original data array
}
};
});
HTML:
<div ng-app="chartApp" ng-controller="SalesController">
<h1>Chart</h1>
<div pie-chart chart-data="salesData"></div>
</div>
I've tried to add a padding and margin as shown here but issue is still persist.
Any ideas?
There are several issues with your code:
Do not use a template: <svg></svg>, because later on you insert another svg in it. Simple remove that line, so that the pie chart will be inserted in your current div.
One you removed the first svg element, change the selector from var svg = d3.select(element.find('svg')[0]) to var svg = d3.select(element[0]).
And lastly, you need to chain your svg definition, so that it will point the the object that already has the translated g in it. Now you define the svg. Then you attach to it a g element, and later you attach another g.slice element, that is not placed inside the first g.
Changes at point 3 are as follows:
// From
var svg = d3.select(element[0]);
svg.data([data]) ...
// To
var svg = d3.select(element[0])
.data([data])
.append('svg') ...
Here is a fork of your codepen with a working example.
Good luck!

How to test three.js tutorial in the View of CakePHP?

I get stuck when try to insert a demo of three.js tutorial into the view of CakePHP,
This demo (creating a scene): enter link description here
Has anybody try it like that ?
Thanks for reading . I hope you share your experiments.
Detail my problems:
I create webgl_test.js and put it into ...webroot/js/, and also put the three.min.js into webroot/js/
//------------- CREATING THE SCENE-----------------------
/* To actually be able to display anything with Three.js, we need three things:
1. A Scene
2. A Camera
3. A Renderer so we can render the scene with the camera
*/
var main=function() {
var CANVAS=document.getElementById("your_canvas");
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera (75, window.innerWidth/window.innerHeight, 0.1, 1000);
var renderer = new THREE.WebGLRenderer({
antialias : true,
canvas : CANVAS
});
renderer.setSize(window.innerWidth, window.innerHeight);
//document.body.appendChild(renderer.domElement); //we add the renderer element to our HTML document
var geometry = new THREE.BoxGeometry (2,1,1);
var material = new THREE.MeshBasicMaterial ({color: 0x00ffff});
var cube = new THREE.Mesh (geometry, material);
scene.add(cube);
camera.position.z = 5;
//-------------RENDERING THE SCENE------------------------
function render(){
requestAnimationFrame(render);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
}
render();
};
In the header of default.ctp, I call script's library like that
<head>
<script type="text/javascript" src="/js/webgl_test.js"></script>
<script type="text/javascript" src="/js/three.min.js"></script>
</head>
Last step, I write some lines to show <canvas> element as below:
<div>
<ul>
<li onload='main()'>
<canvas id='your_canvas'style='position: absolute;'></canvas>
</li>
</ul>
</div>
Then, It show nothing :((

AngularJS directive to create a thumbnail

I've just started learning AngularJS and I'm approaching directives. I'd need to create a directive named f.e. "thumbnail" which takes as input a "src" (the image) and create a thumbnail of it.
So far I've coded the javascript function to create the thumbnail which does its job correctly:
function readURL(input) {
var imageSize = 50;
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
var blah = $('#myimage');
blah.attr('src', e.target.result);
var height = blah.height();
var width = blah.width();
if (height < imageSize && width < imageSize) {
if (width > height) {
blah.width(imageSize);
}
else {
blah.height(imageSize)
}
}
};
reader.readAsDataURL(input.files[0]);
}
}
</script>
<body onload="readURL(this);">
<img id="myimage" src="../picture.gif" width="50" alt="your image" />
However I have not been able to find a simple example which produces (in AngularJS) an Element, based on a JS function. Any help ?
Thanks!
It depends on what you want to achieve. If your purpose of creating a thumbnail at client-side is to:
Upload in a smaller size in a web application: perhaps you can make use of a library like http://www.plupload.com.
Display only: you should just use CSS resizing with width and height properties.
<img src="/original/320x320.jpg" style="width: 100px; height: 100px">
Reading/storing in an Ionic/PhoneGap app: try make use of angular-thumbnail (disclaimer: I wrote it)
Doing image manipulation of this kind on the client side is not a very good idea , because, as of now there isn't a good support for Filereader in IE.
You can delegate this either to server(you will find lot of node module for image manipulation) or you can use external services like cloudinay

Resources