首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >模块设计模式在简单D3“覆盖”程序中的应用

模块设计模式在简单D3“覆盖”程序中的应用
EN

Code Review用户
提问于 2016-05-26 08:25:28
回答 1查看 579关注 0票数 5

我一直在学习JS (主要是使用D3),我想将应用于其中。我编写了一个简单的脚本,允许您用更容易读的代码构建条形图。

最终用户代码:

代码语言:javascript
复制
canvas.initialise()
canvas.margin(20, 100, 60, 20)
canvas.width(500)
canvas.height(400)
canvas.finalise()
svg = canvas.get_canvas()

my_data = [["A", 10], ["B", -3], ["C", 4]]

bar_chart.data(my_data)
bar_chart.x_scale([0, canvas.get_width()], .1, 1)
bar_chart.y_scale([canvas.get_height(), 0])
bar_chart.formatting(".2f")
bar_chart.add_to(svg)

使用MDP:

的库代码

代码语言:javascript
复制
var canvas = (function ()
{
    // private
    var svg;
    var margin, width, height, x_pos, y_pos;

    var initialise = function () { svg = d3.select("body").append("svg") }
    var set_position = function (x, y) { x_pos = x; y_pos = y;}
    var set_margins = function (top, bottom, left, right) { margin = { top: top, bottom: bottom, left: left, right: right }; }
    var set_width = function (val) { width = val - margin.left - margin.right; svg.attr("width", val + margin.left + margin.right); }
    var set_height = function (val) { height = val - margin.top - margin.bottom; svg.attr("height", val + margin.top + margin.bottom); }
    var finalise = function ()
    {
        svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")")
                       .attr("x", x_pos)
                       .attr("y", y_pos)
    }



    return {
        initialise: initialise,
        position: set_position,
        margin: set_margins,
        width: set_width,
        height: set_height,
        finalise: finalise,
        get_canvas: function () { return svg },
        get_margin: function () { return margin },
        get_width: function () { return width },
        get_height: function () { return height }
    }
}());

var bar_chart = (function ()
{
    var data,
        x, y,
        xAxis, yAxis,
        formatting;

    var set_data = function(data_input)
    {
        data = data_input;
    }

    var set_x_scale = function (interval, padding, outer_padding)
    {
        x = d3.scale.ordinal()
          .rangeRoundBands(interval, padding, outer_padding)
    }

    var set_y_scale = function (interval)
    {
        y = d3.scale.linear()
                  .range(interval)
    }

    var set_formatting = function (fmt)
    {
        formatting = d3.format(fmt);
    }

    var add_to = function(svg)
    {
        console.log(data)

        xAxis = d3.svg.axis()
                  .scale(x) // call ticks?

        yAxis = d3.svg.axis()
                  .scale(y)
                  .orient("left")
                  .tickFormat(formatting)

        x.domain(data.map(function (d) { return d[0] }))
        y.domain([-5, 15]) //make general

        // Put the axes on the canvas
        svg.append("g")
           .attr("class", "x axis")
           .attr("transform", "translate(" + canvas.get_margin().left + "," + canvas.get_height() + ")")
           .call(xAxis)

        svg.append("g")
            .attr("class", "y axis")
            .attr("transform", "translate(" + canvas.get_margin().left + ",0)")
            .call(yAxis)

        // Put the data in rectangle elements and put on canvas
        var bars = svg.selectAll(".bar")
                       .data(data)
                       .enter()
                       .append("rect")
                       .attr("class", "bar")
                       .attr("width", x.rangeBand())
                       .attr("x", function (d) { return x(d[0]) + canvas.get_margin().left })  // hmm...
                       .attr("y", function (d)
                       {
                           if (d[1] < 0)
                           {
                               return y(0);
                           }
                           else
                               return y(d[1])
                       })
                       .attr("height", function (d) { return y(0) - y(Math.abs(d[1])) });


    }

    return {
        data: set_data,
        formatting: set_formatting,
        x_scale: set_x_scale,
        y_scale: set_y_scale,
        add_to: add_to
    }

}());

我所关切的是:

  • 我认为,必须在其他函数之前调用一些函数,这意味着我的结构已经关闭(有时不可避免,但对此的评论将是有用的)。
  • 这是设计模式的适当使用吗?
  • 通过不同的使用模式可以提高可用性吗?
  • 在这种情况下,另一种模式更适合吗?
EN

回答 1

Code Review用户

回答已采纳

发布于 2016-06-02 11:13:13

你在你的关注列表中提出了一些非常好的观点,特别是你的第一个问题及其背后的原因:

您的模块有太多的依赖项

模块背后的想法是创建自包含的、单一用途的代码。canvas模块取决于用户调用函数的顺序。您的bar_chart特别需要,因为它的addTo方法要求直接访问canvas模块。好的模块简单明了。他们将一些复杂的任务封装在一个黑匣子里,让用户不知道引擎盖下面发生了什么。这使得用户可以专注于使用模块,而不是担心可能的副作用。

建议的可用性重构,它也消除了功能顺序依赖,

下面是用户更友好的制作条形图的方法:

代码语言:javascript
复制
var canvas = createCanvas({
  margins: {
    top: 20,
    left: 60,
    right: 20,
    bottom: 100
  },
  width: 420, // 500 - 60 - 20, maybe the 500 totalWidth is more intuitive
  height: 280 // 400 - 20 - 100
});

drawBarChart({
  canvas: canvas,
  data: [["A", 10], ["B", -3], ["C", 4]],
  range: [-5, 15],
  numberFormat: ".2f", // optional parameter
  barInnerPadding: 0.1, // optional parameter
  barOuterPadding: 1 // optional parameter
});

这为开发人员提供了一个用于创建图表的CSS-esque界面。不必担心按错误的顺序调用函数,所有属性都是命名的,这使您可以轻松地使任何属性都是可选的。

下面是我对提供上述用户界面的代码所做的一个重构的JSFiddle

我重新分析了一些事情以及原因:

  1. 我将“画布”划分为一个数据对象和一个createSVG函数,因为我觉得画布做了两件事:存储格式化数据和构建/格式化/存储svg。(而且,与OOP相比,我更喜欢函数式编程范式)
  2. 我将您的bar_chart模块浓缩为单个drawBarChart函数,因为将所有逻辑拆分以创建图表会增加必须按特定顺序调用函数的依赖性。(不过,我认为在我的drawBarChart中应该有一些内联函数。强调内联;如果我们没有重复的代码,而且函数没有在其他地方调用,那么使函数只在其他地方取代代码,而不是实际执行它的地方)
  3. 我做了很多参数的可选,并赋予用户指定y轴范围的能力。可选的参数通常是更加友好的用户。如果用户想要学习如何为drawBarChart函数做特定的格式化工作,那么他们可以,但如果他们不想这样做,那么他们就不必担心它。

无用代码

xycanvas中的位置不为您的程序提供任何功能。考虑把它们移走。(如果你最终想在以后添加它们,那么你可以在以后添加它们,目前它们只是分散注意力)。

风格公约

只要你的风格不妨碍你的可读性,就去做吧。我提出这个问题的唯一原因是因为您的一些代码行变得非常非常长。例如:

代码语言:javascript
复制
var set_height = function (val) { height = val - margin.top - margin.bottom; svg.attr("height", val + margin.top + margin.bottom); }

这个函数可以在多行上更容易读懂。

我对你的d3印象深刻!前一段时间我学到了一些东西,但没有充分的理由坚持下去。保持良好的工作状态!

票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/129351

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档