D3.js canvas context fill wrong

独自空忆成欢 提交于 2019-12-03 18:13:42

问题


I make a map with D3, it's my code

d3.json('https://unpkg.com/world-atlas@1/world/110m.json', (error, topology) => {
        if (error) throw error;
        let width = map.offsetWidth,
            height = map.offsetHeight;

        let projection = d3.geoMercator().scale('200').translate([width / 2, height / 1.4]);

        let canvas = d3.select('.map').append('canvas')
            .attr('width', width)
            .attr('height', height);

        let context = canvas.node().getContext('2d'),
            path = d3.geoPath()
                .context(context)
                .projection(projection);

        context.fillStyle = '#d8d8d8';
        context.strokeStyle = 'black';

        context.beginPath();
        path(topojson.mesh(topology));
        context.fill();
        context.stroke()
    });

and get wrong canvas

There are some white but should be gray. I have no idea what happened, if use svg it works perfectly, but in this case, I want to use canvas. Thanks.


回答1:


This happens because you aren't actually drawing the countries. You are drawing the mesh around the countries - and this means that your features aren't countries, but border (and coast) segments.

Normally when drawing countries, each feature is a whole country, and filling the path fills the feature, as you want. Each border between two countries is thus drawn twice. Topojson encodes topology, which breaks the countries shapes into line segments so that each segment is recorded once. The topojson mesh just produces these line segments. Filling a line essentially creates a polygon by linking the first point with the last point. In your map this is quite visible with the coasts of the continental US.

Try converting the topojson to geojson:

topojson.feature(topology, topology.objects.features)

As in the snippet below (using your code):

d3.json('https://unpkg.com/world-atlas@1/world/110m.json', (error, topology) => {
        if (error) throw error;
        let width = 960,
            height = 500;

        let projection = d3.geoMercator().scale('200').translate([width / 2, height / 1.4]);

        let canvas = d3.select('body').append('canvas')
            .attr('width', width)
            .attr('height', height);

        let context = canvas.node().getContext('2d'),
            path = d3.geoPath()
                .context(context)
                .projection(projection);

        context.fillStyle = '#d8d8d8';
        context.strokeStyle = 'black';

        context.beginPath();
        path(topojson.feature(topology, topology.objects.countries));
        context.fill();
        context.stroke()
    });
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
<script src="https://d3js.org/topojson.v2.min.js"></script>


来源:https://stackoverflow.com/questions/45726130/d3-js-canvas-context-fill-wrong

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