В d3.geo MultiPoint, как я могу предоставить разные формы для разных точек?
У меня есть некоторые данные geoJson, которые я строю на графике, используя d3.geo.
Когда я пишу что-то вроде
d3.select("svg")
...
.attr("d", function(d) {
return path({
type:"MultiPoint",
coordinates: get_activity_coords_(d.activities)
});
})
Я всегда получаю круг для каждой координаты. Координаты представляют местоположения различных точек остановки путешествия. То, что я бы предпочел, это разные формы для первой и последней координаты.
Можно ли сделать это с помощью MultiPoint, есть ли пример, которому я могу следовать? Я мог бы рисовать точки одну за другой, но я помню, что читал, что MultiPoint намного быстрее. Кроме того, код будет намного понятнее для чтения.
Большое спасибо.
1 ответ
Вы не можете делать различные формы для MultiPoint GeoJSON с d3.geo.path
, Вы можете изменить радиус в зависимости от функции, но похоже, что вы можете установить его только для объекта, а не для точки, поэтому вам придется разбить набор точек на несколько объектов и потерять любое преимущество в производительности при использовании одного элемента.,
Однако есть и другие способы сделать это.
Один из вариантов, как вы упомянули, заключается в создании вложенного выделения с отдельным <path>
элемент для каждой точки, и нарисуйте каждый путь, используя d3.svg.symbol()
функция. Затем вы можете настроить функцию символа на основе данных или индекса.
var trips = d3.select("svg").selectAll("g.trips")
.data(/*The data you were currently using for each path,
now gets to a group of paths */)
.attr("class", "trips");
//also set any other properties for the each trip as a whole
var pointSymbol = d3.svg.symbol().type(function(d,i){
if (i === 0)
//this is the first point within its groups
return "cross";
if ( this === this.parentNode.querySelector("path:last-of-type") )
//this is the last point within its group
return "square";
//else:
return "circle";
});
var points = trips.selectAll("path")
.data(function(d) {
return get_activity_coords_(d.activities);
//return the array of point objects
})
.attr("transform", function(d){
/* calculate the position of the point using
your projection function directly */
})
.attr("d", pointSymbol);
Другой вариант, который позволяет вам устанавливать пользовательские фигуры для первой и последней точки (но все промежуточные точки будут одинаковыми) - это соединять точки как вершины одной невидимой <path>
элемент и использовать линейные маркеры для рисования точечных символов.
Ваш подход будет следующим:
Создать
<defs>
элемент в вашем SVG (жестко или динамически с d3), и определить начальную, среднюю и конечную точки маркера в них. (Ты можешь использоватьd3.svg.symbol()
функции, чтобы нарисовать пути, или сделать свой собственный, или использовать изображения, это ваше дело.)Использовать
d3.svg.line()
функция для создания атрибута пути "d" на основе вашего массива координат точек; функции доступа x и y для линии должны использовать функцию проекции, которую вы используете для карты, чтобы получить положение x/y из координат этой точки. Чтобы избежать расчета проекции дважды, вы можете сохранить проекционные координаты в объекте данных:var multipointLine = d3.svg.line() .x(function(d,i) { d.projectedCoords = projection(d); return d.projectedCoords[0]; }) .y(function(d){ return d.projectedCoords[1];});
(Вы не можете использовать свой
d3.geo.path()
функция для рисования линий в качестве элемента карты, потому что она разбивает линию на кривые, чтобы соответствовать кривым линий долготы и широты в вашей проекции карты; чтобы заставить работать линейные маркеры, путь должен представлять собой простое прямолинейное соединение между точками.)Установите стиль на этом пути без обводки и заливки, чтобы сама линия не отображалась, но затем установите
marker-start
,marker-mid
а такжеmarker-end
свойства в строке для ссылки на значения идентификатора правильного элемента маркера.
Для начала, вот пример использования d3 для динамического создания линейных маркеров:
Можно ли использовать d3.svg.symbol вместе с svg.marker