【问题标题】:How to make a Raphael fill pattern move with the element? (background image position relative to the element)如何使 Raphael 填充图案随元素移动? (背景图像相对于元素的位置)
【发布时间】:2013-07-21 10:03:06
【问题描述】:

如何为 Raphael 元素提供一个随元素移动而移动的填充,就像 position: absolute; HTML 元素的 CSS background-image 如何在移动时相对于其位置保持相同的位置?

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

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


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

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


有一个question similar to this for pure SVG,但在撰写本文时没有任何好的答案,当然也没有适合 Raphael 的答案。


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

所以一种可能性可能是to define a custom attribute 将变换应用于元素而不将其应用于模式。听起来很难——可能需要破解 Raphael 或复制大量 Raphael 转换代码。希望还有别的办法。还有god help us making this work in VML...


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

【问题讨论】:

    标签: svg raphael background-image


    【解决方案1】:

    我最近偶然发现了一个类似的问题。我在任何地方都找不到可行的解决方案,所以我想出了自己的解决方案。我使用@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 + ")"});
        }
    },
    

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

    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 更新。然而,拉斐尔最近变化不大,所以我愿意冒这个险。


    编辑:修复了此处描述的错误:Image blurry when using url fill pattern for svg circle

    【讨论】:

      【解决方案2】:

      编辑:

      对此有一个粗略的解决方法,不需要破解 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 的 Raphael 函数。

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

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


      原始答案:这是一种修复方法。它在两个方面很丑:

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

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

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


      您可以通过以某种方式关闭 Raphael 函数 updatePosition() 来解决这个难看的问题。上述行为不是 SVG 的默认行为,它是 updatePosition() 函数中定义的 Raphael 功能,似乎旨在使 Raphael SVG 元素的行为与 Internet Explorer 时 VML 元素的行为相匹配不是一堆错误与错误结合在一起的。请注意,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 设置 @ 987654338@ 进行动态计算。这些似乎是 updatePosition() 的 VML 等价物。理论上,VML 应该默认设置相对于形状的填充,只要alignshape = true for the fill element, which in theory should be true by default

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

      【讨论】:

        猜你喜欢
        • 2011-07-19
        • 2013-08-09
        • 1970-01-01
        • 1970-01-01
        • 2013-06-01
        • 2023-03-10
        • 2011-04-17
        相关资源
        最近更新 更多