2013-06-29 2 views
2

Я изучаю, как работает Clojurescript, пытаясь нарисовать некоторые сетки из структуры JSON, используя d3.js. Я использую strokes для доступа к d3.Работа с мутацией в Clojurescript

JSON выглядит следующим образом:

[[{"players":{"0":{"rep":0},"1":{"rep":0}}},{"players":{"0":{"rep":0},"1":{"rep":0}}}, 
    {"players":{"0":{"rep":0},"1":{"rep":0}}},{"players":{"0":{"rep":0},"1":{"rep":0}}}], 
[{"players":{"0":{"rep":0},"1":{"rep":0}}},{"players":{"0":{"rep":0},"1":{"rep":0}}}, 
    {"players":{"0":{"rep":0},"1":{"rep":0}}},{"players":{"0":{"rep":0},"1":{"rep":0}}}], 
[{"players":{"0":{"rep":0},"1":{"rep":0}}},{"players":{"0":{"rep":0},"1":{"rep":0}}}, 
    {"players":{"0":{"rep":0},"1":{"rep":0}}},{"players":{"0":{"rep":0},"1":{"rep":0}}}], 
[{"players":{"0":{"rep":0},"1":{"rep":0}}},{"players":{"0":{"rep":0},"1":{"rep":0}}}, 
    {"players":{"0":{"rep":0},"1":{"rep":0}}},{"players":{"0":{"rep":0},"1":{"rep":0}}}]] 

Он представляет собой 4 по 4 сетки. Я пытаюсь добавить значения в ячейки, такие как координаты высоты, ширины, х и у, так что тогда это просто простой случай передачи данных в d3 для рисования.

Например, это будет выглядеть примерно так:

[[{"width":32,"height":32,"x":0,"y":0,"value":{"players":{"0":{"rep":0},"1":{"rep":0}}}}, 
    {"width":32,"height":32,"x":32,"y":0,"value":{"players":{"0":{"rep":0},"1":{"rep":0}}}},... 

Обычно я сопоставить по структуре с функцией преобразования для преобразования клеток из их текущей стоимости в новую форму, однако этот подход просто Безразлично Кажется, что он работает. Я пробовал map-indexed: (map-indexed #(doto %2 (aset "width" %1)) row), но это, похоже, неправильно преобразует значения. Вполне вероятно, что я получаю доступ или неправильно задаю значения.

текущей итерации кода выглядит следующим образом:

(defn board->grid [grid-width grid-height board square] 
    (let [x-length (count board) 
     y-length (count (first board)) 
     same (min (/ grid-width x-length) (/ grid-height y-length)) 
     grid-item-width (if square same (/ grid-width x-length)) 
     grid-item-height (if square same (/ grid-height y-length)) 
     start-x (/ grid-item-width 2) 
     start-y (/ grid-item-height 2) 
     values (array) 
     grid (array) 
     data (js->clj board :keywordize-keys true)] 
     (doseq [x (range x-length) 
       y (range y-length)] 
      (let [current-cell (aget data y x)] 
      (.log js/console (apply str (aset (aget data y x) "a" "b"))) 
      (.push grid (aget data y x)))) 
     (.text ($ :#status) grid))) 

Любая помощь будет оценен по достоинству! Или еще лучше, предложения о лучших подходах, я не могу не почувствовать, что я немного ошибаюсь!

ответ

5

Основное правило для работы с изменчивостью в clojure и clojurescript - «не делать». Массивы и объекты JS не реализуют большинство протоколов, на которые функции полагаются, чтобы выполнять свою работу. Например, простые js-массивы не могут быть выделены! Выполняйте большую часть своей работы с неизменяемыми структурами данных и конвертируйте в изменяемые эквиваленты только тогда, когда вам нужно взаимодействовать с другими библиотеками.

Есть некоторые дополнительные функции, которые являются массивом конкретным: into-array, to-array, aget, aset, amap, areduce и alength. (Смотрите эту cheat sheet.)

Есть также много closure library функции могут оказаться полезными в goog.array, goog.object или goog.structs если вы хотите придерживаться изменяемых структур данных. (Помните, clojurescript включает библиотеку закрытия google!)

Вы также можете использовать эту форму повсюду:

(defn amap2d [arr f] 
    (doseq [x (range (alength arr)) 
      y (range (alength (aget A x))) 
     :let [cell (aget A y x)]] 
    (f x y cell))) 

Но я думаю, что вы будете счастливы делать js->clj, работая над данными, а затем clj->js непосредственно перед передать его на d3.

+0

Спасибо! Я сделаю то, что вы предлагаете, он чувствует себя наиболее естественным! – toofarsideways

+0

Изучите возможности 'strokes' немного больше. Похоже, что он использует библиотеку ['mrhyde'] (https://github.com/dribnet/mrhyde), которая позволяет использовать структуры данных clj более легко с помощью кода javascript. Возможно, вам даже не понадобится последний шаг 'js-> clj'! –

+0

Я действительно отскакивал между «штрихами» и «c2», и в настоящее время я преимущественно использую 'c2', так как он обеспечивает очень приятную функциональность с помощью' bind! '... – toofarsideways

1

Я не знаком с clojurescript; некоторые предложения, хотя:

Форматирование массива массивов в плоский массив объектов с координатами не слишком трудно с ванильным JavaScript:

var grid = []; 
board.forEach(function(row, y){ 
    row.forEach(function(d, x){ 
    d.y = y; d.x = x; grid.push(d); }); }); 

Чтобы отобразить доску, вы, вероятно, захотите использовать что-то вроде этого :

svg.selectAll("rect") 
    .data(grid).enter().append("svg:rect") 
    .attr("x", function(d){ return xScale(d.x); }) 
    .attr("y", function(d){ return yScale(d.y); }) 
    .attr("height", rectHeight) 
    .attr("width", rectWidth) 

Обратите внимание, что фактическое положение квадрата не хранится в объекте, то легче следить, что с масштабом:

xScale = d3.scale.linear() 
    .domain(d3.extent(grid.map(function(d){ return d.x; }). 
    .range(0, svgWidth); 
4

Я вижу, что вы используете aget на data и что data - это структура данных ClojureScript. aget предназначен только для работы с объектами типа Array.

+0

Благодарим вас за указание:) ... BTW Дэвид, любите свою работу! – toofarsideways

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