How to draw a Raphael pattern with an element? (position of the background image relative to the element)

How can I give a Raphael element a pad that moves as the element moves, for example, as a CSS background-image an HTML element position: absolute; Will keep the same position relative to its location when it was moving?

Here is a demo example: how can I make the background image template of the Raphael element (triangular path) behave the same when dragging as an HTML element (square div)?

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


This question is essentially the opposite. How to make the template “fixed” in Raphael.js / IE? with polarized glasses simulator. I want the IE behavior that they were trying to avoid to happen consistently in all browsers (including IE8).

As detailed in this other question, only in IE8 (VML), the Raphael element behaves the way I want; but even this is unstable: various things, such as calling setSize on the paper element or overriding the padding (essentially all that forces you to redraw), lead to switching to another behavior.


Here is a question similar to this for pure SVG , but without any good answers at the time of writing, and, of course, no one works for Raphael.


Change 2 . Watching what happens in SVG mode, it seems that each Raphael transformation automatically performs the same transformation of the matrix into the svg <pattern> element. I think this is what causes the behavior I am trying to avoid - I think that patternContentUnits and patternUnits not connected. There is an unresolved problem that is related here (highlighting the same problem with clip-rect, next to the line this.pattern && updatePosition(this); ) - https://github.com/DmitryBaranovskiy/raphael/issues/638

Thus, one possibility might be to define a custom attribute that applies the transform to an element without applying it to the template. It sounds complicated - you may need to hack Raphael or duplicate a lot of Raphael's conversion code. Hope something else. And God will help us do this work in VML ...


Edit 3: Some potentially relevant information is not just a path that has this problem. Raphael image elements created with paper.image() do not have this problem in SVG mode, but they have a very similar problem, which is very bad in IE8 VML mode. Here is a demonstration of several ways to make image elements move, and here it is compared side by side, showing how they all work flawlessly in non-IE and all do not work in IE:

enter image description here

+6
svg background-image raphael
source share
2 answers

I recently encountered a similar problem. I could not find a working solution anywhere, so I came up with my own. I used @ user568458 answer as a starting point. First, I changed the updatePosition function as follows:

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

I also changed the fill case of the setFillAndStroke function as follows:

 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; } 

Then, when you want to use it, you must set yourElement.data({ relativeFill: true })

Here is a working example with relative and refill: https://codepen.io/mmazur/pen/Gmebrj?editors=0010


I agree with @ user568458, this solution is very ugly and may stop working with a future Raphael update. However, Raphael has not changed much lately, so I'm fine with this risk.


EDIT: Fixed the error described here: The image is blurry when using the URL fill pattern for SVG circle

+3
source share

Edit:

There is a rough workaround that does not require hacking Raphael's kernel code, but depends on the not completely stable IE error described by https://github.com/DmitryBaranovskiy/raphael/issues/177

It works by hiding the SVG template object from Raphael, renaming it a Raphael object, as a result of which updatePosition() will not be called. This stops Raphael moving the background image in SVG mode. In VML mode, IE8 has an error in which, although the code moves the <fill> element, it does not refresh on the screen until it is forced to redraw.

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

This has the same drawback as the assumption below that in VML mode it relies on an IE error. But it works for simple cases. I have not tested fully enough to see if there are other side effects of this fix, but it shouldn’t be - look at the Raphael source code, it looks like updatePosition() is the only Raphael function that uses element.pattern .

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

Please note that path.pattern needs to be renamed the way it is done every time the image is applied - therefore, if you use the placeholder by default, you need to re-execute this fix, and re-applying the fill will "fix IE error, we will depend from the fact that the image eludes synchronization with the object.


Original answer: There is a kind of correction here. This is ugly in two ways:

  • For SVG, it relies on hacking Raphael's kernel code (but only a small hack).
  • For VML, it relies on Internet Explorer redraw error and will fail if your code causes redraw

But you can get relative positions if your code does not cause IE to redraw (for example, by overriding the padding of an element).

Ideally, there would be a way to do this, which would work in IE VML, rather than relying on an error.


You can make this ugly almost correction by disabling the Raphael function updatePosition() somehow . The behavior described above is not an SVG standard, it is the Raphael function defined in the updatePosition() function, which seems to be designed to ensure that the behavior of the Raphael SVG elements matches what the VML elements would look like if Internet Explorer was not a collection errors along with errors. Note that the updatePosition() function is called only in SVG mode. VML populations should behave by default (but not reliably due to the redraw error described in the above related question ...).

My (ugly) way to do this is to change the updatePosition() function code to this:

 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 + ")"}); } }, 

... then for each element that you want to have a relative fill, you set someElement.relativeFill = true;


Please note that this is not good practice - for example. a future Raphael update may use the relativeFill namespace for something else. This is just an example of a sticky gypsum fix that (roughly) works.


repeatedly. VML mode:. Theoretically, you can make this fix reliable and not error-dependent by adding a similar condition to the place in the Raphael functions of the VML mode setFillAndStroke and / or setCoords that set fill.position to the dynamic calculation. This seems to be the equivalent of VML updatePosition() . Theoretically, VML should default to fill with respect to the form, while alignshape = true for the fill element, which should be true by default .

But it doesn't seem to work in practice. From my testing, relying on an IE bug, as shown above, actually seems more reliable than trying to get IE VML to work as documented. In my testing, it's pretty hard to get IE8 to redraw the fill: only resetting the fill seems to do it.

+1
source share

All Articles