Problems with dynamically generated linearGradient on Firefox and IE

498 views
Skip to first unread message

Chris Nicola

unread,
Sep 12, 2014, 1:55:02 PM9/12/14
to d3...@googlegroups.com
I've also posted this question to SO here: https://stackoverflow.com/questions/25793720

The D3 gradient example does work in Firefox and IE (obviously), but I've created an AngularJS directive that can update the stop values as well as linearGradient attributes dynamically after inserting the gradient into the DOM which it doesn't seem to like.

The code (which uses AngularJS) looks like this:

    gradient = svg.insert("defs", 'g')
      .append("linearGradient")
      .attr("id", $attrs.id)

    ['x1', 'x2', 'y1', 'y2'].forEach (attr) ->
      $attrs.$observe attr, (val) -> gradient.attr(attr, val)

    $attrs.$observe 'transition', (val) -> transition = val if val?

    $scope.$watch $attrs.stops, (stops) ->
      return unless stops?
      stops = gradient.selectAll('stop').data(stops)
      stops.enter().append('stop')
      stops.attr('offset', (d) -> d.offset)
        .attr('stop-color', (d) -> d.color)
        .attr('stop-opacity', (d) -> if d.opacity? then d.opacity else 1)
      stops.exit().remove()

Essentially Angular will set x1, x2, y1 and y2 dynamically if the attributes change (this allows for variable interpolation on those attributes. And we bind the stops to a Javascript array of stop values and if they change Angulary will rerun the function attached to $watch. It uses a pretty standard D3 enter/exit setup as far as I can tell.

It works perfecting in Chrome and Safari but Firefox displays nothing. If I copy the resulting SVG to a JSFiddle and render it statically however it does work. I'm guessing a Firefox bug but I though it was worth it to get a second opinion from the experts.

Jason Davies

unread,
Sep 12, 2014, 4:52:52 PM9/12/14
to d3...@googlegroups.com
On Fri, Sep 12, 2014 at 10:55:01AM -0700, Chris Nicola wrote:
> I've also posted this question to SO
> here: https://stackoverflow.com/questions/25793720

I've answered it. For posterity, I'll summarise the Firefox issue here
in case anyone else runs into the same problem.

Chris had created a simple SVG linearGradient, similar to Mike's:

http://bl.ocks.org/mbostock/1086421

In Mike's, the rectangle fill is set to the gradient using an inline
style, like this:

.style("fill", "url(#gradient)");

However, Chris was setting it using a stylesheet instead:

rect { fill: url(#gradient); }

This works fine when it's in the same document, but not if it's in an
external CSS file!

The reason is that Firefox expands partial URLs relative to their
containing document, so url(#gradient) becomes url(style.css#gradient).

You could use url(./#gradient) or url(document.html#gradient), but only
if style.css is in the same directory. Suppose style.css is in a
subdirectory called "css". You could try url(../#gradient) but I found
that this works in Firefox and not Chrome.

I think the best advice is not to use partial URLs in external
stylesheets like this (unless anyone else knows of a better workaround).

--
Jason Davies, http://www.jasondavies.com/
Reply all
Reply to author
Forward
0 new messages