6

我怎样才能给 Raphael 元素一个随着元素移动而移动的填充,就像 HTML 元素的 CSS 如何在移动时background-imageposition: absolute;对于它的位置保持相同的位置?

这是一个示例演示:如何使 Raphael 元素(三角形路径)的背景图像模式在拖动时与 HTML 元素(方形 div)表现相同?

http://jsbin.com/oxuyeq/8/edit


这个问题本质上与如何在 Raphael.js / IE 中“固定”模式相反?使用偏光眼镜模拟器 - 我想让他们试图避免的特定于 IE 的行为在所有浏览器(包括 IE8)中始终如一地发生。

正如其他问题中详述的那样,仅在 IE8 (VML) 中,Raphael 元素的行为符合我的要求;但即使这样也是不稳定的:诸如调用元素或重新定义填充(本质上是任何强制重绘的东西)等各种事情都会导致它切换到其他行为setSizepaper


对于纯 SVG有一个与此类似的问题,但在撰写本文时没有任何好的答案,当然也没有对 Raphael 有用。


编辑 2:观察 SVG 模式下发生的情况,似乎每个 Raphael 变换也会自动对 svg<pattern>元素进行相同的矩阵变换。我认为这是导致我试图避免的行为的原因 - 我认为patternContentUnits并且patternUnits是无关的。这里似乎有一个未解决的问题(突出显示与剪辑矩形相同的问题,在该行旁边this.pattern && updatePosition(this);) - https://github.com/DmitryBaranovskiy/raphael/issues/638

因此,一种可能性可能是定义一个自定义属性,该属性将转换应用于元素而不将其应用于模式。听起来很难——可能需要破解 Raphael 或复制大量 Raphael 变换代码。希望还有别的办法。上帝帮助我们在 VML 中完成这项工作......


编辑3:一些可能相关的信息,不仅仅是路径填充有这个问题。创建的Raphaelimage元素paper.image()在 SVG 模式下没有这个问题,但在 IE8 VML 模式下有一个非常相似的问题。这是使图像元素移动的几种方法的演示,这是一个并排比较,显示它们如何在非 IE 中完美地工作,而在 IE 中都失败:

在此处输入图像描述

4

2 回答 2

3

我最近偶然发现了一个类似的问题。我在任何地方都找不到可行的解决方案,所以我想出了自己的解决方案。我使用@user568458 的答案作为起点。首先,我像这样更改了 updatePosition 函数:

 updatePosition = function (o) {
    if(!o.data("relativeFill")) { //data is a custom store for user's properties
        var bbox = o.getBBox(1);
        $(o.pattern, {patternTransform: o.matrix.invert() + " translate(" + bbox.x + "," + bbox.y + ")"});
    }
},

我还改变了函数的fill大小写,setFillAndStroke如下所示:

var relativeFill = o.data("relativeFill"),
isURL = Str(value).match(R._ISURL);
if (isURL) {
    el = $("pattern");
    var ig = $("image");
    el.id = R.createUUID();
    $(el, {x: 0, y: 0, patternUnits: relativeFill ? "objectBoundingBox" : "userSpaceOnUse", height: 1, width: 1});
    $(ig, {x: 0, y: 0, "xlink:href": isURL[1]});
    el.appendChild(ig);

    (function (el) {
        R._preload(isURL[1], function () {
            var w = this.offsetWidth,
                h = this.offsetHeight,
                bbox = o.getBBox();
            $(el, {width: 1, height: 1});
            $(ig, {width: relativeFill ? bbox.width : w, height: relativeFill ? bbox.height : h});
            o.paper.safari();
        });
    })(el);
    o.paper.defs.appendChild(el);
    $(node, {fill: "url(#" + el.id + ")"});
    o.pattern = el;
    o.pattern && updatePosition(o);
    break;
}

然后每当你想使用它时,你必须设置yourElement.data({ relativeFill: true })

这是一个具有相对和重复填充的工作示例:https ://codepen.io/mmazur/pen/Gmebrj?editors=0010


