В 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> элемент и использовать линейные маркеры для рисования точечных символов.

Ваш подход будет следующим:

  1. Создать <defs> элемент в вашем SVG (жестко или динамически с d3), и определить начальную, среднюю и конечную точки маркера в них. (Ты можешь использовать d3.svg.symbol() функции, чтобы нарисовать пути, или сделать свой собственный, или использовать изображения, это ваше дело.)

  2. Использовать 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() функция для рисования линий в качестве элемента карты, потому что она разбивает линию на кривые, чтобы соответствовать кривым линий долготы и широты в вашей проекции карты; чтобы заставить работать линейные маркеры, путь должен представлять собой простое прямолинейное соединение между точками.)

  3. Установите стиль на этом пути без обводки и заливки, чтобы сама линия не отображалась, но затем установите marker-start, marker-mid а также marker-end свойства в строке для ссылки на значения идентификатора правильного элемента маркера.

Для начала, вот пример использования d3 для динамического создания линейных маркеров:
Можно ли использовать d3.svg.symbol вместе с svg.marker

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