Raphael - how to draw a path that stretches to width? - svg

This may be a very dumb question, but how do I draw a path that will stretch to a div's width?
I am experimenting with Raphaeljs to make an interactive chart: the user can click sparklines and the lines shift up and down to reveal text content. I see that Raphael's rectangles and other shapes will stretch to width fine by setting the width to 100%, but I can't get a line to do this.
I've set up the paper like this:
var SLAPaper = new Raphael( document.getElementById("LineSLA"), "100%", 60);
Set up the line like this:
var lineSLA = SLAPaper.path("F1 M 0,42L 103,12L 222,45L 390,13L 460,45L 453,27L 455,28L 450,0L 479,25");
I also set a viewbox but this doesn't seem to make a difference. I can't set a % width on the viewbox anyway:
SLAPaper.setViewBox(0,0,1500,60, true);
Any help appreciated. Thanks.

I've personally had problems with using percentages for defining size of both paper and objects in Raphael, especially with Internet Explorer. The best I could come up with would be to scale the line to fit inside paper, based on the width of the path (assuming that the width is more than the height):
var line = SLAPaper.path("F1 M 0,42L 103,12L 222,45L 390,13L 460,45L 453,27L 455,28L 450,0L 479,25");
var scl = SLAPaper.width / line.getBBox().width;
line.transform('S' + scl + ',' + scl + ',0,0');

Related

Visio Shape Text positioning below the shape using Text Transform

I have a building a set of stencil shapes and I need the text to display below the shape. I am using custom formulas to generate the text, and as such the volume of text changes from use case to use case.
What I have come across is using the Text Transform set of properties, and I have tried the following with success for a single line of text:
TxtWidth = TEXTWIDTH(TheText)
TxtPinX = Width * 0.5
TxtLocPinX = TxtWidth * 0.5
TxtHeight = Height * 0
TxtPinY = Height * -0.2
TxtLocPinY = TxtHieght * 0.5
TxtAngle = 0 deg
The problem arises when there is more than a single line of text to display -> the text appears 'half above (inside) and half below' the bottom the shape.
I would like to place all the text, regardless of how many lines there are, underneath the shape.
What I have tried is to set the TxtPinY = some formula different from above eg/ Height * -(TxtHeight). This seems to always result in an 'error in formula'.
I am sure that this is something simple that I am missing, but I cannot figure it out.
Can anybody point me in the right direction?
Cheers and thanks for taking a look at this,
The Frog
You could try the TEXTHEIGHT function to get around this. Specify a reasonable maximum text widht as a second parameter for it:
TxtHeight = TEXTHEIGHT(TheText,100)
TxtPinY = 0
TxtLocPinY = TxtHeight
You can use the code provided with the stencil available in this post:
http://visguy.com/vgforum/index.php?topic=7461.msg31490#msg31490

About skia antialias

