Possible to Build an Svg That Has Fluid Horizontal Scaling, Similar to Old Table-Slice Method

Possible to build an svg that has fluid horizontal scaling, similar to old table-slice method?

I'm answering this because I had to do the something similar.

Yes, you can do it with just SVG. The key attributes are viewBox and preserveAspectRatio. preserveAspectRatio="xMaxYMid" keeps the rectangle to the right and xMinYMid keeps the rectangle to the left. Set the viewBox to be the desired size of the rectangles on the end.

This has been tested in Chrome, Firefox, and IE.

Here is a plunker demo.

Note that if the change the height of the svg to 100% instead of 20px you can make the image scale with a containing html div.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<svg width="100%" height="20px" version="1.0" state='normal'
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">

<defs>

<!-- The right head -->
<svg class='head input-source' id='right'
height="100%"
width='100%'
viewBox="0 0 15 30"
preserveAspectRatio="xMaxYMid"
>
<rect width="100%" height="100%"/>
</svg>

<!-- The left head -->
<svg class='head input-source' id='left'
height="100%"
width='100%'
viewBox="0 0 15 30"
preserveAspectRatio="xMinYMid"
>
<rect width="100%" height="100%"/>
</svg>

</defs>

<svg
class='input-source'
stroke='black'
stroke-width='0'
fill="green">
<rect x="2" y="20%" width="100%" height="60%"
stroke='black'
stroke-width='0'
>
</rect>
<use xlink:href='#right'/>
<use xlink:href='#left'/>
</svg>
</svg>

Is there a way to apply 9-patch / scale-9 principles in SVG?

I wrote about it on my blog, it's possible in a "perfect" way when you are willing to sacrifice IE and an "almost" way that works in IE as well as long as you can live with a not so perfect solution: http://w3.eleqtriq.com/2014/03/the-holy-grail-of-image-scaling/

responsive dc.js chart is taking over the whole window

Thanks for posting an example! The bug doesn't show up in the SO code snippet feature unless you go to full page mode. I found your fiddle easier to work with.

Note: this is a complete rewrite of my previous answer, which was not clear.

1. Using ResizeObserver

updated 4/28/20

As of Safari 13.1 (released March 24 2020) all modern browsers support ResizeObserver. This is the cleanest way to detect chart resizing.

I recommend

  1. Use a top-down layout such as flexbox or grid to position the divs for your charts
  2. Use ResizeObserver to determine when the div has changed size
  3. Tell the charts to detect the chart div size using .width(null).height(null)

There is currently one resizing example that does this.

The special value null tells the chart to make the SVG node the same size as its parent div:

chart1.width(null)
.height(null)

The callback uses a helper function to disable transitions, because transitions just slow resizing down and make it look clunky:

const callback = chart => entries => {
redraw_chart_no_transitions(
chart
.width(null)
.height(null)
.rescale());
};

Setting up the observer looks like

new ResizeObserver(callback(chart1)).observe(d3.select('#test1').node());

Please see the example for more details.

2. Using window.onresize

The other resizing examples watch for window.onresize because until recently that was the only efficient, reliable cross-browser way to detect changes.

They calculate chart sizes based on the window size, which works well if your layout is bottom-up, e.g. using the default float: left layout.

Here is the function which sets this up:

function apply_resizing(chart, adjustX, adjustY, onresize) {
if(!Array.isArray(chart))
chart = [chart];
if(!isNaN(adjustX))
adjustX = (dx => x => x-dx)(adjustX);
adjustX = adjustX || (x => x);
if(!isNaN(adjustY))
adjustY = (dy => y => y-dy)(adjustY);
adjustY = adjustY || adjustX || (y => y);
chart.forEach(c => c.width(adjustX(window.innerWidth))
.height(adjustY(window.innerHeight)));
window.onresize = function () {
if (onresize) {
chart.forEach(onresize);
}
chart.forEach(c => {
c.width(adjustX(window.innerWidth))
.height(adjustY(window.innerHeight));
if (c.rescale) {
c.rescale();
}
});
redraw_chart_no_transitions(chart);
};
}

A single chart can be initialized like so:

apply_resizing(chart, 20);

This fills the window but makes the chart 20 pixels less wide.

The function can also take multiple charts in an array, and adjustment functions to support complicated layouts, like one where two charts should split the window vertically:

apply_resizing([heatmapChart, barChart], 20, y => y/2-fudge);

In D3 bar graph, y-axis ordinal scale is not aligning properly with bars

Problem 1:

Instead of this:

  var _barThickness = 20;

Do this:

  var _barThickness = scales.y.rangeBand();

Read here

If you want to regulate the thickness

Instead of this:

y: d3.scale.ordinal().rangeRoundBands([0, height], .1)

Do this:

y: d3.scale.ordinal().rangeRoundBands([0, height], .7)

Problem 2:

Incorrect transform.

Instead of this:

var rect = bar.enter()
.append('g')
.attr('transform', function(d, i) {
return 'translate(0,' + parseInt(i * _barThickness + 2) + ')';
});

Do this:

var rect = bar.enter()
.append('g');

Problem 3:

Incorrect calculation of y for the bars.

  .attr('y', function(d, i) {
return (i * _barThickness);
})

Do this:

  .attr('y', function(d, i) {
return scales.y(d.label);
})

working code here



Related Topics



Leave a reply



Submit