У меня есть некоторые данные geoJson, которые я рисую с помощью d3.geo.
Когда я пишу что-то вроде
d3.select("svg")
...
.attr("d", function(d) {
return path({
type:"MultiPoint",
coordinates: get_activity_coords_(d.activities)
});
})
Я всегда получаю круг для каждой координаты. Координаты представляют собой расположение различных остановочных пунктов пути. Я бы предпочел другую форму для первой и последней координаты.
Можно ли сделать это с помощью MultiPoint, есть ли пример, которому я могу следовать? Я мог рисовать точки одну за другой, но я помню, что читал, что MultiPoint намного быстрее. Кроме того, код будет намного понятнее для чтения.
Большое спасибо.
Ответ 1 · рейтинг 3 · AmeliaBR
Вы не можете создавать разные формы для 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