Snap.svg and dynamic text - javascript

I'm trying to place text dynamically into an svg created by Snap, this is what I tried:
this.setContent(
`<svg id="${this.svgId}"></svg>`
);
var snap = Snap($(`#${this.svgId}`)[0]);
text = "asdfsdfsdsfd";
var rect = snap.paper.rect(0, 0, 50, text.length*3 + 4, 10);
snap.text(1.5,10, text);
console.log("rect", rect);
console.log("snap", snap);
rect.attr({
fill: "#FFFFFF",
fillOpacity: 0.6,
});
I get this:
I want the rectangle to be just a little bigger than the text, but there must be a better way to do it than to calculate the length and height of the text, and that's assuming the font size won't change.
This is the only result I found regarding text in the snap docs: http://snapsvg.io/docs/#Paper.text

You could try using getBBox() on the text element, and use that to figure the size of the rect. getBBox() wll give you the x,y,width,height,x2,y2 figures to help.
var text = s.text(0,0,'blah blah')
var bb = text.getBBox();
var rect = s.rect(bb.x, bb.y, bb.width, bb.height )
Adjusting with offsets for whatever padding etc that you want. You may also need to allow for stroke widths, as I don't think that's included.

Related

Place text in kendo donut chart

I am trying to create a semi circle donut chart to show some progress data. This I was able to complete. Further I needed to place text inside/ center of the donut chart which again I was able to do successfully. Now I have a new requirement where I need to show some text on the start and end positions of the graph(I need 0% and 100% to be shown on either axis). I tried several ways without any ado. Can you please help me with a possible solution.
Please find the dojo I created here:
http://dojo.telerik.com/Exike
This is roughly what I would like my end result to appear like:
Any suggestions for the same?
Thanks in advance.
You could add a couple of text boxes to your render function and use the bounding box to place them:
render: function (e) {
var draw = kendo.drawing;
var geom = kendo.geometry;
var chart = e.sender;
// The center and radius are populated by now.
// We can ask a circle geometry to calculate the bounding rectangle for us.
var circleGeometry = new geom.Circle(center, radius);
var bbox = circleGeometry.bbox();
// Render the text
var text = new draw.Text("33%", [0, 0], {
font: "18px Verdana,Arial,sans-serif"
});
// Align the text in the bounding box
draw.align([text], bbox, "center");
draw.vAlign([text], bbox, "center");
var text0 = new draw.Text("0%", [bbox.origin.x, bbox.origin.y + bbox.size.height / 2 ], {
font: "10px Verdana,Arial,sans-serif"
});
var text100 = new draw.Text("100%", [bbox.origin.x + bbox.size.width - 28, bbox.origin.y + bbox.size.height / 2 ], {
font: "10px Verdana,Arial,sans-serif"
});
// Draw it on the Chart drawing surface
e.sender.surface.draw(text);
e.sender.surface.draw(text0);
e.sender.surface.draw(text100);
}
Use DonutCenterTemplate for that:
<ng-template kendoChartDonutCenterTemplate>
<h3>99.5%</h3>
Accepted
</ng-template>

svg text with background under the text

Need to "mark" a svg text item with a background color, it has to be generated with javascript.
Found a working method but it needs to code the text, get the bbox values and draws a rect at the text position. I can't use "fill-opacity" (the text/background need to be above other elements!) and with a solid colored rect the text isn't seen anymore.
With the idea "first element -> 'painted' first" or the last element will be seen, I rewrite the text element once more .. all is ok ... but is there a simpler method?
Roughly the code is this:
var textColored = function (parent, text, idTxt, anchor, xT, yT, textColor, fillColor) {
var labelText = $svg.text(idTxt,
xT, yT,
text, // "xTime.hh+":"+xTime.mm + " Sunset",
{
fill: textColor,
"font-size": defaultOptions.fontSize,
"text-anchor": anchor,
"font-style": "italic"
}
)
labelText.appendTo(parent);
// background for text
var bbox = $("#" + idTxt)[0].getBBox();
var sRect = $svg.rect(
// "x","y","width","height"
bbox.x -2, bbox.y, bbox.width + 4, (+defaultOptions.fontSize + 3)
)
.attr("fill", fillColor)
// .prependTo(parent); // not working! added to first position of 'parent', see Inspector
.appendTo(parent);
labelText.appendTo(parent);
}
Tried with the edited code to use '.prependTo' but that adds the background element to the top of 'parent' and so at lowest level - behind all other svg elements.
Also failed with <g> element as recommended by Robert failed (for the moment).
Probably will stay with the double adding the text element which works fine using scripting with bbox. As described the background size and position has to be 'generated' based on the text.

