2016-06-07 4 views
2

Я работаю над рендерингом модели с использованием SVG. Я постараюсь предоставить более четкий пример, чем то, над чем я работаю. Скажем, структура данных представляет собой объект JSON следующим образом:Как разместить объект по отношению к другому

vehicle = { 
    "axles": [ 
     { 
      "id": 0, 
      "wheels": [ 
       { 
        "id": 0, 
        "diameter": 18 
       }, 
       { 
        "id": 1, 
        "diameter": 18 
       } 
      ] 
     }, 
     { 
      "id": 1, 
      "wheels": [ 
       { 
        "id": 0, 
        "diameter": 18 
       }, 
       { 
        "id": 1, 
        "diameter": 18 
       } 
      ] 
     } 
    ] 
} 

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

(я проигнорирует большинство свойств стайлинг/размер)

var svg = d3.select("body").append("svg"); 
svg.append("rect").attr("class", "car") // Only 1 car object 
svg.selectAll(".car).data(vehicle.axles, function(d){return d.id}) // Render each axle 
    .append("rect") 

Я хочу, чтобы затем «нарисовать колеса» по отношению к положению оси, но применяя данные() до конца Приложение append помещает внутри элемента оси, не отображая его - мне нужно, чтобы элемент колеса находился в родительском элементе вместе с осью, но мне нужно прочитать дочерние данные оси в структуре данных.

Надеюсь, это имело какой-то смысл и что кто-то может помочь.

ответ

3

Вы не можете поместить прямоугольник внутри прямоугольника, но вы можете поместить группу g внутри другой группы. Имеет смысл сделать «автомобиль» группой, которая содержит группу для каждой «оси», каждая из которых содержит пару «колес» (которые могут быть также rects или группы).

Вместо цепочки все ваши выражения, вы можете также назначить выбор переменной и использовать его, или selectAll элементы по их селектора (если данные, которые вы связывания не зависит от предыдущего контекста.) Вы также можете использовать each() и повторить код для каждого элемента в выборе с помощью d3.select(this), чтобы обратиться к родительскому элементу.

Вот пример. Вы можете добавить в «автомобиль» в качестве группы (и вы можете иметь любое количество элементов в нем, в том числе rect):

svg.append("g").attr("class", "car") // this group is the car 
    .append("rect") // a rect inside the car group 
    ... 

Затем вы предварительно выбрать «ось» объекты, которые вы собираетесь создать внутри группа «автомобиль»:

svg.select(".car") // selects the group car (where we will append axles) 
    .selectAll(".axle") // pre-select all axles 
    .data(vehicle.axles) // bind the data 
    .enter() 
    .append("g").attr("class", "axle") // will append new axle for each data item 
     .each(function(d,i) { // now repeat for each axle 
      d3.select(this) // selects the current axle 
      .selectAll(".wheel") // pre-select the wheels you are going to create 
      .data(d.wheels) // bind the data 
      .enter() 
      .append("g").attr("class", "wheel") // append a wheel for the current axle 
      .append("rect") // the rect representing the wheel 
      ... 
     }) 
     .append("rect") // the rect representing the axle 

Попробуйте использовать это JSFiddle. Я заменил rects на text и немного изменил данные JSON, чтобы проиллюстрировать решение.

+0

Отлично! Моя единственная проблема в том, что псевдо-класс hover применяется ко всем предкам элемента при наведении на элемент. Если у меня есть '.car: hover, .axle: hover, .wheel: hover {stroke: blue}', зависание только элемента колеса будет применять псевдо-класс hover к каждому его предку, то есть. ось и автомобиль. Я даже пытался передвинуть элемент колеса от других элементов, так что ничего не перекрывается, и оно все еще происходит. –

+0

EDIT: Я исправил это, ха. Я забыл, что классы стали классами для групп, а не прямым. Изменены селектор стиля на '.car rect: hover, .axle rect: hover, .wheel rect: hover {stroke: blue}' Еще раз спасибо за отличный ответ! –

+1

Вы также можете отключить события на элементе с помощью CSS «pointer-events: none». Это полезно, когда вы укладываете слои и можете игнорировать события на нем (типичным примером являются текстовые метки). – helderdarocha

Смежные вопросы