Recently I'm learning skia library(google open source 2d engine,be used on Android and chromium,etc.),Now I want to use it on windows instead of GDI+ dont support clip area with antialias,during it, I find a problem about pixel.
up is set antialias,down is not set antialias
the main code is:
paint.setStrokeWidth(1);
paint.setStyle(SkPaint::kStroke_Style);
paint.setAntiAlias(true);
canvas.drawRect(skrect,paint); //draw up rect
skrect.fTop += 110;
skrect.fBottom += 110;
paint.setAntiAlias(false);
canvas.drawRect(skrect, paint); //draw down rect
As you see,the same rect,if I not set Antialias,the boundary pixel is 1(I set strock width is 1),but if I set Antialias, the boundary pixel is 2,and it become a bit light,although I set color is black.
I dont konw why,anyone can tell me?
thk,
now,maybe I konw.
the skia library canvas should be like Html5`s canvas ,Canvas every line have an infinite thin "line", the width of the line from the center line to stretch,so if we draw a 1px line,in fact,it will fill two of 0.5 pixel point,but the display device dont allow it do that,so it will fill 2 pixel point,and set it color more light to differentiate real 2 pixels .
I will search more material to prove it.
This happens because OpenGL assumes that each pixel is centered at [0.5; 0.5]. The rasterizer have to draw indeed two pixels and interpolate the alpha. Read more here
If you would like to draw sharp 1px lines with antialiasing turned on just offset coordinates of a line or other figure with 0.5f.
For example a point at [10; 10] should have coordinates [10.5; 10.5] and so on

d3 create SVG path from array

Following this example
http://jsfiddle.net/4xXQT/
I was able to render the points coordinates stored in one array using D3 as follow
https://jsfiddle.net/il_pres/qq9o1ovt/.
var vis = d3.select("body").append("svg")
.attr("width", 30)
.attr("height", 30);
var regioni = [{regione:'Abruzzo',polygon:{points:'25.171,18.844 25.094,18.582 24.567,17.714 24.015,17.714 23.226,16.899 22.805,16.268 21.911,14.558 21.043,14.427 20.753,15.163 20.043,15.084 19.938,15.741 19.386,16.268 19.386,17.056 18.439,16.899 18.202,17.345 18.334,17.924 18.281,18.582 19.57,19.423 18.939,20.055 18.176,19.581 17.756,20.16 17.808,20.844 18.703,21.08 19.517,21.396 19.491,22.079 20.517,22.185 20.596,22.605 21.122,22.133 21.832,22.658 22.568,22.737 23.094,23.473 23.646,22.553 23.751,21.738 24.646,21.212 25.094,21.738 25.409,22.29 26.25,21.238 26.409,20.475 26.776,19.923 26.303,19.634 26.145,19.292'}},{regione:'Basilicata',polygon:{points:'24.607,15.268 23.476,14.716 23.818,14.4 23.161,13.848 22.556,14.111 22.135,14.005 21.529,14.452 20.53,14.716 19.294,14.111 18.952,13.742 18.426,14.242 18.479,14.926 17.637,14.321 17.295,14.531 17.479,15.426 16.611,16.083 17.216,16.451 17.637,17.556 18.321,18.214 18.453,18.792 19.189,18.871 19.61,18.424 20.662,19.186 20.662,19.581 20.109,19.844 19.978,20.344 20.662,20.081 21.188,20.318 21.372,20.002 21.951,19.713 22.424,19.713 22.949,20.265 23.423,20.896 23.555,21.448 23.187,22.053 23.213,22.658 23.844,23.027 24.475,23.105 25.159,23.605 25.08,23.894 25.58,24.157 26.158,24.157 26.5,23.552 27.105,23.552 27.631,22.816 27.92,22.238 27.579,21.291 26.658,20.475 26.132,19.844 26.053,19.239 25.238,18.45 25.238,17.766 26.001,17.74 26.264,17.398 26.21,16.609 25.764,16.32 24.712,16.136'}}];
vis.selectAll("polygon")
.data(regioni) .enter().append("polygon")
.attr("points",function(d) {return d.polygon.points})
.attr("stroke","red")
.attr("stroke-width",0.1);
Now I was trying to do the same with the same svg shape, this time stored as d coordinates
var regionico =[{Regione:'Abruzzo',polygon:{points:'m 127.945,84.9805 -0.781,2.6172 -5.273,8.6835 -5.508,0 -7.891,8.1528 -4.219,6.308 -8.9292,17.09 -8.6836,1.32 -2.8985,-7.363 -7.1015,0.789 -1.0547,-6.57 -5.5157,-5.266 0,-7.89 -9.4648,1.582 -2.3711,-4.4731 1.3164,-5.7812 -0.5273,-6.582 12.8906,-8.4063 -6.3086,-6.3203 -7.6367,4.7383 -4.1992,-5.793 0.5273,-6.8359 8.9453,-2.3633 8.1445,-3.1641 -0.2617,-6.8242 10.2617,-1.0664 0.7813,-4.1992 5.2656,4.7265 7.0977,-5.2539 7.3632,-0.7812 5.25,-7.3633 5.527,9.1992 1.055,8.1446 8.945,5.2656 4.473,-5.2656 3.164,-5.5157 8.399,10.5157 1.601,7.6367 3.652,5.5195 -4.726,2.8906 -1.582,3.418 -9.727,4.4805'}},{Regione:'Basilicata',polygon:{points:'m 123.746,104.57 -7.637,-4.7458 -9.453,3.4178 -3.961,8.692 -12.3512,2.089 2.1093,9.739 -7.6289,4.734 -5,-5.516 -6.0547,3.418 -7.3633,-7.109 0.5274,-7.891 -2.6172,-3.41 -7.6367,-0.527 0,-6.57 8.1445,-7.9027 0.8008,-6.0352 5.2539,-6.3281 9.4727,-8.1445 3.4101,-9.4727 -3.1562,-6.0547 -5,-7.0898 5.2617,-5.2617 2.1094,-5.2539 2.8906,6.8242 8.9375,0.8008 3.4375,-7.625 16.8128,4.207 3.945,14.9805 12.109,-1.0547 9.981,23.4101 -9.727,5.7891 0,14.4723 -7.617,3.418'}}
but if I use the same code with d as attr.
vis.selectAll("path")
.data(regionico).enter().append("path")
.attr("d",function(d) { return d.polygon.points})
.attr("stroke","red")
.attr("stroke-width",0.1);
it doesn't work.
Any suggestion?
The problem is simply that your SVG isn't big enough to make the path visible -- note in particular how you're first moving more than 100 pixels to the right before starting the path. It works fine if you make the SVG bigger, e.g. 300x300 here.

trouble with d3.js - scaling a path shape

I'm trying to scale this speech bubble into existence. I'm not really sure how to do it because the default d3 scale is changing the area where it starts drawing.
var svgHeight = 1000
var svgWidth = 1000
var floatycircleRadius = 30
var textColor = "#FFFFFF"
var svg = d3.select("body").append("svg")
.attr("width", svgHeight)
.attr("height", svgWidth)
var floatycontainer = svg.append("g");
var floatygroup = floatycontainer.append("g")
var floatypath = floatygroup.append("path")
.attr("d", "m125.512,0h-66C26.645,0,0,26.482,0,59.35c0,28.574,20.142,52.312,47,58.029V145l26.283-26.283, l52.229,0.064c32.868,0,59.512-26.563,59.512-59.431S158.38,0,125.512,0z")
.style("fill", "#90C4E4")
floatygroup.attr("transform", "translate(500, 500)")
floatycontainer.attr("transform", "scale(1)");
floatycontainer.transition().duration(2000).attr("transform", "0")
Use transition.attrTween(name, tween) on the <g> or <path> element.
.attrTween("transform", function(d, i, a) {
return d3.interpolateString(a, 'scale(1)');
});
http://jsfiddle.net/Wexcode/2jFP5/
So the problem wasn't that I couldn't get the item to scale. It's that when the item was scaling the "M" attribute was also shifting and the svg element was flying across the page due to mixed relative and absolute points on the path.
After changing the line manually to all relative so I could finish my project I found a javascript script to change all paths to relative. Then I could manually change the "M" attribute to 0 so the scale would work correctly source (Convert SVG Path to Relative Commands).
I modified the script to better suit my needs and build this simple page using gist.github.com and bl.ocks.org so it's a simple site to get the all relative path. It fits my long term use case and I thought I'd share it for those interested. Thanks for your help.
http://bl.ocks.org/TheMcMurder/6393419 (live page to convert)

How can I "best fit" an arbitrary cairo (pycairo) path?

It seems like given the information in stroke_extents() and the translate(x, y) and scale(x, y) functions, I should be able to take any arbitrary cairo (I'm using pycairo) path and "best fit" it. In other words, center it and expand it to fill the available space.
Before drawing the path, I have scaled the canvas such that the origin is the lower left corner, up is y+, right is x+, and the height and width are both 1. Given these conditions, this code seems to correctly scale the path:
# cr is the canvas
extents = cr.stroke_extents()
x_size = abs(extents[0]) + abs(extents[2])
y_size = abs(extents[1]) + abs(extents[3])
cr.scale(1.0 / x_size, 1.0 / y_size)
I cannot for the life of me figure out the translating though. Is there a simpler approach? How can I "best fit" a cairo path on its canvas?
Please ask for clarification if anything is unclear in this question.
I have found a solution that I like (at least for my purposes). Just create a new surface and paint the old surface on to the new one.
As for the scale only, I have done a similar thing to adjust an image inside a box with a "best-fit" approach. As about scale, here is the code:
available_width = 800
available_height = 600
path_width = 500
figure_height = 700
# formulas
width_ratio = float(available_width)/path_width
height_ratio = float(available_height)/figure_height
scale = min(height_ratio, width_ratio)
# result
new_path_width = path_width*scale
new_figure_height = figure_height*scale
print new_path_width, new_figure_height
The image gets drawn aligned to the origin (top left in my case), so perhaps a similar thing should be done to translate the path.
Also, this best fit is intended to preserve aspect ratio. If you want to stretch the figure, use each of the ratios instead of the 'scale' variable.
Hope I have helped

Resources