Невозможно заставить метки работать с проекцией плитки D3

1

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

Я создал jsfiddle, где я создаю карты, а затем пытаюсь спроецировать их так, чтобы они перемещались с пользовательским взаимодействием.

Бит кода, который этого не достигает, находится здесь:

  d3.selectAll(".country_labels")   
    .attr("transform", function(d) {return "translate(" + path.centroid(d) + ")"})  

ОБНОВИТЬ

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

Я добился определенного прогресса и собрал эту новую скрипку. Этикетки теперь все на карте, но плавающие вокруг залива Гвинея, рядом с геокоординатами [0,0]. Для меня это означает, что они, возможно, были спроектированы правильно, но что зум не работает должным образом. Проблема здесь в том, что в этом скрипте есть три отдельных типа координат:

  1. Геокоординаты - это исходная точка и всегда фиксированная
  2. Координаты 'd3-tile'. Те, которые вписываются в один пиксель и поэтому всегда очень близки к нулю
  3. Координаты пикселей - они соответствуют фактическим координатам на экране
Теги:
d3.js

1 ответ

1
Лучший ответ

Это похоже на ваш другой вопрос, просто он находится на передней проекции и масштабировании, а не на инвертирует. (Я начал писать это перед обновлением, но должен был работать, я продолжу свой исходный код).

Как и в случае с дорожками, вы добавляете свои ярлыки, как ожидалось:

country_labels.selectAll("text")
  .data(collection.features)
  .enter().append("text")
  .attr("x", function(d){return path.centroid(d)[0];})
  .attr("y", function(d){return path.centroid(d)[1];})
  .attr("dx", -40)
  .text(function(d){ return d.properties.name })
  .style("fill", "#aeaeaf") 
  .style("font-size", "15px")

Здесь есть одна проблема, поскольку проекция большинства примеров d3-tile, включая ваши, использует масштаб d3-проекции 1/tau, мир проецируется в пределах 1 пикселя, поэтому значение dx равно 40 мирам, это не будет работать при применении масштабирования, поэтому отпустите эту часть

Теперь вы добавляете функции более или менее точно так же, как и пути, но проблема заключается в управлении масштабированием:

d3.selectAll(".country_labels") 
  .attr("transform", function(d) {return "translate(" + path.centroid(d) + ")"})    

Пути получают аналогичное лечение:

vector
    .attr("transform", "translate(" + [transform.x, transform.y] + ")scale(" + transform.k + ")")
    .style("stroke-width", 1 / transform.k); 

Но здесь есть несколько отличий:

  1. вы применяете другое преобразование (масштаб и перевод) к путям по сравнению с текстом: для текста нет ссылки на текущее преобразование масштабирования, вместо этого вы используете только проекцию, которая привязана к 0,0 со всеми функции, лежащие в области одного пикселя (и привязанные к 0,0 будут иметь базовую линию при y = 0, текст будет в значительной степени не учитываться). Если вы проверите svg, вы увидите текст, который находится не в том месте.

  2. Пути имеют уменьшенную ширину штриха, так как один масштабируется (поскольку мы увеличиваем масштаб svg, сама ширина хода увеличивается), то же самое применимо и к тексту, поэтому, даже если текст был правильно позиционирован, он был бы очень большим (больше чем на любом экране с браузером).

Один из способов, которым мы можем это решить, - применить масштабное преобразование к координатам x/y текста, а не самому элементу (который также будет масштабировать размер текста, так что нам вообще не нужно изменять размер текста):

country_labels.selectAll("text").attr("x", function (d) {return transform.apply(path.centroid(d)) [0];}).attr("y", function (d) { return transform.apply(path.centroid(d)) 1 ;})

Как и при инверсии из пикселя svg в lat/long, мы проходим те же движения, но в обратном порядке: применяем проекцию, а затем применяем масштабирование.

Здесь обновленная скрипка.


Тем не менее, у меня плохие новости - ярлыки расположены точно там, где вы говорите, что они теперь расположены. Но они не там, где вы хотите, чтобы они были (как говорится, самое лучшее в программировании - это то, что код делает именно то, что вы ему рассказываете, самое плохое в программировании - то, что код делает именно то, что вы ему рассказываете?),

Вы используете дорожные центроиды для размещения меток, иногда это работает для некоторых функций, но это не работает все время. Возьмем Соединенные Штаты, например, центроид США, использующий проекцию Меркатора, находится не в Соединенных Штатах, потому что он находится между Аляской и нижними 48 государствами (извините, Гавайи, у вас здесь не так много тягот). Центроид Канады частично находится в Северном Ледовитом океане, и во многих наборах данных (не удивительно) Франция помечена в середине Атлантики из-за Французской Гвианы, когда используется центроиды в качестве текстового якоря.

Вы можете немного улучшить визуальный внешний вид, используя .style("text-anchor","middle"), который по крайней мере центрирует метки, где они (очень полезны для стран с меньшим или эквивалентным уровнем), но в конечном итоге центроидное размещение не является идеальным.

Я просто закончу: Аннотации - проклятие картографии.

Но есть надежда, вот одно из наиболее перспективных фьючерсов, которые я видел.

  • 0
    Андрей - твой ответ идеален, еще раз. Я уверен, что говорю не только за себя, когда говорю, что вы действительно проливаете кучу света на плитки D3. Быстрый вопрос - как вы могли бы изменить свою скрипку, чтобы пересчитать все размещения меток после завершения переходов (масштабирование к границе или панорамирование / масштабирование пользователя)? В зависимости от браузера, я нахожу, что ярлыки действительно снижают производительность и заставляют анимацию дрожать.
  • 0
    Спасибо также за ваше обсуждение размещения центроидов - я нашел это действительно полезным, и я также восхищался ссылкой, которой вы поделились.
Показать ещё 5 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню