我正在尝试使用d3.js从JSON结构中绘制一些网格来学习Clojurescript的工作原理。我正在使用strokes访问d3。
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的网格。我正在尝试向单元格添加值,例如高度,宽度,x和y坐标,这样就可以将数据传递给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)))
任何帮助将不胜感激!或者更好的是,更好的方法的建议,我不禁觉得我正在做这个有点错误!
答案 0 :(得分: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包含谷歌闭包库!)
您也可以在任何地方使用此表单:
(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
,处理数据,然后在将其传递给d3之前clj->js
。
答案 1 :(得分:4)
我发现您在aget
上使用data
,而data
是ClojureScript数据结构。 aget
仅用于处理类似Array的JavaScript对象。
答案 2 :(得分:1)
我不熟悉clojurescript;但有些建议:
使用vanilla 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);