Centering multiple line wrapping - svg

My question is regarding how to center multiple elements in one node after line wrapping. I'm utilizing code example given here on word wrapping: http://bl.ocks.org/mbostock/7555321 to create multiple tspan objects.
After creating/drawing all the tspan objects, I define the location of the X and Y. First I get the text area of the entire tspan and create a box around it:
var tspanbbox = d3.select(this).select("tspan").node().getBBox();
var node_bbox = {"height": tspanbbox.height+5, "width": tspanbbox.width+5};
var rect = d3.select(this).select('rect');
rect.attr("x", -node_bbox.width/2).attr("y", -node_bbox.height/2)
rect.attr("width", node_bbox.width).attr("height", node_bbox.height+10);
and then I added the attribute for the tspan, the text that's within rect.
tspan.attr("x", -node_bbox.x).attr("y", -node_bbox.y);
This code correctly prints a box around the area around the text, but there's overflowing text.
http://imgur.com/zxiRmxR
So what I'm trying to do is to center the group as an entity rather than the first tspan (what I'm assuming is the first line after the GO term).
If I try to alter the tspan attribute (as shown in the code above), only one of the tspan objects move. If I do it with all of them using selectAll("tspan"), all of them the tspans are grouped on the same y axis.
Is there any way of going about this properly?

