使用 jQuery 修改 Raphael SVG 图像

发布于 2024-11-19 20:49:18 字数 3333 浏览 0 评论 0原文

我有一个小型应用程序,需要为弧生成文本路径标签。我通过拉斐尔绘制弧线,效果很好。然而 Raphael 不支持 textPaths。我们可以通过 jQuery 将它们添加到 svg 元素,但由于某种原因它们不会渲染。当我静态复制动态生成的代码时,它呈现得很好。

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="600" height="600">
  <desc>Created with Raphaël</desc><defs></defs>
  <a title="This is a test entry">
    <path fill="none" stroke="#1e79a0" d="M395.2627944162883,355A110,110,0,0,1,199.5099996593139,344.74103073833805" style="stroke-width: 20px; " stroke-width="20" id="This_is_a_test_entry"></path>
  </a>
  <text>
    <textpath xlink:href="#This_is_a_test_entry">This is a test entry</textpath>
  </text>
</svg>

使用上面的代码,您永远不会看到弧的标签。然而,当以下内容被硬编码时,它会按预期呈现:

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="600" height="600">
  <a title="Bacon">
    <path id="Arc" fill="none" stroke="#1e79a0" d="M395.2627944162883,355A110,110,0,0,1,201.13265490709162,348.2208261467985" style="stroke-width: 20;" stroke-width="20">
    </path>
  </a>
  <text>
    <textPath xlink:href="#Arc">This is an Arc</textPath>
  </text>
</svg>

任何关于为什么我没有看到我的整个 svg 的见解将不胜感激。

编辑:

我已经对我的 javascript 进行了更改,我认为它几乎就在那里,但 textPath 仍然不会呈现。这是当前的代码,主要感谢 Femi:

function drawRange(start, end, R, range, id, title) {
                    var color = "hsb(".concat(Math.round(R) / 200, ",", end / 360, ", .75)");
                    var key_position = key[id];
                    var svg_bits = document.getElementsByTagName('svg')[0].childNodes;
                    var svgns = document.createElementNS('http://www.w3.org/2000/svg', "path");
                    var path;
                    range.attr({title: title});
                    range.animate({arc: [start, end, R]}, 900, ">");
                    //Add an id to the path element that was just drawn.  This doesn't seem to help though.
                    for(var i = 0; i < svg_bits.length; i++) {
                        if (svg_bits[i].tagName == "a" && svg_bits[i].getAttribute('title') == title){
                            path = svg_bits[i].childNodes[0];
                        }
                    }
                    path.setAttribute('id', title);
                    //Add the name to the key, set the color and unhide the element.
                    $(key_position).html(range.attr("title"));
                    $(key_position).css('color', Raphael.getRGB(color).hex);
                    $(key_position).show();
                };



function makeSVG(tag, attrs) {
                    var el = document.createElementNS('http://www.w3.org/2000/svg', tag);
                    for (var k in attrs)
                        el.setAttribute(k, attrs[k]);
                    return el;
                };

function addLabel(label) {
                    var text = makeSVG("text", {});
                    var title = makeSVG("textPath", {"xlink:href":'#' + label.replace(/\s/g, '_')});
                    title.appendChild(document.createTextNode(label));
                    text.appendChild(title);
                    r.canvas.appendChild(text);
                };

我得到了 textPath 的边界框 0x0,但没有 textPath。

I have a small application where I need to generate textPath labels for arcs. I'm drawing the arcs via Raphael and that is working great. However Raphael has no support for textPaths. We can add them to the svg element via jQuery but they don't render for some reason. When I duplicate the dynamically generated code statically it renders fine.

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="600" height="600">
  <desc>Created with Raphaël</desc><defs></defs>
  <a title="This is a test entry">
    <path fill="none" stroke="#1e79a0" d="M395.2627944162883,355A110,110,0,0,1,199.5099996593139,344.74103073833805" style="stroke-width: 20px; " stroke-width="20" id="This_is_a_test_entry"></path>
  </a>
  <text>
    <textpath xlink:href="#This_is_a_test_entry">This is a test entry</textpath>
  </text>
</svg>

With the above code you never see the label for the arc. However when the following is hard coded it renders as expected:

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="600" height="600">
  <a title="Bacon">
    <path id="Arc" fill="none" stroke="#1e79a0" d="M395.2627944162883,355A110,110,0,0,1,201.13265490709162,348.2208261467985" style="stroke-width: 20;" stroke-width="20">
    </path>
  </a>
  <text>
    <textPath xlink:href="#Arc">This is an Arc</textPath>
  </text>
