How to position and size an SVG programmatically? (dynamic CSS not working)

1,690 views
Skip to first unread message

Curran

unread,
Mar 27, 2014, 12:07:55 AM3/27/14
to d3...@googlegroups.com
Greetings,

I am working on a project that dynamically creates, positions and resizes visualizations. I'm looking for a way to, given (x, y, width, height) in pixels, programmatically set the position and size of an SVG element (relative to its parent container, say a div).

I tried using dynamic CSS on the SVG element, but this has quirky behavior in Chrome where the rendered SVG element doesn't update until something happens on the page like a resize or another element updating.

Here's a JSBin dynamic CSS example that demonstrates the issue. When the program prints "blue rect should appear" one second after the page loads, the blue SVG element should appear with its new (x, y, width, height). However, in the latest Chrome (Version 33.0.1750.152, on a Mac), the blue rectangle does not appear unless you resize the browser. The blue rectangle does appear correctly in Firefox, I'm only seeing this issue in Chrome and Safari.

Oddly, the problem does not occur when you have JSBin's "Output" tab showing, and the blue rectangle appears if you hover over JSBin's split pane border to the left of the rendered page. Here's a JSFiddle version, just to show it's not a JSBin quirk. Here's a version where the position and size is initialized, then changed - here also the change does not update the display.

Does anyone else see the same behavior, where the blue rectangle does not appear when it should? Any tips on how to implement programmatic SVG positioning and sizing in another way? Might this be a bug in WebKit? Thank you very much.

Best regards,
Curran

audebert christian

unread,
Mar 27, 2014, 4:17:06 AM3/27/14
to d3...@googlegroups.com

Problem, i tried, but, the second svg is in html parts, but  invisible. 

I made simple exemple working, with 1 svg in the div and adding rect..

http://jsfiddle.net/eomer/4NznA/

 

this exemple show how to add data and manage delayed update..

 

make one svg by div… I think it’s the key..  wrong.?

 

De : d3...@googlegroups.com [mailto:d3...@googlegroups.com] De la part de Curran
Envoyé : jeudi 27 mars 2014 05:08
À : d3...@googlegroups.com
Objet : How to position and size an SVG programmatically? (dynamic CSS not working)

--
You received this message because you are subscribed to the Google Groups "d3-js" group.
To unsubscribe from this group and stop receiving emails from it, send an email to d3-js+un...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

christian audebert

unread,
Mar 27, 2014, 4:45:08 AM3/27/14
to d3...@googlegroups.com
try this fiddle.

simple delayed

and with opacity transition..

mindrones

unread,
Mar 27, 2014, 6:51:03 AM3/27/14
to d3...@googlegroups.com
Hi,


On 27 March 2014 05:07, Curran <curran....@gmail.com> wrote:

Does anyone else see the same behavior, where the blue rectangle does not appear when it should?

confirmed.

 
Any tips on how to implement programmatic SVG positioning and sizing in another way?

IMO this is working as it should, infact in Chrome you see attributes and styles changing in the DOM, which is correct: it just doesn't force a repaint.

If you give the svg the same attributes and styles without using setTimeout, the svg renders correctly (positions, colors).

 
Might this be a bug in WebKit?

Yes to me this seems to be a bug in Blink/WebKit.

The only hack that seems to work is changing the value of position after the timeout, but this works because the two have the same appearance, it's still a bug IMO:

#container{
  position: absolute;  // <---- start with another position value
  top:    15px;
  bottom: 15px;
  left:   15px;
  right:  15px;
  background-color: red;
}

window.onload = function() {
    var container = d3.select('#container');
    var svg = container
                .append('svg')
                .style('position', 'absolute');
    setTimeout(function (){
        console.log("blue rect should appear");
        container.style('position', 'fixed');  // <---- give it the position value
        svg
            .style('left', '50px')
            .style('top', '50px')
            .style('stroke-width', '0px')
            .style('background-color', 'blue')
            .attr('width', 20)
            .attr('height', 20)
           
        }, 1000);
}


Regards,
Luca



mindrones

unread,
Mar 27, 2014, 6:53:46 AM3/27/14
to d3...@googlegroups.com
Hi,

On 27 March 2014 11:51, mindrones <mind...@gmail.com> wrote:

            .style('stroke-width', '0px')


oops! :), this is not needed, sorry for the noise.


Regards,
Luca

mindrones

unread,
Mar 27, 2014, 7:11:11 AM3/27/14
to d3...@googlegroups.com
Hi,

On 27 March 2014 11:51, mindrones <mind...@gmail.com> wrote:

The only hack that seems to work is changing the value of position after the timeout, but this works because the two have the same appearance, it's still a bug IMO:

another solution seems to be:
- leaving the container position as 'fixed'
- in the setTimeout callback, modify the container z-index:
container.style('z-index', 1);

This also forces a repaint.

Regards,
Luca


Curran

unread,
Mar 27, 2014, 1:38:22 PM3/27/14
to d3...@googlegroups.com
Hello,

Thank you so much for your responses, they have been very helpful.

Luca, thank you for confirming the buggy behavior and suggesting several workarounds.

Christian, your fiddles helped by showing that manipulating inner elements within the SVG (such as 'g' and 'rect') triggers repainting in Chrome.

To get the desired behavior, I changed my code to use a rect within the SVG. Here's a working fiddle using a rect within the SVG, where repainting is triggered properly in Chrome.

Thanks again for your help, I really appreciate D3's vibrant community!

Best regards,
Curran
Reply all
Reply to author
Forward
0 new messages