链接D3.js插件中的函数

时间:2017-07-23 15:02:12

标签: javascript d3.js

我为D3.js写了一个名为d3-marcon的插件,它实现了Mike Bostock's margin conventions。例如,而不是必须写:

var margin = {top: 10, bottom: 10, left: 10, right: 10},
    width = window.innerWidth - margin.left - margin.right,
    height = window.innerHeight - margin.top - margin.bottom,
    svg = d3.select("body").append("svg")
            .attr("width", width + margin.left + margin.right)
            .attr("height", height + margin.top + margin.bottom)
        .append("g")
            .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

你可以写:

var setup = d3.marcon({top: 10, bottom: 10, left: 10, right: 10, width: window.innerWidth, height: window.innerHeight}),
    margin = setup.margin,
    width = setup.width,
    height = setup.height,
    svg = setup.svg;

如您所见,它通过将选项对象传递给marcon()函数来工作。如果您未指定任何选项,则默认为0表示所有页边距,900表示宽度,600表示高度,并将svg元素附加到"body"。因此,您只需使用一行代码var setup = d3.marcon()即可快速启动并运行,然后在您想要更改时即可传递选项。

这很有用,但它仍然不像真正的D3功能。真正的D3函数允许将函数链接在一起,而不是传递选项对象。因此,D3代码不是d3.marcon({element: ".viz"}),而是d3.marcon().element(".viz")

D3代码还允许您将其他功能传递给链接函数(例如d3.method().chainedFunction(function(d) { return d.value; })),以便您可以根据数据更新对象的属性。

显然,我的插件没有做这些事情。我花了几个小时看现有的D3模块,试图找出它们是如何工作的,但我没有到达任何地方。任何人都可以建议如何使我的代码像适当的D3模块一样工作?或者,如果没有,那么阅读一个很好的教程?

我链接到上面的存储库,但是here it is again。并here is a block展示了它是如何运作的。

2 个答案:

答案 0 :(得分:3)

这是我的建议,基于Nick Zhu在他的书“数据可视化与D3 4.x ”中的方法。

基本上,我们用对象创建一个函数......

function marcon() {
    var instance = {};
}

...并分别设置每个方法:

instance.top = function(d) {
    if (!arguments.length) return top;
    top = d;
    return instance;
};

最后,您使用render()调用渲染部分:

marcon().top(10)
    .left(10)
    //etc...
    .render();

这种方法的好处在于,正如您所要求的那样,它允许链接。例如,您可以像这样创建SVG:

var mySvg = marcon();

mySvg.top(20)
    .left(10)
    .right(10)
    .bottom(10)
    .height(200)
    .width(200)
    .element("body")
    .render();

这是一个演示:



function marcon() {
  var instance = {};
  var top = 10,
    bottom = 0,
    left = 0,
    right = 0,
    width = 900,
    height = 600,
    element = "body",
    innerWidth, innerHeight, svg;

  instance.top = function(d) {
    if (!arguments.length) return top;
    top = d;
    return instance;
  };

  instance.left = function(d) {
    if (!arguments.length) return left;
    left = d;
    return instance;
  };

  instance.right = function(d) {
    if (!arguments.length) return right;
    right = d;
    return instance;
  };

  instance.bottom = function(d) {
    if (!arguments.length) return bottom;
    bottom = d;
    return instance;
  };

  instance.width = function(d) {
    if (!arguments.length) return width;
    width = d;
    return instance;
  };

  instance.height = function(d) {
    if (!arguments.length) return height;
    height = d;
    return instance;
  };

  instance.element = function(d) {
    if (!arguments.length) return element;
    element = d;
    return instance;
  };

  instance.innerWidth = function() {
    return innerWidth;
  };

  instance.innerHeight = function() {
    return innerHeight;
  };

  instance.svg = function() {
    return svg;
  };

  instance.render = function() {
    innerWidth = width - left - right;
    innerHeight = height - top - bottom;
    svg = d3.select(element)
      .append("svg")
      .attr("width", innerWidth + left + right)
      .attr("height", innerHeight + top + bottom)
      .append("g")
      .attr("transform", "translate(" + left + ", " + top + ")");
  }

  return instance;
}

var mySvg = marcon();
mySvg.top(20)
  .left(10)
  .right(10)
  .bottom(20)
  .height(200)
  .width(200)
  .element(".testDiv")
  .render();

var rect = mySvg.svg()
  .append("rect")
  .attr("width", mySvg.innerWidth())
  .attr("height", mySvg.innerHeight())
  .style("fill", "teal")

svg {
  background-color: tan;
}

<script src="https://d3js.org/d3.v4.min.js"></script>
<div class="testDiv"></div>
&#13;
&#13;
&#13;

此外,它允许默认值。如果您未设置setter,则默认为指定值。在这里,如果我们不设置宽度,则默认为900:

&#13;
&#13;
function marcon() {
  var instance = {};
  var top = 10,
    bottom = 0,
    left = 0,
    right = 0,
    width = 900,
    height = 600,
    element = "body",
    innerWidth, innerHeight, svg;

  instance.top = function(d) {
    if (!arguments.length) return top;
    top = d;
    return instance;
  };

  instance.left = function(d) {
    if (!arguments.length) return left;
    left = d;
    return instance;
  };

  instance.right = function(d) {
    if (!arguments.length) return right;
    right = d;
    return instance;
  };

  instance.bottom = function(d) {
    if (!arguments.length) return bottom;
    bottom = d;
    return instance;
  };

  instance.width = function(d) {
    if (!arguments.length) return width;
    width = d;
    return instance;
  };

  instance.height = function(d) {
    if (!arguments.length) return height;
    height = d;
    return instance;
  };

  instance.element = function(d) {
    if (!arguments.length) return element;
    element = d;
    return instance;
  };

  instance.innerWidth = function() {
    return innerWidth;
  };

  instance.innerHeight = function() {
    return innerHeight;
  };

  instance.svg = function() {
    return svg;
  };

  instance.render = function() {
    innerWidth = width - left - right;
    innerHeight = height - top - bottom;
    svg = d3.select(element)
      .append("svg")
      .attr("width", innerWidth + left + right)
      .attr("height", innerHeight + top + bottom)
      .append("g")
      .attr("transform", "translate(" + left + ", " + top + ")");
  }

  return instance;
}

var mySvg = marcon();
mySvg.top(20)
  .left(10)
  .right(10)
  .bottom(20)
  .height(200)
  .element("body")
  .render();

var rect = mySvg.svg()
  .append("rect")
  .attr("width", mySvg.innerWidth())
  .attr("height", mySvg.innerHeight())
  .style("fill", "teal")
&#13;
svg {
  background-color: tan;
}
&#13;
<script src="https://d3js.org/d3.v4.min.js"></script>
<div class="testDiv"></div>
&#13;
&#13;
&#13;

最后,您可以使用getters,例如:

marcon().top();

它为您提供了价值。这是一个演示,看一下控制台:

&#13;
&#13;
function marcon() {
  var instance = {};
  var top = 10,
    bottom = 0,
    left = 0,
    right = 0,
    width = 900,
    height = 600,
    element = "body",
    innerWidth, innerHeight, svg;

  instance.top = function(d) {
    if (!arguments.length) return top;
    top = d;
    return instance;
  };

  instance.left = function(d) {
    if (!arguments.length) return left;
    left = d;
    return instance;
  };

  instance.right = function(d) {
    if (!arguments.length) return right;
    right = d;
    return instance;
  };

  instance.bottom = function(d) {
    if (!arguments.length) return bottom;
    bottom = d;
    return instance;
  };

  instance.width = function(d) {
    if (!arguments.length) return width;
    width = d;
    return instance;
  };

  instance.height = function(d) {
    if (!arguments.length) return height;
    height = d;
    return instance;
  };

  instance.element = function(d) {
    if (!arguments.length) return element;
    element = d;
    return instance;
  };

  instance.innerWidth = function() {
    return innerWidth;
  };

  instance.innerHeight = function() {
    return innerHeight;
  };

  instance.svg = function() {
    return svg;
  };

  instance.render = function() {
    innerWidth = width - left - right;
    innerHeight = height - top - bottom;
    svg = d3.select(element)
      .append("svg")
      .attr("width", innerWidth + left + right)
      .attr("height", innerHeight + top + bottom)
      .append("g")
      .attr("transform", "translate(" + left + ", " + top + ")");
  }

  return instance;
}

var mySvg = marcon();
mySvg.top(20)
  .left(10)
  .right(10)
  .bottom(20)
  .height(200)
  .width(200)
  .element("body")
  .render();

var rect = mySvg.svg()
  .append("rect")
  .attr("width", mySvg.innerWidth())
  .attr("height", mySvg.innerHeight())
  .style("fill", "teal");
  
console.log("The height is " + mySvg.height())
&#13;
svg {
  background-color: tan;
}
&#13;
<script src="https://d3js.org/d3.v4.min.js"></script>
<div class="testDiv"></div>
&#13;
&#13;
&#13;

答案 1 :(得分:2)

有几种不同的方式来完成你所追求的目标。首先,您应该使用d3阅读有关可重用性的优秀tutorial。将这些想法与您的代码结合起来会是这样的:

<!DOCTYPE html>
<html>

<head>
  <script data-require="d3@4.0.0" data-semver="4.0.0" src="https://d3js.org/d3.v4.min.js"></script>
</head>

<body>
  <script>
    function marcon() {
      
      var top = 0,
      	bottom = 0,
      	left = 0,
      	right = 0,
      	width = 900,
      	height = 600,
      	svg;

      function self(selection) {
        
    		var w = width - left - right,
    		    h = height - top - bottom;
    		
    		svg = selection.append("svg")
    		  .attr("width", width + left + right)
    			.attr("height", height + top + bottom)
    			.append("g")
    			.attr("transform", "translate(" + left + ", " + top + ")");
    	}

      self.top = function(value) {
        if (!arguments.length) return top;
        top = value;
        return self;
      };

      self.bottom = function(value) {
        if (!arguments.length) return bottom;
        bottom = value;
        return self;
      };
      
      self.left = function(value) {
        if (!arguments.length) return left;
        left = value;
        return self;
      };
      
      self.right = function(value) {
        if (!arguments.length) return right;
        right = value;
        return self;
      };
      
      self.width = function(value) {
        if (!arguments.length) return width;
        width = value;
        return self;
      };
      
      self.height = function(value) {
        if (!arguments.length) return height;
        height = value;
        return self;
      };
      
      self.svg = function(value){
        if (!arguments.length) return svg;
        svg = value;
        return self;
      }


      return self;
    }
    
    var m = marcon()
      .width(100)
      .height(100)
      .top(50)
      .left(50);
    
    d3.select('body')
      .call(m);
      
    m.svg()
      .append("text")
      .text("Hi Mom!");
    
  </script>
</body>

</html>