</svg>

Any insight as to why I'm not seeing my entire svg would be much appreciated.

EDIT:

I've made changes to my javascript and I think it's almost there but the textPath still won't render. Here is the current code, mostly thanks to Femi:

function drawRange(start, end, R, range, id, title) {
                    var color = "hsb(".concat(Math.round(R) / 200, ",", end / 360, ", .75)");
                    var key_position = key[id];
                    var svg_bits = document.getElementsByTagName('svg')[0].childNodes;
                    var svgns = document.createElementNS('http://www.w3.org/2000/svg', "path");
                    var path;
                    range.attr({title: title});
                    range.animate({arc: [start, end, R]}, 900, ">");
                    //Add an id to the path element that was just drawn.  This doesn't seem to help though.
                    for(var i = 0; i < svg_bits.length; i++) {
                        if (svg_bits[i].tagName == "a" && svg_bits[i].getAttribute('title') == title){
                            path = svg_bits[i].childNodes[0];
                        }
                    }
                    path.setAttribute('id', title);
                    //Add the name to the key, set the color and unhide the element.
                    $(key_position).html(range.attr("title"));
                    $(key_position).css('color', Raphael.getRGB(color).hex);
                    $(key_position).show();
                };



function makeSVG(tag, attrs) {
                    var el = document.createElementNS('http://www.w3.org/2000/svg', tag);
                    for (var k in attrs)
                        el.setAttribute(k, attrs[k]);
                    return el;
                };

function addLabel(label) {
                    var text = makeSVG("text", {});
                    var title = makeSVG("textPath", {"xlink:href":'#' + label.replace(/\s/g, '_')});
                    title.appendChild(document.createTextNode(label));
                    text.appendChild(title);
                    r.canvas.appendChild(text);
                };

I get a bounding box of 0x0 for the textPath but no textPath.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

硪扪都還晓 2024-11-26 20:49:19

您可能需要删除第一个示例中出现的 xlink,或者添加适当的 XML 命名空间定义。

编辑:当您添加 textPath 元素时,您可能需要使用正确的元素名称(textPath,而不是 textpath)。

编辑:相当有趣,因为它是浏览器和 jQuery 改变路径的组合。要获得正确的东西,请使用此函数(从jquery 的追加不适用于 svg 元素?):

function makeSVG(tag, attrs){
   var el= document.createElementNS('http://www.w3.org/2000/svg', tag);
   for (var k in attrs)
     el.setAttribute(k, attrs[k]);
   return el;
 }

然后执行以下操作:

var paper = Raphael("notepad", 320, 200);

// do all your other stuff here
...

var text = makeSVG("text", {});
       var c = makeSVG("textPath", {"xlink:href":"#Arc"});
       c.appendChild(document.createTextNode("This is an Arc"));
       text.appendChild(c);
paper.canvas.appendChild(text);

这将为您提供正确的 SVG:但是,它仍然无法正确绘制,这很奇怪。

You may need to either remove the xlink that appears in the first sample, or add the appropriate XML namespace definition.

EDIT: when you are adding the textPath element you may need to use the correct element name (textPath, not textpath).