$(object)[0].offsetTop working in Chrome but not in Firefox

I'm trying to access this property:
$(text)[0].offsetTop
It works fine in Chrome, but in Firefox I get 'undefined'.
Is there any way to do this in all browsers?
See: http://jsfiddle.net/qgqr5m6n/3/
$("body").css("margin", "0px");
var svgNS = "http://www.w3.org/2000/svg";
var svgBox = document.createElementNS(svgNS, "svg");
$("body").append(svgBox);
var text = document.createElementNS(svgNS, "text");
$(svgBox).append(text);
text.innerHTML = "Hello World";
$(text).attr({ "dominant-baseline": "hanging"});
console.log($(text)[0].offsetTop);
$(text).attr({ "x": 0 , "y": 0 });
In case you are wondering what I need this for:
I want to align a text of variable font-size in the VERTICAL center of a rectangle. The font size, however, always includes a little gap above the actual top of the letter. What I want is the actual pixel height. This gap above the letter is exactly the value of "offsetTop" after I set "dominant-baseline" to "hanging".
Instead $(element)[0].offsetTop, use $(element).offset() that returns an object with Top and left.

Raphael.js centered text on path

What I have:
Text along a path made out of circle. It uses Raphael.js and a function called textOnPath (found here: Raphael JS Text Along path ):
var pathTest = r.path(getCircletoPath(286, 322, radius)).attr({stroke:"#b9b9b9"});
textOnPath(message, pathTest, fontSize, fontSpacing, kerning, kerning, point, textFill, fontNormal, fontFamily);
JSFiddle: http://jsfiddle.net/zorza/62hDH/1/
What I need:
The text to be centered on top of the circle.
My approach:
Try to calculate where the text should start depending on the arc size and text width. I tried to calculate the text width by creating it's invisible clone with text() function and get it's BBox width.
It doesn't quite work and the results vary depending on the web browser, font used and number of letters and spaces:
var length = r.text(100,400,message)
.attr({"font-size":fontSize,'opacity': 0, 'font-family': fontFamily})
.getBBox()
.width;
var point = (Math.PI*radius - length*fontSpacing)/2;
JSFiddle: http://jsfiddle.net/zorza/k8vBy/3/
Could anyone point me in the right direction?
The easiest way, IMHO, is to create additional helper path that is raised by half of text size. http://jsfiddle.net/p84VQ/
Also, I find it a bit more convenient to define a circle and then get points at specified angle:
var Circle = function(cx, cy, r) {
return function (a) {
return {
x: cx + r*Math.sin(Math.PI*-a/180),
y: cy - r*Math.cos(Math.PI*-a/180)
}
}
};

how to change size of raphael icons?

how I can change the width and the height of icons from free Raphael icons ?
I tried to use attr, tried to use % , like this var paper = Raphael("canvas", 100%, 100%);.
I need to do this: if I change the size of the parent block, the size of my icon changes too.
upd: i tried use "scale" and "transform", but icon resize from centre and not fit into the parent correctly
According to the Raphael.js documentation
var el = paper.rect(10, 20, 300, 200);
// translate 100, 100, rotate 45°, translate -100, 0
el.transform("t100,100r45t-100,0");
// if you want you can append or prepend transformations
el.transform("...t50,50");
el.transform("s2...");
// or even wrap
el.transform("t50,50...t-50-50");
// to reset transformation call method with empty string
el.transform("");
// to get current value call it without parameters
console.log(el.transform());
Check this Fiddle:
Demonstration of all the transformations
var icon = paper.rect(100,200,100,100);
var anim = Raphael.animation({
"10%":{transform:'t100,0'}, //transform on x-axis
"20%":{transform:'...t0,100'},//transform on y-axis
"30%":{transform:'...t-100,0'},//transform on x-axis(negative)
"40%":{transform:'...t0,-100'},//transform on y-axis(negative)
"50%":{transform:'...t200,200'},//transform diagonally
"60%":{transform:'...t-100,-100'},//transform diagonally(negative)
"70%":{transform:'...s1,1.5'},//scale y-axis
"80%":{transform:'...s1.5,1'},//scale x-axis
"90%":{transform:'...s2'},//scale in both direction
"100%":{transform:'...r45'},//rotate
},5000);
icon.animate(anim.delay(1000));
So in your case you'll have to do this:
var somename = paper.path("path coordinates").transform('s2,3');
where 2 is for width & 3 is for height.

Categories