Неправильная заливка контекста холста D3.js

Я делаю карту с D3, это мой код

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()
    });

и получите неверный холст  введите описание изображения здесь

Есть белые, но они должны быть серыми. Я понятия не имею, что произошло, если использовать svg, он отлично работает, но в этом случае я хочу использовать холст. Спасибо.


person PaulHuang    schedule 17.08.2017    source источник


Ответы (1)


Это происходит потому, что вы на самом деле не рисуете страны. Вы рисуете сетку вокруг стран - и это означает, что ваши объекты - это не страны, а граничные (и прибрежные) сегменты.

Обычно при рисовании стран каждый объект представляет собой целую страну, а заполнение пути заполняет объект по своему усмотрению. Таким образом, каждая граница между двумя странами проводится дважды. Topojson кодирует топологию, которая разбивает фигуры стран на линейные сегменты, так что каждый сегмент записывается один раз. Сетка topojson просто создает эти линейные сегменты. Заполнение линии по существу создает многоугольник, связывая первую точку с последней точкой. На вашей карте это хорошо видно на побережье континентальной части США.

Попробуйте преобразовать topojson в geojson:

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

Как в приведенном ниже фрагменте (с использованием вашего кода):

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>

person Andrew Reid    schedule 17.08.2017