EDIT: moderately interesting, as it is combination of the browser and jQuery changing the path. To get the right thing, use this function (liberated from the answer to jquery's append not working with svg element?):

function makeSVG(tag, attrs){
   var el= document.createElementNS('http://www.w3.org/2000/svg', tag);
   for (var k in attrs)
     el.setAttribute(k, attrs[k]);
   return el;
 }

And then do this:

var paper = Raphael("notepad", 320, 200);

// do all your other stuff here
...

var text = makeSVG("text", {});
       var c = makeSVG("textPath", {"xlink:href":"#Arc"});
       c.appendChild(document.createTextNode("This is an Arc"));
       text.appendChild(c);
paper.canvas.appendChild(text);

That will get you the right SVG: however, it still won't draw right, which is odd.

你的笑 2024-11-26 20:49:19

如果您不担心您的工作无法在 ie8 或更早版本中运行,为什么不使用 kieth wood 的支持 textpath 的 jquery SVG 插件
该插件的路径语法不同,但很容易从 Raphael 转换
SVG 插件提供了美丽的径向渐变,但这就是我现在参与其中的原因。

如果你想要路径上的文本而不是每个字母都沿着曲线走,那么你可以继续使用 Rap 并使用这个...http://irunmywebsite.com/raphael/additionalhelp.php?v=1&q=anglebannersoncurves

请原谅拼写 iPod新手

If your not worried about your work not working in ie8 or earlier why not use kieth wood's jquery SVG plugin that supports textpath
The path syntax for the plugin is different but easy to convert from Raphael
The SVG plugin delivers beautiful radial gradients but this is why I am involved with it now.

If you want text on a path without gollowing the curve with every letter then you could stay with Rap and use this...http://irunmywebsite.com/raphael/additionalhelp.php?v=1&q=anglebannersoncurves

Excuse spelling iPod newbie

指尖上得阳光 2024-11-26 20:49:19

Femi 的答案非常好,唯一缺少的是重绘和设置 xlink 命名空间。

我无法弄清楚根本原因,但它一定是 Raphael 核心中的某些东西阻止了 SVG 画布更新,因为修复绘图所需要做的就是通过快速删除然后读取 svg 元素来强制重绘来自 DOM:

$('#myRaphaelDiv').html($('#myRaphaelDiv').html());

应该注意的是,任何对 SVG 属性的直接攻击都会破坏与使用 VML 的浏览器(叹息,IE)的兼容性。我还没有研究过在 VML 中处理文本路径的方法。下面的代码是为了完整性。

// add the new namespace attribute to the SVG canvas. 'raphael' is the Raphael instance.
// note that this only needs to be done once.
$(raphael.canvas).attr('xmlns:xlink', "http://www.w3.org/1999/xlink");

// draw the curved text
var lblId = 'some_unique_dom_id';
var path = raphael.path().attr({
    stroke : 'none' // defaults to black
    // ...other path attributes used in generating it...
});
var label = raphael.text().attr({ 'text-anchor' : 'start' });

// create and inject raw SVG textPath element
var link;
try {
    link = document.createElementNS('http://www.w3.org/2000/svg', 'textPath');
} catch (e) {
    // no createElementNS() method is pretty much synonymous with using IE, so
    // this is where you would do your VML version of a text path
    alert("Your browser does not support SVG, please use Firefox, Chrome etc");
}
link.setAttribute('xlink:href', '#' + lblId);
link.appendChild(document.createTextNode("path-oriented text"));

// finally, force a redraw of the SVG document. 
// Obviously, you would defer this until all elements had been added.
$('#myRaphaelDiv').html($('#myRaphaelDiv').html());

Femi's answer is pretty good, the only things missing are getting it to redraw and setting the xlink namespace.

I can't figure out the underlying reason, but it must be something in the core of Raphael that prevents the SVG canvas from updating, since all you need to do to fix drawing is force a redraw by quickly removing and then readding the svg element from the DOM:

$('#myRaphaelDiv').html($('#myRaphaelDiv').html());

It should be noted that any direct hacking of SVG attributes will break compatibility with browsers (sigh, IE) that use VML instead. I've yet to look into a way of doing text paths in VML. Code below is for completeness.

// add the new namespace attribute to the SVG canvas. 'raphael' is the Raphael instance.
// note that this only needs to be done once.
$(raphael.canvas).attr('xmlns:xlink', "http://www.w3.org/1999/xlink");

// draw the curved text
var lblId = 'some_unique_dom_id';
var path = raphael.path().attr({
    stroke : 'none' // defaults to black
    // ...other path attributes used in generating it...
});
var label = raphael.text().attr({ 'text-anchor' : 'start' });

// create and inject raw SVG textPath element
var link;
try {
    link = document.createElementNS('http://www.w3.org/2000/svg', 'textPath');
} catch (e) {
    // no createElementNS() method is pretty much synonymous with using IE, so
    // this is where you would do your VML version of a text path
    alert("Your browser does not support SVG, please use Firefox, Chrome etc");
}
link.setAttribute('xlink:href', '#' + lblId);
link.appendChild(document.createTextNode("path-oriented text"));

// finally, force a redraw of the SVG document. 
// Obviously, you would defer this until all elements had been added.
$('#myRaphaelDiv').html($('#myRaphaelDiv').html());
十雾 2024-11-26 20:49:19

因此,在此处找到 Raphael 的补丁并对补丁进行一些小调整后,它是在职的。我仍然不确定我错过了什么,但 textPaths 现在呈现,每个人都很高兴。感谢大家的帮助。

So, after finding a patch to Raphael here and making a small tweak to the patch it is working. I'm still not sure what I was missing but the textPaths now render and everyone is happy. Thanks to everyone for the help.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文