问题
I have forked the example dc.js (version 4) map file is this JsFiddle. What I want is for the map to be responsive to the Bootstrap container. So, if the screen size changes the map is displayed correctly. The SVG is responsive by setting the width and height to null and a CSS format to set the width and height to 100%. However I see that the underlying <g>
(layer0) element is not responsive. Therefore I tried to add a scale element to the projection. But unfortunately I don't know how to make it flexible like I did with the SVG element.
In addition, I would like to have the possibility to zoom in. Hopefully someone can help me with this.
<div class="container">
<div class="row">
<div class="col">
<div id="world-map" class="responsive"></div>
</div>
</div>
</div>
<pre id="data">country total
Belgium 2
Germany 3
France 4
</pre>
function world(data) {
var xf = crossfilter(data);
var country = xf.dimension(function(d) {
return d.country;
});
var countryGroup = country.group().reduceSum(d => +d.total);
var worldMap = new dc.GeoChoroplethChart("#world-map");
d3.json("https://raw.githubusercontent.com/johan/world.geo.json/master/countries.geo.json").then(function(worldJson) {
worldMap
.width(null)
.height(null)
.dimension(country)
.group(countryGroup)
.colors(d3.scaleQuantize().range(["#E2F2FF", "#C4E4FF", "#9ED2FF", "#81C5FF", "#6BBAFF", "#51AEFF", "#36A2FF", "#1E96FF", "#0089FF", "#0061B5"]))
.colorDomain([0, 200])
.colorCalculator(function(d) {
return d ? worldMap.colors()(d) : '#ccc';
})
.overlayGeoJson(worldJson.features, "state", function(d) {
return d.properties.name;
})
.projection(d3.geoEquirectangular()
.scale(100)
.translate([800 / 2, 400 / 2])
)
.valueAccessor(function(kv) {
//console.log(kv);
return kv.value;
})
.title(function(d) {
return d.key + "\nTotal: " + (d.value ? d.value : 0);
});
dc.renderAll();
});
}
const data = d3.tsvParse(d3.select('pre#data').text());
world(data);
.row {
background: #f8f9fa;
margin-top: 20px;
}
.col {
border: solid 1px #6c757d;
padding: 10px;
}
pre#data {
display: none;
}
.responsive {
width: 100%;
height: 100%;
}
回答1:
It's really easy to connect d3-zoom to change the transform of a parent <g>
in response to zoom events.
First, pull out the projection initialization because we'll need the initial values later:
const scale0 = 100, x0 = 800 / 2, y0 = 400 / 2,
projection = d3.geoEquirectangular()
.scale(scale0)
.translate([x0, y0])
worldMap
.projection(projection)
Then add the zoom handlers after the chart renders:
worldMap.on('postRender', chart => {
const zoom = d3.zoom();
zoom.on('zoom', () => {
const {k, x, y} = d3.event.transform;
chart.select('g.layer0')
.attr('transform', `translate(${x},${y}) scale(${k})`)
})
chart.svg().call(zoom);
});
Each time we receive a zoom event, we'll pull the scale, x and y offset from the event, and apply them to a transform that looks like
translate(-350.6778787924404,-173.42665430196223) scale(1.9132163161837539)
On my first try, I applied a new projection and redrew the chart. This worked but it had performance problems. Changing the transform is the way to go!
Fork of your fiddle, with pan and zoom.
来源:https://stackoverflow.com/questions/60920890/dc-js-responsive-map-and-zoom-function-mousewheel