Добавление карт как части группы (несколько карт) - PullRequest
1 голос
/ 27 июня 2019

Я пытаюсь создать разделенную рамку d3 визуала карты мира с некоторыми другими точками данных по регионам. По сути, предполагается, что карта мира повторяется несколько раз по вертикали вниз страницы, при этом каждая карта выделяет отдельный континент. Вот мой код:

var margins = {top:20, bottom:300, left:30, right:100};

var height = 600;
var width = 900;

var totalWidth = width+margins.left+margins.right;
var totalHeight = height+margins.top+margins.bottom;
var projection = d3.geoMercator().rotate([-10,0]).scale(50).translate([160,100]);

var path = d3.geoPath().projection(projection);

var svg = d3.select("body")
    .append('svg')
    .attr('width', 310)
    .attr('height', 150);

var topoData = d3.json("world-continents.json");

topoData.then(function(data) {

var continents = topojson.feature(data, data.objects.continent).features;

var map = svg.append('g').attr('class', 'boundary');
var continent = map.selectAll('.continent').data(continents);
console.log(continents)
var color = d3.scaleLinear()
   .range(["#4f81d7","#f6d18b"])
   .domain([3000000,105000000]);

var data = [
  {'continent':'Asia', 't1fg':19, 't2fg':24, 't1fc':758, 't2fc':773},
  {'continent':'Europe', 't1fg':6, 't2fg':37, 't1fc':234, 't2fc':241},
  {'continent':'North America', 't1fg':20, 't2fg':60, 't1fc':102, 't2fc':102},
  {'continent':'South America', 't1fg':-2, 't2fg':22, 't1fc':1, 't2fc':1},
  {'continent':'Other', 't1fg':3, 't2fg':4, 't1fc':5, 't2fc':5},
];

var continentG = svg.selectAll('.cont')
    .data(data)
    .attr('class','cont')
    .enter()
    .append('g');

continentG.data(continents).append('path')
.attr('class', 'continent')
.attr('d', path)
.style('stroke', "#a6a6a6")
.style('fill', function(d) {
  if (d.properties.continent=="South America") {
    return "#003366";
  } else {
    return "none";
  }
});


})

Проблема в том, что я не могу понять, как я могу повторить карту, как обычно, используя такой подход:

svg.selectAll('.cont')
    .data(data)
    .attr('class','cont')
    .enter()
    .append('g');

, чтобы связать несколько объектов SVG с данными (например, поместить текст в прямоугольник или прямоугольник в круг, т. Д.). Потому что я должен перезаписать переменную data данными топойсона, необходимыми для рисования карты. Я думал, что у меня может быть два вызова данных, но это не сработало. Как вы можете заметить из моего кода выше, рисуется только одна карта.

Вопрос

Могу ли я как-то сохранить геометрию топойсона, чтобы я мог добавить ее к g для использования с картами с разделением кадра? Здесь контекст для каждой карты выделен другим континентом (синим цветом).

1 Ответ

2 голосов
/ 27 июня 2019

Вот решение, добавляющее несколько SVG.Преимущество этого подхода заключается в том, что вы можете заключить каждый SVG в div, который вы можете легко распределить по вертикали (например, используя flex).Здесь для краткости я просто использую display: block;.

. У вас есть два варианта ввода: SVG-ввод использует вашу переменную data:

var svg = d3.select("body").selectAll(null)
    .data(data)
    .enter()
    .append('svg')
    .attr('width', 300)
    .attr('height', 150)

Затем внутри каждогоSVG, выбор пути ввода использует загруженные данные topoJson (здесь переименованный mapData):

var map = svg.selectAll(null)
    .data(continents)
    .enter()
    .append('path')
    .attr('class', 'continent')
    .attr('d', path)

Единственная сложная часть - получение данных от родителя.Это можно сделать с помощью each, локальной переменной или, в этом решении, с помощью this.parentNode:

map.style('fill', function(d) {
    var thisContinent = d3.select(this.parentNode).datum().continent;
    if (d.properties.continent === thisContinent) {
        return "#003366";
    } else {
        return "none";
    }
});

Вот демо *:

svg {
  border: 1px solid gray;
  margin-bottom: 6px;
}
<!DOCTYPE html>

<head>
  <meta charset="utf-8">
  <script src="https://d3js.org/d3.v5.min.js"></script>
  <script src="https://d3js.org/topojson.v2.min.js"></script>
</head>

<body>
  <script>
    var projection = d3.geoMercator().rotate([-10, 0]).scale(50).translate([160, 100]);
    var path = d3.geoPath().projection(projection);
    var data = [{
        'continent': 'Asia',
        't1fg': 19,
        't2fg': 24,
        't1fc': 758,
        't2fc': 773
      },
      {
        'continent': 'Europe',
        't1fg': 6,
        't2fg': 37,
        't1fc': 234,
        't2fc': 241
      },
      {
        'continent': 'North America',
        't1fg': 20,
        't2fg': 60,
        't1fc': 102,
        't2fc': 102
      },
      {
        'continent': 'South America',
        't1fg': -2,
        't2fg': 22,
        't1fc': 1,
        't2fc': 1
      },
      {
        'continent': 'Other',
        't1fg': 3,
        't2fg': 4,
        't1fc': 5,
        't2fc': 5
      },
    ];

    var topoData = d3.json("https://piwodlaiwo.github.io/topojson//world-continents.json");

    topoData.then(function(mapData) {

      var svg = d3.select("body").selectAll(null)
        .data(data)
        .enter()
        .append('svg')
        .attr('width', 300)
        .attr('height', 150)
        .style("display", "block")

      var continents = topojson.feature(mapData, mapData.objects.continent).features;

      var map = svg.selectAll(null)
        .data(continents)
        .enter()
        .append('path')
        .attr('class', 'continent')
        .attr('d', path)
        .style('stroke', "#a6a6a6")
        .style('fill', function(d) {
          var thisContinent = d3.select(this.parentNode).datum().continent;
          if (d.properties.continent === thisContinent) {
            return "#003366";
          } else {
            return "none";
          }
        });
    })
  </script>
</body>

* с использованием topoJson я нашел здесь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...