dc.js responsive map and zoom function (mousewheel)

≯℡__Kan透↙ 提交于 2021-02-10 18:35:29

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!