Put label in the "center" of an SVG path - path

I'm trying to draw a label on a polygon of an svg file. The problem I'm facing is to find out roughly the center of this polygon to place the label, as the path's coordinates are in svg format and need to be parsed. Is there an easier way to determine the center of an svg polygon (maybe someone can point out a javascript library or a snippet)? I'm using Raphael javascript library to manipulate the svg, but it doesn't seem to go beyond the standard svg functionality.

You could try the following approximation for doing something similar to the polygon suggestion, based on SVG DOM methods:
var totalPathLength = pathelm.getTotalLength();
var step = totalPathLength / 100;
for(var dist=0; dist < totalPathLength; dist+=step)
{
var pt = pathelm.getPointAtLength(dist);
addToAverage(pt.x, pt.y);
}
I think the simplest approach is to use the center of the path element's boundingbox (pathelm.getBBox()), that's simpler than the polygon suggestion.

The simplest thing you could try doing is to calculate the center by taking the average of all the points in the polygon. It should work for all but the most irregular of polygons. I've used the same algorithm to good effect in my programs.
Best of luck.

Insert a text tag inside the svg and position it by calculating the width and hight
<svg width="447pt" height="559pt" viewBox="0 0 894 1118" version="1.1" xmlns="http://www.w3.org/2000/svg">
............
............
<text x="450" y="300" font-family="Verdana" font-size="15" fill="red" >
Text To Show
</text>
</svg>

Related

Highcharts: converting millimeters to pixel

Hello to the community,
I would have one more question on Highcharts. I am working closely with designers and they prefer to have charts given to them with a predefined height, width, and text size, in millimetres (not pixels). That is because ultimately these charts are going to be printed out in reports.
Right now designers enter the value they want for a specific chart in millimetres onto a spreadsheet, and I convert all that to px before making the chart.
To convert pixel to mm I use:
px = mm * DPI / 25.4 since 1in = 25.4 mm.
For point (pt) to pixel I use:
px = pt * DPI/72 since 1pt = 1/72th of 1in.
Where DPI is a variable given to me: usually 300.
However the font size tends to be much bigger than it should be (it looks like it is 20 pt on the chart when I want 12 pt), and the chart dimensions also seem to be wrong.
My first question: do my calculations look right? (I am afraid I am not much of an image expert).
My second question: would there be a way to specify chart dimensions in a different format than pixel when configuring a chart on Highcharts, by any chance?
Thank you so very much!
You can use some of the already existing converters to get those values, like: https://www.unitconverters.net/typography/millimeter-to-pixel-x.htm
You can use CSS to set parameters for the container that the chart is rendered inside, demo: https://jsfiddle.net/BlackLabel/vu41gdt6/
#container {
height: 15rem;
width: 15rem;
}
Consider use regular CSS units for the charts on you web app and change them only for printing needs.
API: https://api.highcharts.com/highcharts/chart.events.beforePrint
Useful article: Using cm/mm on the CSS of a web app that replicates paper interaction is a good practice?

L.polygon boundings in leafletjs

I have several markers in a map, I want to color the area inside the maps of a different color. I've tried L.multiPolygon , L.polygon, L.rectangle, but nothing does but I want. I guess my only option is to calculate the boundings of all the markers and draw the polygon based on these points, right ?
Here the code
<c:forEach var="marker" items="${markers}" varStatus="rowIndex">
var marker${rowIndex.index} = L.marker([${marker.lat},${marker.lng}],{icon: yellowIcon,title: '${marker.title}'}).addTo(mymap)
.bindPopup( "${marker.HTMLMarkerPopupCode}").openPopup();
storeCoordinate(${marker.lat}, ${marker.lng}, polygonPoints);
</c:forEach>
var polygon = L.polygon(polygonPoints);
polygon.setStyle({fillColor: '#0000FF'});
polygon.setStyle({color: 'red'});
polygon.setStyle({weight:1});
polygon.setStyle({fillOpacity: 0.5});
mymap.addLayer(polygon);
I would like to achieve something similar to this picture:
You can use L.Polygon as well.
Just do something like this:
var polygon = L.polygon([
marker1,
marker2,
marker3,
], {
fillColor: '#f03' // My custom color here
}
).addTo(mymap);
Not sure exactly what you are trying to achieve?
You might be interested in computing the Convex Hull of your markers area.
In that case, you should be able to find some JavaScript implementations on the Internet. E.g., you can look at how it is done in Leaflet.markercluster plugin: https://github.com/Leaflet/Leaflet.markercluster/blob/master/src/MarkerCluster.QuickHull.js
EDIT:
As for creating Convex Hull, you could also use Turf, in particular turf.convex.
Turf also provides you with plenty other functionalities, including turf.concave.

svg linejoin imlementation differs in different applications

I write an svg parser.
I have an svg file with the following string:
<polygon fill="#969696" stroke="#323232" stroke-width="0.5" stroke-miterlimit="10" points="555.583,394.805 564.085,394.805 564.02,394.817 568.896,399.655"/>
And this picture looks different in various applications. Possible cases:
1)linejoin = bevel
2)linejoin = miter (Corel Draw)
3)two nearest points are not connected (Inkscape, adobe illustrator)
The second and the third case look look like:
It seems that svg documentation advices to draw the same picture as corel draw draws (right picture). But it is not very pretty.
So what rule will allow to achieve the left picture?
You seem to have a bogus co-ordinate in your polygon. The polygon has 3 vertices but you're supplying 4 and the bogus one is confusing things. Try this instead...
<polygon fill="#969696" stroke="#323232" stroke-width="0.5" stroke-miterlimit="10" points="555.583,394.805 564.085,394.805 568.896,399.655"/>

Highcharts chartWidth no longer works with chart.getSVG()

Correct me if I'm wrong but I could have sworn chart.chartWidth used to return the exact width attribute as returned by getSVG().
I'll explain.
Say I target a div that forces a chart to render with the following as read via view source.
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="270" height="300">
Now if I call chart.highcharts().chartWidth I'll get 270. Great!
But if I then call chart.highcharts().getSVG() I'll get this is an opening
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="400" height="600">
I've been using and adding to an export function that will combine multiple charts into a single and I typically need to do some scaling to get it to look nice. The scale is dependent on the originally rendered size, not the default and now it's causing a huge problem.
Shouldn't getSVG return svg representing the chart as it appears in html?
Have you tried sourceWidth or scale parameter?

How do you animate an SVG path in IOS?

I have an SVG path like this:
<svg width="100" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" version="1.1" baseProfile="full">
<path d="M47.16,66.38c0.62,1.65-0.03,2.93-0.92,4.28c-5.17,7.8-8.02,11.38-14.99,18.84c-2.11,2.25-1.5,4.18,2,3.75c7.35-0.91,28.19-5.83,40.16-7.95" style="fill:none;stroke:black;stroke-width:2" />
</svg>
I can render the path but can't seem to find a way to make the path animate so that it looks like it is "being draw" as if with pencil. The animate node works for single coords but not for paths.
I will eventually end up using this animation in an iPhone app either with a parser or with a UIWebView.
Try animating the 'stroke-dashoffset' (note that you need a matching 'stroke-dasharray' with it), see this example. The length of the path that needs to be computed to be able to use this successfully can be fetched via script like:
var pathlength = yourPathElm.getTotalLength()
View source on the example to see how it's done.
I tried for a long while to do this without having to add extra scripts to the header (that I have no idea of javascript didn't help), so here's the solution:
<path d="..." stroke-dasharray="">
<animate attributeName="stroke-dashoffset" from="" to="0" dur="1s" begin="0s"
onload="var length = parentNode.getTotalLength();
parentNode.setAttribute('stroke-dasharray',length+','+length);
this.setAttribute('from',length)" />
</path>
I added extra line breaks for readability here.
This is legal in SVG (although not in HTML) because the svg:animate element allows onload, which most HTML elements do not.
Once you've rendered your SVG path, to make it look like it's being drawn with a pencil, you could simply cover it all with an opaque layer, and then animate the movement of this layer along the path.
To find the CGPath along which you'll move the layer you can use this library:
https://github.com/arielelkin/PocketSVG
This will parse the SVG data into a UIBezierPath. Then:
SvgToBezier *myBezier = [[SvgToBezier alloc] initFromSVGPathNodeDAttr:#"M176.17,369.617c0,0,335.106-189.361,214.894,38.298s129.787,282.978,178.723,42.553C618.724,210.042,834.681,87.702,790,307.915" rect:CGRectMake(0,0,1024,768)];
UIBezierPath *myPath = myBezier.bezier;
CAKeyframeAnimation *mySVGPathAnimation = [CAKeyframeAnimation animationWithKeyPath:#"position"];
bounceAnimLeft.duration = 3;
bounceAnimLeft.path = myPath.CGPath;
[myObjectToMove.layer addAnimation:mySVGPathAnimation forKey:#"pathAnimation"];

Resources