I have a project where I am using D3 js to create a few charts. I am trying to make these charts responsive when the window size changes. To do this I already used viewbox to define the svg:
var svg = d3
.select(this.$refs["chart"])
.classed("svg-container", true)
.append("svg")
.attr("class", "chart")
.attr(
"viewBox",
`0 0 ${width + margin.left + margin.right} ${height +
margin.top +
margin.bottom}`
)
.attr("preserveAspectRatio", "xMinYMin meet")
.classed("svg-content-responsive", true)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
I also use to set the width and height the same as the div where the SVG is inside. So that this chart uses the same size as the div it is inside:
width = this.$refs["chart"].clientWidth - margin.left - margin.right,
height = this.$refs["chart"].clientHeight - margin.top - margin.bottom;
The width and height of this div is set to 100% of it's parent div. So when I am resizing the window the div where the svg is in can change size and aspect ratio. So this is what the chart looks initially when the page is loaded. So it's getting its height and width from the div it is in:
But when i resize the chart shrinks to still fit inside the new width of the parent div. But the height changes with it. So I assume that the aspect ratio stays the same:
I have tried to update the svg viewport when the window resizes. But the vieuwport isn't being updated when I inspect the SVG element in DOM of the developer tools in Chrome. I have added console logs to check if the width and height of the parent also change and they seem to change. But the updated viewport doesn't gets applied to the svg:
d3.select(window).on("resize", () => {
svg.attr(
"viewBox",
`0 0 ${this.$refs["chart"].clientWidth} ${this.$refs["chart"].clientHeight}`
);
});
<!DOCTYPE html>
<html>
<head>
<title></title>
<script src="https://unpkg.com/vue"></script>
<script src="https://d3js.org/d3.v6.js"></script>
<style>
.area {
fill: url(#area-gradient);
stroke-width: 0px;
}
body{
width: 100%;
height: 100%;
}
.app{
width: 100%;
height: 100%;
}
#page{
width: 100%;
height: 100%;
}
.my_dataviz{
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div id="app">
<div class="page">
<div id="my_dataviz" ref="chart"></div>
</div>
</div>
<script>
new Vue({
el: '#app',
data: {
type: Array,
required: true,
},
mounted() {
const minScale = 0,
maxScale = 35;
var data = [{
key: 'One',
value: 33,
},
{
key: 'Two',
value: 30,
},
{
key: 'Three',
value: 37,
},
{
key: 'Four',
value: 28,
},
{
key: 'Five',
value: 25,
},
{
key: 'Six',
value: 15,
},
];
console.log(this.$refs["chart"].clientHeight)
// set the dimensions and margins of the graph
var margin = {
top: 20,
right: 0,
bottom: 30,
left: 40
},
width =
this.$refs["chart"].clientWidth - margin.left - margin.right,
height =
this.$refs["chart"].clientHeight - margin.top - margin.bottom;
// set the ranges
var x = d3.scaleBand().range([0, width]).padding(0.3);
var y = d3.scaleLinear().range([height, 0]);
// append the svg object to the body of the page
// append a 'group' element to 'svg'
// moves the 'group' element to the top left margin
var svg = d3
.select(this.$refs['chart'])
.classed('svg-container', true)
.append('svg')
.attr('class', 'chart')
.attr(
'viewBox',
`0 0 ${width + margin.left + margin.right} ${
height + margin.top + margin.bottom
}`
)
.attr('preserveAspectRatio', 'xMinYMin meet')
.classed('svg-content-responsive', true)
.append('g')
.attr(
'transform',
'translate(' + margin.left + ',' + margin.top + ')'
);
// format the data
data.forEach(function(d) {
d.value = +d.value;
});
// Scale the range of the data in the domains
x.domain(
data.map(function(d) {
return d.key;
})
);
y.domain([minScale, maxScale]);
//Add horizontal lines
let oneFourth = (maxScale - minScale) / 4;
svg
.append('svg:line')
.attr('x1', 0)
.attr('x2', width)
.attr('y1', y(oneFourth))
.attr('y2', y(oneFourth))
.style('stroke', 'gray');
svg
.append('svg:line')
.attr('x1', 0)
.attr('x2', width)
.attr('y1', y(oneFourth * 2))
.attr('y2', y(oneFourth * 2))
.style('stroke', 'gray');
svg
.append('svg:line')
.attr('x1', 0)
.attr('x2', width)
.attr('y1', y(oneFourth * 3))
.attr('y2', y(oneFourth * 3))
.style('stroke', 'gray');
//Defenining the tooltip div
let tooltip = d3
.select('body')
.append('div')
.attr('class', 'tooltip')
.style('position', 'absolute')
.style('top', 0)
.style('left', 0)
.style('opacity', 0);
// append the rectangles for the bar chart
svg
.selectAll('.bar')
.data(data)
.enter()
.append('rect')
.attr('class', 'bar')
.attr('x', function(d) {
return x(d.key);
})
.attr('width', x.bandwidth())
.attr('y', function(d) {
return y(d.value);
})
.attr('height', function(d) {
console.log(height, y(d.value))
return height - y(d.value);
})
.attr('fill', '#206BF3')
.attr('rx', 5)
.attr('ry', 5)
.on('mouseover', (e, i) => {
d3.select(e.currentTarget).style('fill', 'white');
tooltip.transition().duration(500).style('opacity', 0.9);
tooltip
.html(
`<div><h1>${i.key} ${
this.year
}</h1><p>${converter.addPointsToEveryThousand(
i.value
)} kWh</p></div>`
)
.style('left', e.pageX + 'px')
.style('top', e.pageY - 28 + 'px');
})
.on('mouseout', (e) => {
d3.select(e.currentTarget).style('fill', '#206BF3');
tooltip.transition().duration(500).style('opacity', 0);
});
// Add the X Axis and styling it
let xAxis = svg
.append('g')
.attr('transform', 'translate(0,' + height + ')')
.call(d3.axisBottom(x));
xAxis
.select('.domain')
.attr('stroke', 'gray')
.attr('stroke-width', '3px');
xAxis.selectAll('.tick text').attr('color', 'gray');
xAxis.selectAll('.tick line').attr('stroke', 'gray');
// add the y Axis and styling it also only show 0 and max tick
let yAxis = svg.append('g').call(
d3
.axisLeft(y)
.tickValues([this.minScale, this.maxScale])
.tickFormat((d) => {
if (d > 1000) {
d = Math.round(d / 1000);
d = d + 'K';
}
return d;
})
);
yAxis
.select('.domain')
.attr('stroke', 'gray')
.attr('stroke-width', '3px');
yAxis.selectAll('.tick text').attr('color', 'gray');
yAxis.selectAll('.tick line').attr('stroke', 'gray');
d3.select(window).on('resize', () => {
svg.attr(
'viewBox',
`0 0 ${this.$refs['chart'].clientWidth} ${this.$refs['chart'].clientHeight}`
);
});
},
});
</script>
</body>
</html>
from D3 change SVG dimensions on resize window
No comments:
Post a Comment