в 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 намного быстрее. Кроме того, код будет намного понятнее для чтения.

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


person Dinesh    schedule 20.03.2014    source источник
comment
Похоже, вам нужно изменить координаты, переданные функции path.   -  person Lars Kotthoff    schedule 20.03.2014


Ответы (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

person AmeliaBR    schedule 20.03.2014
comment
большое спасибо. Мой пользователь привязан к изогнутым разъемам еще и потому, что они показывают прибл. путь путешествия. Но было здорово узнать о линейных маркерах и повозиться с ними!! - person Dinesh; 20.03.2014