2

我正在通过尝试使用 d3.js 从 JSON 结构中绘制一些网格来了解 Clojurescript 的工作原理。我正在使用笔画来访问 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 x 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)))

任何帮助,将不胜感激!或者更好的是,更好的方法的建议,我不禁觉得我做的有点不对!

4

3 回答 3

5

在 clojure 和 clojurescript 中处理可变性的基本经验法则是“不要”。JS 数组和对象并没有实现函数所依赖的大多数协议来完成它们的工作。例如,普通的 js 数组是不可排序的!使用不可变数据结构完成大部分工作,并仅在需要与其他库交互时转换为可变等价物。

还有一些特定于数组的附加函数:into-arrayto-arrayagetasetamap和。(请参阅此备忘单。)areducealength

还有许多闭包库函数,您可能会在 , 中找到有用的goog.arraygoog.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 之前。

于 2013-06-30T15:30:23.673 回答
4

我看到您正在使用ageton data,这data是一个 ClojureScript 数据结构。aget仅设计用于类似数组的 JavaScript 对象。

于 2013-07-01T13:14:03.400 回答
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);
于 2013-06-30T02:11:33.837 回答