73012

Creating Curved Text with SVG and JS

Question:

I want to create curved text in SVG using Javascript. I have faced a lot of problems, specially the namespace related ones, but now everything works, a path and a circle are successfully shown, but the text is not displayed. When I copy-paste the created svg code in browser inspector and add that to the svg, it works as intended. But I can't make it work using JS. The whole code is as you can see:

<html> <body onload="onLoad()"> <div id="svgbox"></div> </body> <script> var svg; var last_shape; // for debug function qs(sel) { return document.querySelector(sel); } function SVG(el) { this.element = document.createElementNS("http://www.w3.org/2000/svg", "svg"); qs(el).appendChild(this.element); var props = { "xmlns": "http://www.w3.org/2000/svg", "xmlns:xlink": "http://www.w3.org/1999/xlink", "version": "1.1", "style": "width:100%;height:100%;", "stroke": "#58b", "fill":"none", "stroke-width": "2" }; for (i in props) { this.element.setAttribute(i, props[i]); } this.create = function(tag,props) { var o = document.createElementNS("http://www.w3.org/2000/svg", tag); if(typeof(props)!="undefined") { for (i in props) { o.setAttribute(i, props[i]); } } return o; } this.add = function(tag,props) { var o = this.create(tag,props); this.element.appendChild( o ); return o; }; this.addTo = function(parent, tag, props) { var o = document.createElementNS("http://www.w3.org/2000/svg", tag); if(typeof(props)!="undefined") { for (i in props) { o.setAttribute(i, props[i]); } } parent.appendChild(o); return o; }; return this; } function drawArc(svg, fromX, fromY, toX, toY, controlX, controlY, props) { var o = svg.add( "path", { "d":"M" + fromX + " " + fromY + " Q " + controlX + " " + controlY + " " + toX + " " + toY }); if(typeof(props)!="undefined") { for (i in props) { o.setAttribute(i, props[i]); } } last_shape = o; return o; } function drawLabeledArrow(svg, fromX, fromY, toX, toY, title, props) { var arc_id = "arc-"+Math.floor(Math.random()*10000000); var arc = drawArc( svg, fromX, fromY, toX, toY, (fromX+toX)/2, (fromY+toY)/2 - (fromX+toX)/2, {id: arc_id}); var head_base_x = arc.getPointAtLength(arc.getTotalLength() - 4).x; var head_base_y = arc.getPointAtLength(arc.getTotalLength() - 4).y; last_shape = svg.add("text"); last_shape = svg.addTo(last_shape, "textPath", {"fill":"#ff0000", "xlink:href":"#"+arc_id}); last_shape.appendChild(document.createTextNode(title)); last_shape = svg.add( "circle", { cx: head_base_x, cy: head_base_y, r: 4, fill: "#5ad" }); } function onLoad() { svg = SVG('#svgbox'); drawLabeledArrow(svg, 10,100, 200, 100, "test label"); } </script> </html>

I'd appreciate if anyone tells me what's wrong here, and if there is any good and short explanation of all these problems in working with SVG in JS. Thanks.

<hr />

UPDATE: I modified the code to use setAttributeNS instead, but still no success.

function drawLabeledArrow(svg, fromX, fromY, toX, toY, title, props) { var arc_id = "arc-"+Math.floor(Math.random()*10000000); var arc = drawArc( svg, fromX, fromY, toX, toY, (fromX+toX)/2, (fromY+toY)/2 - (fromX+toX)/2, {id: arc_id}); var head_base_x = arc.getPointAtLength(arc.getTotalLength() - 4).x; var head_base_y = arc.getPointAtLength(arc.getTotalLength() - 4).y; last_shape = svg.add("text"); var o = document.createElementNS("http://www.w3.org/2000/svg", "textPath"); o.setAttributeNS("http://www.w3.org/2000/svg", "xlink:href", "#"+arc_id); o.appendChild(document.createTextNode(title)); last_shape.appendChild( o ); last_shape = svg.add( "circle", { cx: head_base_x, cy: head_base_y, r: 4, fill: "#5ad" }); }

Answer1:

The xlink:href attribute cannot be set with setAttribute as that method can only set attributes in the null namespace and xlink:href is in the xlink namespace.

Use setAttributeNS instead and specify the xlink namespace <a href="http://www.w3.org/1999/xlink" rel="nofollow">http://www.w3.org/1999/xlink</a> as the first argument.

Recommend

  • html - Get wrapped text from textarea
  • how to fetch data from multiple tables MySQL
  • React Router 3, exactly match against query param
  • TSQL query to find last execution time of a UDF
  • Alternative To body {overflow:scroll;} That Will Prevent Page Jostling/Wriggling?
  • Play WS (2.2.1): post/put large request
  • Can I check if a recipient has an automatic reply before I send an email?
  • DomPDF {PAGE_NUM} not on first page
  • Javascript simulate pressing enter in input box
  • Getting last autonumber in access
  • Problems to linebreak with an int in JLabel
  • Apache 2.4 and php-fpm does not trigger apache http basic auth for php pages
  • How to add date and time under each post in guestbook in google app engine
  • Fill an image in a square container while keeping aspect ratio
  • Can a Chrome extension content script make an jQuery AJAX request for an html file that is itself a
  • Symfony2: How to get request parameter
  • Importing jscolor library in angular 2
  • Weird JavaScript statement, what does it mean?
  • jquery mobile loadPage not working
  • Warning: Can't call setState (or forceUpdate) on an unmounted component
  • How to get icons for entities from eclipse?
  • A cron job substitute?
  • How to delete a row from a dynamic generate table using jquery?
  • Proper way to use connect-multiparty with express.js?
  • Load html files in TinyMce
  • using HTMLImports.whenReady not working in chrome
  • -fvisibility=hidden not passed by compiler for Debug builds
  • How to CLICK on IE download dialog box i.e.(Open, Save, Save As…)
  • Authorize attributes not working in MVC 4
  • EntityFramework adding new object to nested object collection
  • JaxB to read class hierarchy
  • costura.fody for a dll that references another dll
  • Binding checkboxes to object values in AngularJs
  • Observable and ngFor in Angular 2
  • How to Embed XSL into XML
  • UserPrincipal.Current returns apppool on IIS
  • Conditional In-Line CSS for IE and Others?
  • Net Present Value in Excel for Grouped Recurring CF
  • jQuery Masonry / Isotope and fluid images: Momentary overlap on window resize
  • How to load view controller without button in storyboard?