Подтвердить что ты не робот

Вычислить Centro SVG Path с помощью D3.js

Я использую SVG, расположенный в http://upload.wikimedia.org/wikipedia/commons/3/32/Blank_US_Map.svg в проекте и взаимодействуя с ним с помощью d3.js. Я бы хотел создать эффект масштабирования, например http://bl.ocks.org/2206590, однако этот пример основан на данных о пути, хранящихся в объекте JSON, для вычисления центроида. Есть ли способ загрузить данные пути в d3 из существующего SVG, чтобы получить центроид?

Моя (хакерская) попытка:

  function get_centroid(sel){
    var coords = d3.select(sel).attr('d');
    coords = coords.replace(/ *[LC] */g,'],[').replace(/ *M */g,'[[[').replace(/ *z */g,']]]').replace(/ /g,'],[');
    return d3.geo.path().centroid({
      "type":"Feature",
      "geometry":{"type":"Polygon","coordinates":JSON.parse(coords)}
    });
  }

Это, похоже, работает в некоторых штатах, таких как Миссури, но другие, подобные Вашингтону, терпят неудачу, потому что мой синтаксический анализ SVG является настолько рудиментарным. Поддерживает ли d3 что-то вроде этого?

4b9b3361

Ответ 1

Все функции D3, похоже, предполагают, что вы начинаете с GeoJSON. Тем не менее, я на самом деле не думаю, что вам нужен центроид для этого - вам действительно нужна ограничивающая рамка, и, к счастью, это доступно непосредственно из интерфейса SVG DOM:

function getBoundingBoxCenter (selection) {
  // get the DOM element from a D3 selection
  // you could also use "this" inside .each()
  var element = selection.node();
  // use the native SVG interface to get the bounding box
  var bbox = element.getBBox();
  // return the center of the bounding box
  return [bbox.x + bbox.width/2, bbox.y + bbox.height/2];
}

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

Ответ 2

Принятый ответ работал отлично для меня, пока я не проверил в Edge. Я не могу комментировать, так как у меня недостаточно кармы или чего-то еще, но использовал это решение и нашел проблему с Microsoft Edge, которая не использует x или y, просто верх/левый/нижний/правый и т.д.

Таким образом, приведенный выше код должен быть:

function getBoundingBoxCenter (selection) {
  // get the DOM element from a D3 selection
  // you could also use "this" inside .each()
  var element = selection.node();
  // use the native SVG interface to get the bounding box
  var bbox = element.getBBox();
  // return the center of the bounding box
  return [bbox.left + bbox.width/2, bbox.top + bbox.height/2];
}