//First, we add our sub-namespace to the d3 namespace. It is not essential to do this, //but name-spacing is good practice to not pollute the global space. d3.models = {}; // We add the legend module, which is a simple function returning a function. The outer // function serves as the scoped closure for our module. d3.models.legend = function () { // Some variables are available in the closure and not accessible from the outside (pri- vate). // They have default values. var fontSize = 15; var gxPos = 0; var gyPos = 0; // var width = 10; // var height = 100; var item_height = 20; var fontColor = "white"; var legendValues; var position = "vertical"; // One way for the module to expose events to the outside world is by using d3.dispatch to declare // an event that we can then listen to from the out- side when it’s triggered in the module. //Both d3.dispath and d3.rebind are classified as d3 Internals and are utilities for implementing reusable components. var dispatch = d3.dispatch("mouseOver", "mouseOut","onClick"); function render(selection) { //console.log(selection) selection.each(function(data) { console.log(selection) switch (position) { case "vertical": return vertical(); case "horizontal-recs": return horizontalRecs(); case "horizontal-norecs": return horizontalNoRecs(); } function vertical() { //D3 Vertical Legend////////////////////////// var group = selection.append("g") .attr("transform", function(d,i) { return "translate(" + gxPos + "," + gyPos + ")"}) var legend = group.selectAll("legend").data(legendValues).enter().append("g") .attr("class", "legend") //.attr("transform", function (d, i) { return "translate(0," + i * 20 + ")" }) .attr("transform", function (d, i) { return "translate(0," + i * item_height + ")" }) .on("mouseover",dispatch.mouseOver) //dispath name cannot be same as event .on("mouseout", dispatch.mouseOut) .on("click", dispatch.onClick) legend.append('rect') .attr({ x:5, y:5, width: 10, height: 10 }) .style("fill", function (d, i) { return d.color }) legend.append('text') .attr({ x: 25, y: 15}) .text(function (d, i) { return d.text}) .style("text-anchor", "start") .style("font-size", fontSize) .style("fill",fontColor) }//end vertical function horizontalRecs() { var legend = selection.selectAll('legend').data(legendValues) legend.enter().append("div").attr("class","legend") .style("float","left") .style("margin-right","1em") var p = legend.append("p").attr("class","country-name") p.append("span").attr("class","key-dot").style("background",function(d,i) { return d.color } ) .style("display","inline-block") .style("height","10px") .style("margin-right",".5em") .style("width","10px") p.insert("text").text(function(d,i) { return d.text } ) .style("font-weight","bold") }//end horizontalRecs function horizontalNoRecs() { console.log("inside") var legend = selection.selectAll("legend").data(legendValues).enter().append('div') .attr("class", "legend") .style("display","block") legend .html(function(d,i) {return d.text}) .style("color", function(d,i) {return d.color }) .style("display","inline-block") .style("padding","0px 5px") .style("margin",".2em") .style("font-size","20px") .style("font-weight","bold") .on("mouseover",dispatch.mouseOver) .on("mouseout", dispatch.mouseOut) .on("click", dispatch.onClick) }//end horizonal })//_selection.each() }//render() //Functions are also objects so we can add addtional properties and\or methods // These “public” functions will be used as getters and setters at the same time. // They are getters when no argument is passed to the function; otherwise they set // the private variable to the new value passed as an argument. When setting, we return // the current context this, as we want these methods to be chainable. render.fontSize = function(_x) { if (!arguments.length) return fontSize; fontSize = _x; return this; } render.fontColor = function(_x) { if (!arguments.length) return fontColor; fontColor = _x; return this; } render.width = function(_x) { if (!arguments.length) return width; width = _x; return this; } render.height = function(_x) { if (!arguments.length) return height; height = _x; return this; } render.gxPos = function(_x) { if (!arguments.length) return gxPos; gxPos = _x; return this; } render.gyPos = function(_x) { if (!arguments.length) return gyPos; gyPos = _x; return this; } render.item_height = function(_x) { if (!arguments.length) return item_height; item_height = _x; return this; } render.inputScale = function(_x) { if (!arguments.length) return inputScale; scale = _x; legendValues = []; scale.domain().forEach(function (el) { var cellObject = {color: scale(el), text: el} legendValues.push(cellObject) //console.log(legendValues) }) return this; } render.position = function(_x) { if(!arguments.length) return position; position = _x; return this; } //https://github.com/mbostock/d3/wiki/Internals#rebind d3.rebind(render, dispatch, "on") return render } //d3.rebind // Copies the methods with the specified names from source to target, and returns target. // Calling one of the named methods on the target object invokes the same-named method on the source object, // passing any arguments passed to the target method, and using the source object as the this context