Глобус D3 со слоем меток названий стран

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

https://observablehq.com/@michael-keith/draggable-globe-in-d3

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

Я добавил ручку на случай, если так будет проще: <https://codepen.io/alhuber1502/pen/YzbGPMB>

Большое спасибо!

Вот предыдущий аналогичный вопрос. Хотя он использует более старую версию D3. На глобусе вы можете проверить угловое расстояние от текущего вращения, чтобы увидеть, должна ли отображаться метка. К тексту не будет применена проекция, поэтому он не будет менять перспективу при вращении. Кроме того, позиционирование центроида является проблематичным, например, США: Аляска действительно перемещает центроид, или Франция: Французская Гвиана перемещает метку в Атлантику. Аннотация к карте — это боль.
Andrew Reid 23.05.2024 17:20

По сути, решение по-прежнему svg.selectAll(null).data(features).enter().append("text").at‌​tr("d", path.centroid)... Затем вам нужно применить преобразование масштабирования/поворот проекции так же, как вы делаете для остальной части земного шара.

Andrew Reid 23.05.2024 17:26

Спасибо, Андрей! Я добавил ручку на случай, если вам будет проще указать: codepen.io/alhuber1502/pen/YzbGPMB Я просмотрел как связанный вопрос, на который вы ссылались, так и предложенное вами решение, но у меня возникли проблемы с получением меток. показывать. Я задавался вопросом, можно ли использовать тот же механизм, что и для меток добавляются мировые границы, будет ли это работать? Спасибо!

Alexander Huber 24.05.2024 15:04

@AndrewReid У меня есть метки для показа codepen.io/alhuber1502/pen/YzbGPMB, к сожалению, они не вращаются, не масштабируются и не проецируются должным образом. Я на правильном пути? Любая помощь принимается с благодарностью!

Alexander Huber 25.05.2024 12:30

В завершение вы обновляете контуры страны с помощью svg.selectAll("path").attr("d", path); даже при перетаскивании, но не текст, вам нужно применить ту же логику, которую вы используете для первоначального размещения меток при перетаскивании. Я мог бы взглянуть повнимательнее сегодня вечером

Andrew Reid 30.05.2024 17:38
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
5
94
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Чтобы разместить текст на глобусе, вы используете метод пути path.centroid. Это возвращает центр пути (как нарисовано, а не географически). Это можно использовать для размещения текста следующим образом:

let text = svg.selectAll(null)
                  .data(data)
                  .enter()
                  .append("text")
                  .attr("transform", function(d) { return "translate("+path.centroid(d)+")"});

Однако это не работает для объектов, у которых нет видимого пути (т. е. объектов на дальней стороне Земли, которые не визуализируются). Для этого нам нужно сделать проверку, иначе текст появится по адресу [0,0]:

       .style("opacity", function(d) {
         if (path(d)) return 1; else return 0;
       })

Это проверяет, созданы ли какие-либо данные пути генератором пути, если нет, мы скрываем текст. Если данные пути не созданы, объект не виден и не должен быть помечен.

Мы обновляем их при каждом событии ротации:

  text.attr("transform", function(d) { return "translate("+path.centroid(d)+")"})
      .style("opacity", function(d) {
         if (path(d)) return 1; else return 0;
       })

Нам не нужно обновлять стиль при каждом масштабировании, поскольку мы не вращаем Землю (и, следовательно, не скрываем/открываем новые пути).

Я взял ваш пример (обновил его до версии 7 для d3.json) и применил вышеуказанные изменения.

d3.json("https://static.observableusercontent.com/files/cbb0b433d100be8f4c48e19de6f0702d83c76df3def6897d7a4ccdb48d2f5f039bc3ae1141dd1005c253ca13c506f5824ae294f4549e5af914d0e3cb467bd8b0?response-content-disposition=attachment%3Bfilename*%3DUTF-8%27%27world.json").then(function(data) {
  
    let width = 500;
    let height = 500;
    const sensitivity = 75;

    let projection = d3
      .geoOrthographic()
      .scale(250)
      .center([0, 0])
      .rotate([0, -30])
      .translate([width / 2, height / 2]);

    const initialScale = projection.scale();
    let path = d3.geoPath().projection(projection);

    let svg = d3
      .select("svg")
      .attr("width", width)
      .attr("height", height);

    let globe = svg
      .append("circle")
      .attr("fill", "#EEE")
      .attr("stroke", "#000")
      .attr("stroke-width", "0.2")
      .attr("cx", width / 2)
      .attr("cy", height / 2)
      .attr("r", initialScale);

 

    let map = svg.append("g");

    map
      .append("g")
      .attr("class", "countries")
      .selectAll("path")
      .data(data.features)
      .enter()
      .append("path")
      .attr("class", (d) => "country_" + d.properties.name.replace(" ", "_"))
      .attr("d", path)
      .attr("fill", "white")
      .style("stroke", "black")
      .style("stroke-width", 0.3)
      .style("opacity", 0.8);
    
   let text = map
      .append("g")
      .selectAll("text")
      .data(data.features)
      .enter()
      .append("text")
      .attr("transform", function(d) { return "translate(" +  path.centroid(d) + ")"; })
      .text(function(d) { return d.properties.name; })
      .style("opacity", function(d) {
        if (path(d)) return 1; else return 0;
      })
   
 
   svg
      .call(
        d3.drag().on("drag", () => {
          const rotate = projection.rotate();
          const k = sensitivity / projection.scale();
          projection.rotate([
            rotate[0] + d3.event.dx * k,
            rotate[1] - d3.event.dy * k
          ]);
          path = d3.geoPath().projection(projection);
          svg.selectAll("path").attr("d", path);
          text.attr("transform", function(d) { return "translate(" + path.centroid(d) + ")"; })
            .style("opacity", function(d) {
             if (path(d)) return 1; else return 0;
           })
        })
      )
      .call(
        d3.zoom().on("zoom", () => {
          if (d3.event.transform.k > 0.3) {
            projection.scale(initialScale * d3.event.transform.k);
            path = d3.geoPath().projection(projection);
            svg.selectAll("path").attr("d", path);
            globe.attr("r", projection.scale());
            text.attr("transform", function(d) { return "translate(" + path.centroid(d) + ")"; })
          } else {
            d3.event.transform.k = 0.3;
          }
        })
      );   


    function placeText(d, projection, text) {
        d3.select(this)
          .attr("opacity", path(d) == NULL ? 1 : 0)
          .attr("transform",  "translate(" + path.centroid(d) + ")");
    }

})
<script src = "https://cdnjs.cloudflare.com/ajax/libs/d3/5.9.0/d3.min.js"></script>
<svg></svg>

Другие вопросы по теме