If anyone else is running into this issue, you can check the number of lines inputted total and make adjustments on the y attribute based on how many lines are implemented (so it's a little manual and archaic but it works).

Related

Datalabels on Highmaps appearing bottom to top

I am facing a strange problem with Highmaps. I have a geojson map that Highmaps shows properly. Mouseover works and tooltips appear in the correct places. However, when I turn on data labels, they appear upside down. That is, a label that should appear near the bottom of the map (centered on its province) now appears near the top, and vice-versa. The data labels' coordinate system seems to be reversed.
In the image, the label "603863" should appear over the bottom-most province, while "1966085" should appear over the topmost province.
A sample of my geojson data:
var provincePolygons = {
"type":"FeatureCollection",
"features":[
{"type":"Feature",
"properties":{
"id":"05","name":"Tete"},
"geometry":{"type":"Polygon",
"coordinates":[[
[32.636,-14.204],
[33.245,-13.998],
[33.299,-14.032],
[33.300,-14.146],
[33.385,-14.237],
[33.478,-14.404],
[33.544,-14.434],
[33.627,-14.528],
[33.640,-14.594],
[33.718,-14.572],
...
Things I have tried:
The data labels are SVG elements. I thought that maybe surrounding CSS rules might be affecting their position, but since the other CSS elements, using similar transformations, are in the correct locations, that doesn't seem to be the problem.
The longitudes are negative values. I experimented with making them positive by adding +100 to each value, just to see if the negative values were to blame, but they were not. It was a long shot.
I've played, naturally, with the API settings for data labels, but there does not seem to be a switch that affects their top-to-bottom placement. I would also think that leaving the default values untouched should result in correct placement.
I have wondered how data labels' location is calculated by Highmaps. Perhaps Highmaps cannot find the center of each polygon and needs a hint? I added latitude and longitude values to the feature in the geojson, but that did not help. I've also used Highmaps before in a similar situation without needing to add such data.
There is a group called "highcharts-data-labels" in the generated SVG. I am considering trying the flip its coordinate system upside-down somehow to move the data labels to their correct position, but that would a complex intervention for something that should work correctly.
Please note that I am using ng-highcharts.
What am I doing wrong?
For anyone else running into this problem, I was able to solve this by adding the property 'chartType' to my config object. The docs for the highcharts-ng library mention this for making a highstock chart, but don't say anything about it for highmaps. The lib defaults to 'chart', but you need to put chartType: 'map', and it should fix the problem :)
Here's the relevant code from the highcharts-ng libary, where config is your chart Object:
var chartTypeMap = {
'stock': 'StockChart',
'map': 'Map',
'chart': 'Chart'
};
function getChartType(config) {
if (config === undefined || config.chartType === undefined) return 'Chart';
return chartTypeMap[('' + config.chartType).toLowerCase()];
}
Hope this helps!

Snap SVG - Check if one transformed rectangle is completely inside of another?

I'm using Snap SVG to manipulate SVGs within a web app that I'm making. In this web app I have two rectangles that start out with one being inside of the other, call them rectInner and rectOuter. The aim is to allow the user to transform rectOuter (scale, rotate, translate) such that rectInner is always strictly inside of rectOuter. To be clear, rectInner will never move or be transformed.
My approach to this problem is to get the bounding box of both rectInner and rectOuter, and check to see if the first is strictly contained within the second. Snap SVG provides a function isBBoxIntersect(rectInner, rectOuter), but it only tells me if parts of the bounding boxes intersect, not if one is contained within the other.
Is there a simple way of doing this?
EDIT:
It seems now that I somewhat misunderstood the concept of bounding boxes, but the problem should be simpler. If I can find a way of calculating the four vertices of rectOuter after all of the transformations, then so long as the corners of rectInner are inside the of the path constructed from those vertices, the entire rectangle is. I think.
##### coffeescript
el = Snap('rect#outer')
mat = el.attr('transform').totalMatrix
left = +el.attr('x')
top = +el.attr('y')
right = left + (+el.attr('width'))
bottom = top + (+el.attr('height'))
console.log(left, top, right, bottom)
points = {
x: mat.x(left, top)
y: mat.y(left, top)
x2:mat.x(right, top)
y2:mat.y(right, top)
x3:mat.x(right, bottom)
y3:mat.y(right, bottom )
x4:mat.x(left, bottom)
y4:mat.y(left, bottom)
}
use matrix!
you can find more matrix in mat variable.
if totalMatrix didn't work then try another.

D3 Sunburst clip path of text

I am trying to implement a d3 visualization based on the sunburst diagram, and i have found an almost perfect online example of this which i have got working http://tributary.io/inlet/4127332/:
My main issue is that I need to also Clip the text to the segment,I have tried using the svg clip path but my meager d3 skills have let me down. Any help with this is appreciated.
So my first attempt to clip the text did not work and I think this is because the arc's coordinate space does not line up with the text's coordinate space in the way that you want if you are using the arc generator, as you are.
I found that if I apply the clip to the groups you make for each node then it worked like a charm. There was one caveat. When I tried generating my clip path and then applying them the order that the nodes were joined to the elements differed and so the wrong path were clipping the wrong text. I got around this by adding an id to each data element. You can see the final version here
The important parts are adding the clip paths (note the use of the new id field):
svg.append('defs')
.selectAll("clipPath")
.data(partition.nodes)
.enter().append('svg:clipPath')
.attr('id', function(d,i) { return d.id;})
.append('path').attr('d', arc);
Then you simply have to reference them on your node groups (again using the id):
group =
svg.selectAll("g")
.data(partition.nodes)
.enter().append('svg:g')
.attr('clip-path', function(d,i) { return 'url(#' + d.id + ')';});
In the tributary I put the svg data join first so that the "defs" node would appear in the usual place (first after the svg tag), but I do not think this is technically necessary.

Raphael - find bounding box of text BEFORE printing

Afternoon All,
I'm trying to draw a dynamic "ruler" which can be zoomed (along with the rest of the page) and is annotated, using Raphael.
I've found Raphael's pathBBox() and isBBoxIntersect very useful for determining if a graduation should be printed at a certain point or if it would be too close to another and should thus be skipped.
Now I need to annotate some of the graduations and want to follow a similar method - annotate the largest graduations, working down to the smallest level of detail but skipping drawing the text if it would intersect with some already drawn.
Unfortunately my look through the Raphael docs have only shown me the Paper.print() and Paper.text() methods, both of which add to the paper. This means I would have to add, then find the bbox and test, then remove if bad - which is potentially rather slow.
Is there a way to find the dimensions of some text I want to print without printing it, such that I can manually create a bbox object and test it against my stored bboxes?
As always, thanks very much in advance! :-)
Cheers,
-Oli
You can use .getBBox() on text:
var text = paper.text(...);
if (text.getBBox().width > max) ...;
I didn't see this documented officially, but it works, and apparently cross-browser.

RaphaelJs : How to add some text to an area defined by a path?

I have an SVG image of the united states which I've drawn with a little bit of help from Raphaël js:
http://jsfiddle.net/zCRkg/2/
What I want to do is place some text to the right of each state when you hover over it. The problem is that, since each state is a path, its quite difficult to determine the x & y coordinates for where to place the label.
So, does anyone know a way of calculating the centre of a path using Raphaël? If failing that anyone know how to do this given a an array of vectors?
What you're looking for is the getBBox function in Raphaël. It will give you a bounding box object that you can use to calculate the central point of the path:
var bbox = st.getBBox();
var text = r.text(bbox.x + bbox.width/2, bbox.y + bbox.height/2, "Foo");
I forked your fiddle and made it show a static text in the middle of each state on hover. Picking up the state name from your data is left as an exercise.
the average of the difference between each coord should give you the centre, but thats probably not the most efficient way

Resources