I have a Bezier curve defined in SVG that I'd like to draw using jsPDF. I haven't been able to get the curve to render correctly using jsPDF. How do I draw the Bezier curve defined in the SVG below using jsPDF?
The curve in SVG:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="192" version="1.1" height="288">
<path fill="black" stroke="black" d="M19.0544,25.8288C24.2384,43.2816,22.3952,46.9968,18.7376,50.510400000000004" stroke-width="0" font=" 10pt Arial"></path>
</svg>
My attempt at the curve using jsPDF:
var doc = new jsPDF();
doc.lines([[24.2384, 43.2816, 22.3952, 46.9968, 18.7376, 50.5104]], null, null, [1, 1], 'FD');
What the SVG produces when rendered (left) and what my jsPDF code produces (right):
I don't see the initial move reflected in your code. According to my reading of the documentation, shouldn't this be something more like the following?
var doc = new jsPDF();
doc.lines([[24.2384, 43.2816, 22.3952, 46.9968, 18.7376, 50.5104]], 19.0544,25.8288, [1, 1]);
Update
Didn't notice the docs say coords are relative (thanks Pomax), so try this.
var doc = new jsPDF();
var x = 19.0544;
var y = 25.8288;
doc.lines([[24.2384-x, 43.2816-y, 22.3952-x, 46.9968-y, 18.7376-x, 50.5104-y]], x,y, [1, 1]);
Related
In the below code the call method is not executed after the transition on the path and text svg elements. Could you explain me the reason?
The structure of the elements are as below, will help you in understanding the code-
<g> //each g tag is an arc component in a donut chart
<path> //path which defines arc
<text> //Label for the arc
</g>
The following piece of code is doing the rotation animation-
var counters = {"i":endIndex};
for(counters.i=endIndex; counters.i>=startIndex;){
var textPositionC = textPositionX;
textPositionX = d3.select(arcArray[counters.i]).select("text").attr("transform");
d3.select((d3.select(arcArray[counters.i]).select("path")
.transition()
.duration(301)
.attrTween("d", tweenRotateRight)[0][0])
.node
.parentNode)
.select("text")
.attr("transform", textPositionC)
.style("visibility", "visible")
.call(function(counters){
counters.i=counters.i-1;
if(counters.i<startIndex)
$('#rightButton').removeClass('disableRotate');
});
}
I have successfully implemented a codeflower view for a sample dataset. The code used to achieve that is:
var currentCodeFlower;
var createCodeFlower = function(json) {
document.getElementById('jsonData').value = JSON.stringify(json);
if(currentCodeFlower) currentCodeFlower.cleanup();
var total = countElements(json);
//console.log(total);
w = parseInt(Math.sqrt(total) * 50, 10);
h = parseInt(Math.sqrt(total) * 50, 10);
currentCodeFlower = new CodeFlower("#visualization",w,h).update(json);
};
d3.json('data.json', createCodeFlower);
I now wish to add a fisheye distortion to this visualization and am not sure how to go about this. I have looked into the documentation of fisheye but as I used codeflower.js I am not sure how to access the svg element anymore. Any help is appreciated. Thank you.
You can do a fish-eye distortion using a SVG filter (feDisplacement) but you need a very specific displacement map to achieve it. This is an example I wrote based on Inkscape's reference image for fisheye distortion. See other examples for how to express this in D3 syntax.
<filter id="trilight" x="-50%" y="-50%" width="200%" height="200%">
<feImage xlink:href="http://tavmjong.free.fr/INKSCAPE/MANUAL/images/FILTERS/bubble.png" result="lightMap" x="30" y="0" width="600" height="600"/>
<feDisplacementMap in2="lightMap" in="SourceGraphic" xChannelSelector="R" yChannelSelector="G" scale="10">
</feDisplacementMap>
</filter>
I've seen problems similar to this one, but the solutions offered haven't worked for me. I have 67 polygons inside an svg tag. I want to resize the svg and its polygons. The code below doesn't scale. What are I doing wrong?
<svg version="1.1" id="svg" xmlns="http://www.w3.org/2000/svg" width="800" height="948" viewBox="0 0 800 948" transform="scale(3)" >
<polygon fill="#DCDDDE" stroke="#000000" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
51.863,2.318 51.33,24.344 60.904,24.341 60.368,36.8 56.213,36.622 32.925,36.452 6.163,35.635 6.265,25.489 10.962,22.776
12.801,22.523 18.542,20.605 26.558,16.127 28.034,14.607 29.153,11.827 30.635,10.309 32.479,10.057 33.056,10.166 32.949,10.741
33.309,12.004 33.885,12.114 38.582,9.402 42.008,7.054 43.958,6.223 45.329,5.283 48.545,4.089 50.599,2.681 "/>
...(more polygons)
</svg>
You shouldn't be fiddling with the viewBox attribute. If you want to resize the SVG, change its width and height attributes.
What I finally did was take a ruler and measure the cumulative width of the polygons. Based on that, I could calculate how to resize them:
jquery:
var mapW = $('#map').width();
var mapH = Math.round(mapW * 255 / 477);
var svg = $('svg');
svg.attr('viewbox', '0 0 ' + mapW + ' ' + mapH);
svg.attr('preserveaspectratio', 'xminymin meet');
svg.attr('width', mapW+'px');
svg.attr('height', mapH+'px');
svg.attr('enable-background', "new 0 0 "+mapW + " " + mapH);
//svg.children().attr('transform', 'scale(1.2)');
var s = svg.children();
//I used a ruler to measure the width of the polygons - 360
var factor = mapW /360 ;
console.log(factor);
svg.children().attr('transform', 'scale(' + factor + ')');
//must change svg height to accommodate new height
svg.attr('height', mapH*factor+'px');
I'm a beginner at SVG, but I'd like to learn some techniques.
To be short, is there a simple way to create something like this?
I was thinking about creating a polar gradient and then clipping it:
But how do I generate a polar gradient?
Even if there's no native method, maybe it could be made with a simple linear gradient and then using some rectangular-polar coordinate transformation. Is there a way to do so?
So this is the solution I developed:
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg viewBox="0 0 100 100" version="1.1" onload="makeGradient();">
<script>
function makeGradient() {
var root = document.rootElement, i = 256, cir, a;
for (; i--;) {
a = i*Math.PI/128;
cir = document.createElementNS("http://www.w3.org/2000/svg", "circle");
cir.setAttribute("cx", 50 - Math.sin(a)*45);
cir.setAttribute("cy", 50 - Math.cos(a)*45);
cir.setAttribute("r", "5");
cir.setAttribute("fill", "rgb(" + i + ", " + i + ", " + i + ")");
root.appendChild(cir);
}
}
</script>
</svg>
Minified version (395 bytes):
<?xml version="1.0" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" version="1.1" onload="g(this.namespaceURI,document,Math)"><script>function g(n,d,m,i,c,a,p,z){for(i=256;i--;){a=i*m.PI/128;c=d.createElementNS(n,"circle");for(p in z={cx:10-m.sin(a)*9,cy:10-m.cos(a)*9,r:1,fill:"rgb("+[i,i,i]+")"})c.setAttribute(p,z[p]);d.rootElement.appendChild(c)}}</script></svg>
This was made creating circles filled with 256 shades of gray (it sounds like porn literature for coders!) and conveniently placed.
The radii can be adjusted: I've chosen 45 for the whole spinner and 5 for the single circles. Moreover, the detail can be adjusted too if 256 are too many:
for (; i -= 2;) { ...
Use powers of 2 for optimal results. Or just define the number of steps:
var steps = 100, i = steps;
for (; i--;) {
a = i*2*Math.PI/steps;
...
cir.setAttribute("fill", "rgb(" + i*255/steps + ", " + ...);
}
A big "thank you" to Erik Dahlström for the hint, and thank you Michael Mullany for the attempt :)
Edit: Here's a fiddle to demonstrate the code.
Edit 2: Here's another fiddle using curved segments to create the spinner. You can adjust the number of segments and the size, and even see it spinning. I don't know why when the size is auto, there's a bottom margin of 5 pixels on the SVG, this making the spinning slightly off-centered...
There are no paintservers in SVG 1.1 that allow this directly, but you can e.g do it using a bit of script. Here's an article that explains how.
There is no support for polar gradients in SVG 1.1 (what's available in most edge browsers today) although there are proposals to allow capabilities like these in SVG 2. The only workaround I can think of is to apply a blend filter using an externally generated image as your multiply source. But then, I'm assuming the whole point it to try to avoid external images so this would be a little pointless:)
I want to add text to the centre of a path and align it horizontally, NOT align along the path.
I have the following text running along the path at the centre, but I want to display it so that it is horizontal, no matter what angle the path is heading.
<text text-anchor="middle">
<textPath xlink:href="#SomePath" startOffset="50%">Some Text</textPath>
</text>
If I understand correctly you are after each individual letter being straight (i.e. pointing North) but following the path. Something like this:
Looking at the current SVG standard this does not seem to be possible.
For horizontal text layout flows, the
reference orientation for a given
glyph is the vector that starts at the
intersection point on the path to
which the glyph is attached and which
points in the direction 90 degrees
counter-clockwise from the angle of
the curve at the intersection point.
The image above is generated from SVG but this was achieved (as you can see from the imperfections) by applying individual kerning (rotation) to each letter by applying the rotate attribute:
<text id="text2897">
<textPath xlink:href="#path2890" id="textPath3304">
<tspan
rotate="69.238731 53.737518 40.30315 24.801943 358.96658 358.96658 4.1336575 357.93317 351.73267 351.73267 351.73267 348.63242 343.46533 343.46533 346.56558 347.599 347.599 347.599 347.599 347.599 347.599 346.56558 345.53217 344.49875 343.46533"
id="tspan2899">
Some sample text for path
</tspan>
</textPath>
</text>
You can calculate the necessary adjustments in rotation in script quite easily:
var tp = document.getElementById("textpath");
var rotate = "";
for(var i = 0; i < tp.getNumberOfChars(); i++)
{
rotate += -tp.getRotationOfChar(i) + " ";
}
tp.setAttribute("rotate", rotate);