我同意@user568458,这个解决方案非常丑陋,可能会停止使用未来的 Raphael 更新。然而,拉斐尔最近变化不大,所以我愿意冒这个险。


编辑:修复了此处描述的错误:使用 svg 圆的 url 填充模式时图像模糊

于 2017-05-25T20:46:18.957 回答
1

编辑:

有一个粗略的解决方法,不需要破解 Raphael 核心代码,但确实依赖于不完全稳定的 IE 错误,描述为 https://github.com/DmitryBaranovskiy/raphael/issues/177

它通过在 Raphael 对象中重命名 SVG 模式对象来隐藏 SVG 模式对象,从而导致updatePosition()不被调用。这会阻止 Raphael 在 SVG 模式下移动背景图像。在 VML 模式下,IE8 有一个错误,即即使代码移动了<fill>元素,它也不会在屏幕上更新,直到强制重绘。

path.patternTmp = path.pattern;
delete path.pattern;

这与下面的建议具有相同的其他缺点,即在 VML 模式下它依赖于 IE 错误。但它适用于简单的情况。我还没有完全测试到这个修复是否还有其他副作用,但不应该 - 查看 Raphael 的源代码,它看起来updatePosition()是唯一使用element.pattern.

http://jsbin.com/oxuyeq/10/edit

请注意,path.pattern每次应用图像填充时都必须像这样重命名 - 因此,如果您出于任何原因重新应用填充,则需要重新进行此修复 - 并且重新应用填充将“修复”我们的 IE 错误取决于导致图像与对象不同步。


原始答案:这是一种修复。它的丑陋体现在两个方面:

  • 对于 SVG,它依赖于 hacking Raphael 核心代码(但只是一个小 hack)
  • 对于 VML,它依赖于 Internet Explorer 重绘错误,如果您的代码导致重绘,它将失败

但是您可以获得相对位置,只要您的代码不会触发 IE 重绘(例如,通过重新设置元素的填充)。

理想情况下,有一种方法可以在 IE VML 中稳健地工作,而不是依赖于错误。


你可以通过某种方式关闭 Raphael 函数updatePosition()来完成这个丑陋的几乎修复。上述行为不是 SVG 的默认行为,它是函数中定义的 RaphaelupdatePosition()功能,似乎旨在使 Raphael SVG 元素的行为与 VML 元素的行为相匹配,如果Internet Explorer 不是与错误。请注意,该updatePosition()函数在 SVG 模式下调用 - 默认情况下,VML 填充应该以这种方式运行(但由于上述链接问题中描述的重绘错误......)。

我的(丑陋的)这样做的方法是将updatePosition()功能代码修改为:

updatePosition = function (o) {
    if(!o.relativeFill) {  // <<< added this condition
        var bbox = o.getBBox(1);
        $(o.pattern, {patternTransform: o.matrix.invert() + " translate(" + bbox.x + "," + bbox.y + ")"});          
    }
},

...然后,对于您想要相对填充的每个元素,您设置someElement.relativeFill = true;


请注意,这不是一个好的做法——例如,未来的 Raphael 更新可能会将 relativeFill 命名空间用于其他内容。这只是(几乎)有效的粘性石膏修复的一个例子。


回覆。VML 模式:理论上,您可以通过在 VML 模式 Raphael 函数setFillAndStroke和/或setCoords设置fill.position为动态计算的位置添加类似条件来使此修复变得健壮且不依赖于错误。这些似乎是updatePosition(). 理论上,VML 应该默认设置相对于形状的填充,只要alignshape = true填充元素,理论上默认情况下应该是 true

但是,在实践中它似乎并不像那样工作。从我的测试来看,依赖上面的 IE 错误实际上似乎比试图让 IE VML 像记录的那样工作更强大。在我的测试中,让 IE8 重新绘制填充非常困难:似乎只有重置填充才能做到。

于 2013-07-23T11:29:27.037 回答