Comparing version 0.7.1 to 0.7.2
@@ -0,1 +1,7 @@ | ||
## v0.7.2 (November 18, 2015) | ||
### Bug Fixes | ||
* [#41]: Fix issue where `events.click.block` would error on `null` | ||
## v0.7.1 (October 28, 2015) | ||
@@ -2,0 +8,0 @@ |
@@ -12,55 +12,20 @@ | ||
/* global d3, Colorizer, LabelFormatter, Navigator, Utils */ | ||
/* exported D3Funnel */ | ||
'use strict'; | ||
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); | ||
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
function _typeof(obj) { return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj; } | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
/* global d3, Colorizer, LabelFormatter, Navigator, Utils */ | ||
/* exported D3Funnel */ | ||
var D3Funnel = (function () { | ||
_createClass(D3Funnel, null, [{ | ||
key: 'defaults', | ||
value: { | ||
chart: { | ||
width: 350, | ||
height: 400, | ||
bottomWidth: 1 / 3, | ||
bottomPinch: 0, | ||
inverted: false, | ||
animate: false, | ||
curve: { | ||
enabled: false, | ||
height: 20 | ||
} | ||
}, | ||
block: { | ||
dynamicHeight: false, | ||
fill: { | ||
scale: d3.scale.category10().domain(d3.range(0, 10)), | ||
type: 'solid' | ||
}, | ||
minHeight: false, | ||
highlight: false | ||
}, | ||
label: { | ||
fontSize: '14px', | ||
fill: '#fff', | ||
format: '{l}: {f}' | ||
}, | ||
events: { | ||
click: { | ||
block: null | ||
} | ||
} | ||
}, | ||
/** | ||
* @param {string} selector A selector for the container element. | ||
* | ||
* @return {void} | ||
*/ | ||
enumerable: true | ||
}]); | ||
/** | ||
* @param {string} selector A selector for the container element. | ||
* | ||
* @return {void} | ||
*/ | ||
@@ -79,5 +44,2 @@ function D3Funnel(selector) { | ||
/* exported Colorizer */ | ||
/* jshint bitwise: false */ | ||
/** | ||
@@ -93,2 +55,3 @@ * Remove the funnel and its events from the DOM. | ||
var container = d3.select(this.selector); | ||
// D3's remove method appears to be sufficient for removing the events | ||
@@ -116,2 +79,3 @@ container.selectAll('svg').remove(); | ||
*/ | ||
}, { | ||
@@ -137,2 +101,3 @@ key: 'draw', | ||
*/ | ||
}, { | ||
@@ -187,2 +152,3 @@ key: '_initialize', | ||
*/ | ||
}, { | ||
@@ -213,2 +179,3 @@ key: '_validateData', | ||
*/ | ||
}, { | ||
@@ -246,2 +213,3 @@ key: '_getSettings', | ||
*/ | ||
}, { | ||
@@ -260,2 +228,3 @@ key: '_setBlocks', | ||
*/ | ||
}, { | ||
@@ -283,2 +252,3 @@ key: '_getTotalCount', | ||
*/ | ||
}, { | ||
@@ -305,3 +275,2 @@ key: '_standardizeData', | ||
height: _this2.height * ratio, | ||
formatted: _this2.labelFormatter.format(label, count), | ||
fill: _this2.colorizer.getBlockFill(block, index, _this2.fillType), | ||
@@ -311,3 +280,3 @@ label: { | ||
formatted: _this2.labelFormatter.format(label, count), | ||
color: _this2.colorizer.getLabelFill(block, index) | ||
color: _this2.colorizer.getLabelFill(block) | ||
} | ||
@@ -327,2 +296,3 @@ }); | ||
*/ | ||
}, { | ||
@@ -337,2 +307,3 @@ key: '_getRawBlockCount', | ||
*/ | ||
}, { | ||
@@ -352,2 +323,3 @@ key: '_getDx', | ||
*/ | ||
}, { | ||
@@ -369,2 +341,3 @@ key: '_getDy', | ||
*/ | ||
}, { | ||
@@ -398,2 +371,3 @@ key: '_draw', | ||
*/ | ||
}, { | ||
@@ -438,3 +412,3 @@ key: '_makePaths', | ||
// shared according to the remaining minus the guaranteed | ||
if (this.minHeight !== false) { | ||
if (this.minHeight !== 0) { | ||
totalHeight = this.height - this.minHeight * this.blocks.length; | ||
@@ -472,3 +446,3 @@ } | ||
// Add greedy minimum height | ||
if (_this3.minHeight !== false) { | ||
if (_this3.minHeight !== 0) { | ||
dy += _this3.minHeight; | ||
@@ -593,2 +567,3 @@ } | ||
*/ | ||
}, { | ||
@@ -630,2 +605,3 @@ key: '_defineColorGradients', | ||
*/ | ||
}, { | ||
@@ -660,2 +636,3 @@ key: '_drawTopOval', | ||
*/ | ||
}, { | ||
@@ -678,3 +655,3 @@ key: '_drawBlock', | ||
// Add animation components | ||
if (this.animation !== false) { | ||
if (this.animation !== 0) { | ||
path.transition().duration(this.animation).ease('linear').attr('fill', this.blocks[index].fill.actual).attr('d', this._getPathDefinition(index)).each('end', function () { | ||
@@ -707,2 +684,3 @@ _this4._drawBlock(index + 1); | ||
*/ | ||
}, { | ||
@@ -713,3 +691,3 @@ key: '_getBlockPath', | ||
if (this.animation !== false) { | ||
if (this.animation !== 0) { | ||
this._addBeforeTransition(path, index); | ||
@@ -729,2 +707,3 @@ } | ||
*/ | ||
}, { | ||
@@ -764,2 +743,3 @@ key: '_addBeforeTransition', | ||
*/ | ||
}, { | ||
@@ -776,2 +756,3 @@ key: '_getD3Data', | ||
*/ | ||
}, { | ||
@@ -794,2 +775,3 @@ key: '_getPathDefinition', | ||
*/ | ||
}, { | ||
@@ -802,6 +784,7 @@ key: '_onMouseOver', | ||
/** | ||
* @param {Object} data | ||
* | ||
* @return {void} | ||
*/ | ||
* @param {Object} data | ||
* | ||
* @return {void} | ||
*/ | ||
}, { | ||
@@ -818,2 +801,3 @@ key: '_onMouseOut', | ||
*/ | ||
}, { | ||
@@ -848,2 +832,3 @@ key: '_addBlockLabel', | ||
*/ | ||
}, { | ||
@@ -863,2 +848,39 @@ key: '_getTextY', | ||
/* exported Colorizer */ | ||
/* jshint bitwise: false */ | ||
D3Funnel.defaults = { | ||
chart: { | ||
width: 350, | ||
height: 400, | ||
bottomWidth: 1 / 3, | ||
bottomPinch: 0, | ||
inverted: false, | ||
animate: 0, | ||
curve: { | ||
enabled: false, | ||
height: 20 | ||
} | ||
}, | ||
block: { | ||
dynamicHeight: false, | ||
fill: { | ||
scale: d3.scale.category10().domain(d3.range(0, 10)), | ||
type: 'solid' | ||
}, | ||
minHeight: 0, | ||
highlight: false | ||
}, | ||
label: { | ||
fontSize: '14px', | ||
fill: '#fff', | ||
format: '{l}: {f}' | ||
}, | ||
events: { | ||
click: { | ||
block: null | ||
} | ||
} | ||
}; | ||
var Colorizer = (function () { | ||
@@ -875,4 +897,2 @@ function Colorizer() { | ||
/* exported LabelFormatter */ | ||
/** | ||
@@ -895,2 +915,3 @@ * @param {string} fill | ||
*/ | ||
}, { | ||
@@ -911,2 +932,3 @@ key: 'setScale', | ||
*/ | ||
}, { | ||
@@ -931,2 +953,3 @@ key: 'getBlockFill', | ||
*/ | ||
}, { | ||
@@ -958,2 +981,3 @@ key: 'getBlockRawFill', | ||
*/ | ||
}, { | ||
@@ -976,2 +1000,3 @@ key: 'getBlockActualFill', | ||
*/ | ||
}, { | ||
@@ -996,2 +1021,3 @@ key: 'getLabelFill', | ||
*/ | ||
}], [{ | ||
@@ -1026,2 +1052,3 @@ key: 'shade', | ||
*/ | ||
}, { | ||
@@ -1037,2 +1064,4 @@ key: 'expandHex', | ||
/* exported LabelFormatter */ | ||
var LabelFormatter = (function () { | ||
@@ -1052,4 +1081,2 @@ | ||
/* exported Navigator */ | ||
/** | ||
@@ -1082,2 +1109,3 @@ * Register the format function. | ||
*/ | ||
}, { | ||
@@ -1108,2 +1136,3 @@ key: 'format', | ||
*/ | ||
}, { | ||
@@ -1130,2 +1159,3 @@ key: 'stringFormatter', | ||
*/ | ||
}, { | ||
@@ -1141,2 +1171,4 @@ key: 'getDefaultFormattedValue', | ||
/* exported Navigator */ | ||
var Navigator = (function () { | ||
@@ -1147,8 +1179,2 @@ function Navigator() { | ||
/* exported Utils */ | ||
/** | ||
* Simple utility class. | ||
*/ | ||
_createClass(Navigator, [{ | ||
@@ -1178,2 +1204,8 @@ key: 'plot', | ||
/* exported Utils */ | ||
/** | ||
* Simple utility class. | ||
*/ | ||
var Utils = (function () { | ||
@@ -1200,4 +1232,4 @@ function Utils() { | ||
if (b.hasOwnProperty(prop)) { | ||
if (typeof b[prop] === 'object' && !Array.isArray(b[prop])) { | ||
if (typeof a[prop] === 'object' && !Array.isArray(a[prop])) { | ||
if (_typeof(b[prop]) === 'object' && !Array.isArray(b[prop]) && b[prop] !== null) { | ||
if (_typeof(a[prop]) === 'object' && !Array.isArray(a[prop]) && b[prop] !== null) { | ||
a[prop] = Utils.extend(a[prop], b[prop]); | ||
@@ -1204,0 +1236,0 @@ } else { |
/*! d3-funnel - v0.7.1 | 2015 */ | ||
!function(t,e){"function"==typeof define&&define.amd?define(["d3"],e):"object"==typeof exports?module.exports=e(require("d3")):t.D3Funnel=e(t.d3)}(this,function(t){"use strict";function e(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var i=function(){function t(t,e){for(var i=0;i<e.length;i++){var a=e[i];a.enumerable=a.enumerable||!1,a.configurable=!0,"value"in a&&(a.writable=!0),Object.defineProperty(t,a.key,a)}}return function(e,i,a){return i&&t(e.prototype,i),a&&t(e,a),e}}(),a=function(){function a(t){e(this,a),this.selector=t,this.colorizer=new n,this.labelFormatter=new l,this.navigator=new r}return i(a,null,[{key:"defaults",value:{chart:{width:350,height:400,bottomWidth:1/3,bottomPinch:0,inverted:!1,animate:!1,curve:{enabled:!1,height:20}},block:{dynamicHeight:!1,fill:{scale:t.scale.category10().domain(t.range(0,10)),type:"solid"},minHeight:!1,highlight:!1},label:{fontSize:"14px",fill:"#fff",format:"{l}: {f}"},events:{click:{block:null}}},enumerable:!0}]),i(a,[{key:"destroy",value:function(){var e=t.select(this.selector);e.selectAll("svg").remove(),e.selectAll("*").remove(),e.text("")}},{key:"draw",value:function(t){var e=arguments.length<=1||void 0===arguments[1]?{}:arguments[1];this.destroy(),this._initialize(t,e),this._draw()}},{key:"_initialize",value:function(t,e){this._validateData(t);var i=this._getSettings(e);this.label=i.label,this.labelFormatter.setFormat(this.label.format),this.colorizer.setLabelFill(i.label.fill),this.colorizer.setScale(i.block.fill.scale),this.width=i.chart.width,this.height=i.chart.height,this.bottomWidth=i.chart.width*i.chart.bottomWidth,this.bottomPinch=i.chart.bottomPinch,this.isInverted=i.chart.inverted,this.isCurved=i.chart.curve.enabled,this.curveHeight=i.chart.curve.height,this.fillType=i.block.fill.type,this.hoverEffects=i.block.highlight,this.dynamicHeight=i.block.dynamicHeight,this.minHeight=i.block.minHeight,this.animation=i.chart.animate,this.onBlockClick=i.events.click.block,this._setBlocks(t),this.bottomLeftX=(this.width-this.bottomWidth)/2,this.dx=this._getDx(),this.dy=this._getDy()}},{key:"_validateData",value:function(t){if(Array.isArray(t)===!1)throw new Error("Data must be an array.");if(0===t.length)throw new Error("Data array must contain at least one element.");if(Array.isArray(t[0])===!1)throw new Error("Data array elements must be arrays.");if(t[0].length<2)throw new Error("Data array elements must contain a label and value.")}},{key:"_getSettings",value:function(e){var i=h.extend({},a.defaults);return i.chart.width=parseInt(t.select(this.selector).style("width"),10),i.chart.height=parseInt(t.select(this.selector).style("height"),10),i=h.extend(i,e),i.chart.width<=0&&(i.chart.width=a.defaults.chart.width),i.chart.height<=0&&(i.chart.height=a.defaults.chart.height),i}},{key:"_setBlocks",value:function(t){var e=this._getTotalCount(t);this.blocks=this._standardizeData(t,e)}},{key:"_getTotalCount",value:function(t){var e=this,i=0;return t.forEach(function(t){i+=e._getRawBlockCount(t)}),i}},{key:"_standardizeData",value:function(t,e){var i=this,a=[],n=void 0,l=void 0,r=void 0;return t.forEach(function(t,h){n=i._getRawBlockCount(t),l=n/e,r=t[0],a.push({index:h,value:n,ratio:l,height:i.height*l,formatted:i.labelFormatter.format(r,n),fill:i.colorizer.getBlockFill(t,h,i.fillType),label:{raw:r,formatted:i.labelFormatter.format(r,n),color:i.colorizer.getLabelFill(t,h)}})}),a}},{key:"_getRawBlockCount",value:function(t){return Array.isArray(t[1])?t[1][0]:t[1]}},{key:"_getDx",value:function(){return this.bottomPinch>0?this.bottomLeftX/(this.blocks.length-this.bottomPinch):this.bottomLeftX/this.blocks.length}},{key:"_getDy",value:function(){return this.isCurved?(this.height-this.curveHeight)/this.blocks.length:this.height/this.blocks.length}},{key:"_draw",value:function(){this.svg=t.select(this.selector).append("svg").attr("width",this.width).attr("height",this.height),this.blockPaths=this._makePaths(),"gradient"===this.fillType&&this._defineColorGradients(this.svg),this.isCurved&&this._drawTopOval(this.svg,this.blockPaths),this._drawBlock(0)}},{key:"_makePaths",value:function(){var t=this,e=[],i=this.dx,a=this.dy,n=0,l=this.width,r=0;this.isInverted&&(n=this.bottomLeftX,l=this.width-this.bottomLeftX);var h=0,o=0,s=0,c=this.width/2;this.isCurved&&(r=10);var u=this.height;this.minHeight!==!1&&(u=this.height-this.minHeight*this.blocks.length);var f=this.height;this.blocks.forEach(function(e,i){t.bottomPinch>0&&(t.isInverted?i<t.bottomPinch&&(f-=e.height):i>=t.blocks.length-t.bottomPinch&&(f-=e.height))});var d=2*f/(this.width-this.bottomWidth);return this.blocks.forEach(function(f,v){t.dynamicHeight&&(a=u*f.ratio,t.minHeight!==!1&&(a+=t.minHeight),t.isCurved&&(a-=t.curveHeight/t.blocks.length),h=(r+a)/d,t.isInverted&&(h=(r+a-t.height)/(-1*d)),0===t.bottomWidth&&v===t.blocks.length-1&&(h=t.width/2,t.isInverted&&(h=0)),t.bottomWidth===t.width&&(h=n),i=h-n,t.isInverted&&(i=n-h)),t.bottomPinch>0&&(t.isInverted?(t.dynamicHeight||(i=t.dx),i=v<t.bottomPinch?0:i):v>=t.blocks.length-t.bottomPinch&&(i=0)),h=n+i,o=l-i,s=r+a,t.isInverted&&(h=n-i,o=l+i),t.isCurved?e.push([[n,r,"M"],[c,r+(t.curveHeight-10),"Q"],[l,r,""],[o,s,"L"],[o,s,"M"],[c,s+t.curveHeight,"Q"],[h,s,""],[n,r,"L"]]):e.push([[n,r,"M"],[l,r,"L"],[o,s,"L"],[h,s,"L"],[n,r,"L"]]),n=h,l=o,r=s}),e}},{key:"_defineColorGradients",value:function(t){var e=t.append("defs");this.blocks.forEach(function(t,i){var a=t.fill.raw,l=n.shade(a,-.2),r=e.append("linearGradient").attr({id:"gradient-"+i}),h=[[0,l],[40,a],[60,a],[100,l]];h.forEach(function(t){r.append("stop").attr({offset:t[0]+"%",style:"stop-color:"+t[1]})})})}},{key:"_drawTopOval",value:function(t,e){var i=0,a=this.width,l=this.width/2;this.isInverted&&(i=this.bottomLeftX,a=this.width-this.bottomLeftX);var r=e[0],h=r[1][1]+this.curveHeight-10,o=this.navigator.plot([["M",i,r[0][1]],["Q",l,h],[" ",a,r[2][1]],["M",a,10],["Q",l,0],[" ",i,10]]);t.append("path").attr("fill",n.shade(this.blocks[0].fill.raw,-.4)).attr("d",o)}},{key:"_drawBlock",value:function(t){var e=this;if(t!==this.blocks.length){var i=this.svg.append("g"),a=this._getBlockPath(i,t);a.data(this._getD3Data(t)),this.animation!==!1?a.transition().duration(this.animation).ease("linear").attr("fill",this.blocks[t].fill.actual).attr("d",this._getPathDefinition(t)).each("end",function(){e._drawBlock(t+1)}):(a.attr("fill",this.blocks[t].fill.actual).attr("d",this._getPathDefinition(t)),this._drawBlock(t+1)),this.hoverEffects&&a.on("mouseover",this._onMouseOver).on("mouseout",this._onMouseOut),null!==this.onBlockClick&&a.on("click",this.onBlockClick),this._addBlockLabel(i,t)}}},{key:"_getBlockPath",value:function(t,e){var i=t.append("path");return this.animation!==!1&&this._addBeforeTransition(i,e),i}},{key:"_addBeforeTransition",value:function(t,e){var i=this.blockPaths[e],a="",n="";a=this.isCurved?this.navigator.plot([["M",i[0][0],i[0][1]],["Q",i[1][0],i[1][1]],[" ",i[2][0],i[2][1]],["L",i[2][0],i[2][1]],["M",i[2][0],i[2][1]],["Q",i[1][0],i[1][1]],[" ",i[0][0],i[0][1]]]):this.navigator.plot([["M",i[0][0],i[0][1]],["L",i[1][0],i[1][1]],["L",i[1][0],i[1][1]],["L",i[0][0],i[0][1]]]),n="solid"===this.fillType&&e>0?this.blocks[e-1].fill.actual:this.blocks[e].fill.actual,t.attr("d",a).attr("fill",n)}},{key:"_getD3Data",value:function(t){return[this.blocks[t]]}},{key:"_getPathDefinition",value:function(t){var e=[];return this.blockPaths[t].forEach(function(t){e.push([t[2],t[0],t[1]])}),this.navigator.plot(e)}},{key:"_onMouseOver",value:function(e){t.select(this).attr("fill",n.shade(e.fill.raw,-.2))}},{key:"_onMouseOut",value:function(e){t.select(this).attr("fill",e.fill.actual)}},{key:"_addBlockLabel",value:function(t,e){var i=this.blockPaths[e],a=this.blocks[e].label.formatted,n=this.blocks[e].label.color,l=this.width/2,r=this._getTextY(i);t.append("text").text(a).attr({x:l,y:r,"text-anchor":"middle","dominant-baseline":"middle",fill:n,"pointer-events":"none"}).style("font-size",this.label.fontSize)}},{key:"_getTextY",value:function(t){return this.isCurved?(t[2][1]+t[3][1])/2+this.curveHeight/this.blocks.length:(t[1][1]+t[2][1])/2}}]),a}(),n=function(){function t(){e(this,t),this.hexExpression=/^#([0-9a-f]{3}|[0-9a-f]{6})$/i,this.labelFill=null,this.scale=null}return i(t,[{key:"setLabelFill",value:function(t){this.labelFill=t}},{key:"setScale",value:function(t){this.scale=t}},{key:"getBlockFill",value:function(t,e,i){var a=this.getBlockRawFill(t,e);return{raw:a,actual:this.getBlockActualFill(a,e,i)}}},{key:"getBlockRawFill",value:function(t,e){return t.length>2&&this.hexExpression.test(t[2])?t[2]:Array.isArray(this.scale)?this.scale[e]:this.scale(e)}},{key:"getBlockActualFill",value:function(t,e,i){return"solid"===i?t:"url(#gradient-"+e+")"}},{key:"getLabelFill",value:function(t){return t.length>3&&this.hexExpression.test(t[3])?t[3]:this.labelFill}}],[{key:"shade",value:function(e,i){var a=e.slice(1);3===a.length&&(a=t.expandHex(a));var n=parseInt(a,16),l=0>i?0:255,r=0>i?-1*i:i,h=n>>16,o=n>>8&255,s=255&n,c=16777216+65536*(Math.round((l-h)*r)+h)+256*(Math.round((l-o)*r)+o)+(Math.round((l-s)*r)+s);return"#"+c.toString(16).slice(1)}},{key:"expandHex",value:function(t){return t[0]+t[0]+t[1]+t[1]+t[2]+t[2]}}]),t}(),l=function(){function t(){e(this,t),this.expression=null}return i(t,[{key:"setFormat",value:function(t){"function"==typeof t?this.formatter=t:(this.expression=t,this.formatter=this.stringFormatter)}},{key:"format",value:function(t,e){return Array.isArray(e)?this.formatter(t,e[0],e[1]):this.formatter(t,e,null)}},{key:"stringFormatter",value:function(t,e){var i=arguments.length<=2||void 0===arguments[2]?null:arguments[2],a=i;return null===i&&(a=this.getDefaultFormattedValue(e)),this.expression.split("{l}").join(t).split("{v}").join(e).split("{f}").join(a)}},{key:"getDefaultFormattedValue",value:function(t){return t.toLocaleString()}}]),t}(),r=function(){function t(){e(this,t)}return i(t,[{key:"plot",value:function(t){var e="";return t.forEach(function(t){e+=t[0]+t[1]+","+t[2]+" "}),e.replace(/ +/g," ").trim()}}]),t}(),h=function(){function t(){e(this,t)}return i(t,null,[{key:"extend",value:function(e,i){var a=void 0;for(a in i)i.hasOwnProperty(a)&&("object"!=typeof i[a]||Array.isArray(i[a])?e[a]=i[a]:"object"!=typeof e[a]||Array.isArray(e[a])?e[a]=t.extend({},i[a]):e[a]=t.extend(e[a],i[a]));return e}}]),t}();return a}); | ||
!function(t,e){"function"==typeof define&&define.amd?define(["d3"],e):"object"==typeof exports?module.exports=e(require("d3")):t.D3Funnel=e(t.d3)}(this,function(t){"use strict";function e(t){return t&&"undefined"!=typeof Symbol&&t.constructor===Symbol?"symbol":typeof t}function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var a=function(){function t(t,e){for(var i=0;i<e.length;i++){var a=e[i];a.enumerable=a.enumerable||!1,a.configurable=!0,"value"in a&&(a.writable=!0),Object.defineProperty(t,a.key,a)}}return function(e,i,a){return i&&t(e.prototype,i),a&&t(e,a),e}}(),n=function(){function e(t){i(this,e),this.selector=t,this.colorizer=new l,this.labelFormatter=new r,this.navigator=new h}return a(e,[{key:"destroy",value:function(){var e=t.select(this.selector);e.selectAll("svg").remove(),e.selectAll("*").remove(),e.text("")}},{key:"draw",value:function(t){var e=arguments.length<=1||void 0===arguments[1]?{}:arguments[1];this.destroy(),this._initialize(t,e),this._draw()}},{key:"_initialize",value:function(t,e){this._validateData(t);var i=this._getSettings(e);this.label=i.label,this.labelFormatter.setFormat(this.label.format),this.colorizer.setLabelFill(i.label.fill),this.colorizer.setScale(i.block.fill.scale),this.width=i.chart.width,this.height=i.chart.height,this.bottomWidth=i.chart.width*i.chart.bottomWidth,this.bottomPinch=i.chart.bottomPinch,this.isInverted=i.chart.inverted,this.isCurved=i.chart.curve.enabled,this.curveHeight=i.chart.curve.height,this.fillType=i.block.fill.type,this.hoverEffects=i.block.highlight,this.dynamicHeight=i.block.dynamicHeight,this.minHeight=i.block.minHeight,this.animation=i.chart.animate,this.onBlockClick=i.events.click.block,this._setBlocks(t),this.bottomLeftX=(this.width-this.bottomWidth)/2,this.dx=this._getDx(),this.dy=this._getDy()}},{key:"_validateData",value:function(t){if(Array.isArray(t)===!1)throw new Error("Data must be an array.");if(0===t.length)throw new Error("Data array must contain at least one element.");if(Array.isArray(t[0])===!1)throw new Error("Data array elements must be arrays.");if(t[0].length<2)throw new Error("Data array elements must contain a label and value.")}},{key:"_getSettings",value:function(i){var a=o.extend({},e.defaults);return a.chart.width=parseInt(t.select(this.selector).style("width"),10),a.chart.height=parseInt(t.select(this.selector).style("height"),10),a=o.extend(a,i),a.chart.width<=0&&(a.chart.width=e.defaults.chart.width),a.chart.height<=0&&(a.chart.height=e.defaults.chart.height),a}},{key:"_setBlocks",value:function(t){var e=this._getTotalCount(t);this.blocks=this._standardizeData(t,e)}},{key:"_getTotalCount",value:function(t){var e=this,i=0;return t.forEach(function(t){i+=e._getRawBlockCount(t)}),i}},{key:"_standardizeData",value:function(t,e){var i=this,a=[],n=void 0,l=void 0,r=void 0;return t.forEach(function(t,h){n=i._getRawBlockCount(t),l=n/e,r=t[0],a.push({index:h,value:n,ratio:l,height:i.height*l,fill:i.colorizer.getBlockFill(t,h,i.fillType),label:{raw:r,formatted:i.labelFormatter.format(r,n),color:i.colorizer.getLabelFill(t)}})}),a}},{key:"_getRawBlockCount",value:function(t){return Array.isArray(t[1])?t[1][0]:t[1]}},{key:"_getDx",value:function(){return this.bottomPinch>0?this.bottomLeftX/(this.blocks.length-this.bottomPinch):this.bottomLeftX/this.blocks.length}},{key:"_getDy",value:function(){return this.isCurved?(this.height-this.curveHeight)/this.blocks.length:this.height/this.blocks.length}},{key:"_draw",value:function(){this.svg=t.select(this.selector).append("svg").attr("width",this.width).attr("height",this.height),this.blockPaths=this._makePaths(),"gradient"===this.fillType&&this._defineColorGradients(this.svg),this.isCurved&&this._drawTopOval(this.svg,this.blockPaths),this._drawBlock(0)}},{key:"_makePaths",value:function(){var t=this,e=[],i=this.dx,a=this.dy,n=0,l=this.width,r=0;this.isInverted&&(n=this.bottomLeftX,l=this.width-this.bottomLeftX);var h=0,o=0,s=0,c=this.width/2;this.isCurved&&(r=10);var u=this.height;0!==this.minHeight&&(u=this.height-this.minHeight*this.blocks.length);var f=this.height;this.blocks.forEach(function(e,i){t.bottomPinch>0&&(t.isInverted?i<t.bottomPinch&&(f-=e.height):i>=t.blocks.length-t.bottomPinch&&(f-=e.height))});var d=2*f/(this.width-this.bottomWidth);return this.blocks.forEach(function(f,v){t.dynamicHeight&&(a=u*f.ratio,0!==t.minHeight&&(a+=t.minHeight),t.isCurved&&(a-=t.curveHeight/t.blocks.length),h=(r+a)/d,t.isInverted&&(h=(r+a-t.height)/(-1*d)),0===t.bottomWidth&&v===t.blocks.length-1&&(h=t.width/2,t.isInverted&&(h=0)),t.bottomWidth===t.width&&(h=n),i=h-n,t.isInverted&&(i=n-h)),t.bottomPinch>0&&(t.isInverted?(t.dynamicHeight||(i=t.dx),i=v<t.bottomPinch?0:i):v>=t.blocks.length-t.bottomPinch&&(i=0)),h=n+i,o=l-i,s=r+a,t.isInverted&&(h=n-i,o=l+i),t.isCurved?e.push([[n,r,"M"],[c,r+(t.curveHeight-10),"Q"],[l,r,""],[o,s,"L"],[o,s,"M"],[c,s+t.curveHeight,"Q"],[h,s,""],[n,r,"L"]]):e.push([[n,r,"M"],[l,r,"L"],[o,s,"L"],[h,s,"L"],[n,r,"L"]]),n=h,l=o,r=s}),e}},{key:"_defineColorGradients",value:function(t){var e=t.append("defs");this.blocks.forEach(function(t,i){var a=t.fill.raw,n=l.shade(a,-.2),r=e.append("linearGradient").attr({id:"gradient-"+i}),h=[[0,n],[40,a],[60,a],[100,n]];h.forEach(function(t){r.append("stop").attr({offset:t[0]+"%",style:"stop-color:"+t[1]})})})}},{key:"_drawTopOval",value:function(t,e){var i=0,a=this.width,n=this.width/2;this.isInverted&&(i=this.bottomLeftX,a=this.width-this.bottomLeftX);var r=e[0],h=r[1][1]+this.curveHeight-10,o=this.navigator.plot([["M",i,r[0][1]],["Q",n,h],[" ",a,r[2][1]],["M",a,10],["Q",n,0],[" ",i,10]]);t.append("path").attr("fill",l.shade(this.blocks[0].fill.raw,-.4)).attr("d",o)}},{key:"_drawBlock",value:function(t){var e=this;if(t!==this.blocks.length){var i=this.svg.append("g"),a=this._getBlockPath(i,t);a.data(this._getD3Data(t)),0!==this.animation?a.transition().duration(this.animation).ease("linear").attr("fill",this.blocks[t].fill.actual).attr("d",this._getPathDefinition(t)).each("end",function(){e._drawBlock(t+1)}):(a.attr("fill",this.blocks[t].fill.actual).attr("d",this._getPathDefinition(t)),this._drawBlock(t+1)),this.hoverEffects&&a.on("mouseover",this._onMouseOver).on("mouseout",this._onMouseOut),null!==this.onBlockClick&&a.on("click",this.onBlockClick),this._addBlockLabel(i,t)}}},{key:"_getBlockPath",value:function(t,e){var i=t.append("path");return 0!==this.animation&&this._addBeforeTransition(i,e),i}},{key:"_addBeforeTransition",value:function(t,e){var i=this.blockPaths[e],a="",n="";a=this.isCurved?this.navigator.plot([["M",i[0][0],i[0][1]],["Q",i[1][0],i[1][1]],[" ",i[2][0],i[2][1]],["L",i[2][0],i[2][1]],["M",i[2][0],i[2][1]],["Q",i[1][0],i[1][1]],[" ",i[0][0],i[0][1]]]):this.navigator.plot([["M",i[0][0],i[0][1]],["L",i[1][0],i[1][1]],["L",i[1][0],i[1][1]],["L",i[0][0],i[0][1]]]),n="solid"===this.fillType&&e>0?this.blocks[e-1].fill.actual:this.blocks[e].fill.actual,t.attr("d",a).attr("fill",n)}},{key:"_getD3Data",value:function(t){return[this.blocks[t]]}},{key:"_getPathDefinition",value:function(t){var e=[];return this.blockPaths[t].forEach(function(t){e.push([t[2],t[0],t[1]])}),this.navigator.plot(e)}},{key:"_onMouseOver",value:function(e){t.select(this).attr("fill",l.shade(e.fill.raw,-.2))}},{key:"_onMouseOut",value:function(e){t.select(this).attr("fill",e.fill.actual)}},{key:"_addBlockLabel",value:function(t,e){var i=this.blockPaths[e],a=this.blocks[e].label.formatted,n=this.blocks[e].label.color,l=this.width/2,r=this._getTextY(i);t.append("text").text(a).attr({x:l,y:r,"text-anchor":"middle","dominant-baseline":"middle",fill:n,"pointer-events":"none"}).style("font-size",this.label.fontSize)}},{key:"_getTextY",value:function(t){return this.isCurved?(t[2][1]+t[3][1])/2+this.curveHeight/this.blocks.length:(t[1][1]+t[2][1])/2}}]),e}();n.defaults={chart:{width:350,height:400,bottomWidth:1/3,bottomPinch:0,inverted:!1,animate:0,curve:{enabled:!1,height:20}},block:{dynamicHeight:!1,fill:{scale:t.scale.category10().domain(t.range(0,10)),type:"solid"},minHeight:0,highlight:!1},label:{fontSize:"14px",fill:"#fff",format:"{l}: {f}"},events:{click:{block:null}}};var l=function(){function t(){i(this,t),this.hexExpression=/^#([0-9a-f]{3}|[0-9a-f]{6})$/i,this.labelFill=null,this.scale=null}return a(t,[{key:"setLabelFill",value:function(t){this.labelFill=t}},{key:"setScale",value:function(t){this.scale=t}},{key:"getBlockFill",value:function(t,e,i){var a=this.getBlockRawFill(t,e);return{raw:a,actual:this.getBlockActualFill(a,e,i)}}},{key:"getBlockRawFill",value:function(t,e){return t.length>2&&this.hexExpression.test(t[2])?t[2]:Array.isArray(this.scale)?this.scale[e]:this.scale(e)}},{key:"getBlockActualFill",value:function(t,e,i){return"solid"===i?t:"url(#gradient-"+e+")"}},{key:"getLabelFill",value:function(t){return t.length>3&&this.hexExpression.test(t[3])?t[3]:this.labelFill}}],[{key:"shade",value:function(e,i){var a=e.slice(1);3===a.length&&(a=t.expandHex(a));var n=parseInt(a,16),l=0>i?0:255,r=0>i?-1*i:i,h=n>>16,o=n>>8&255,s=255&n,c=16777216+65536*(Math.round((l-h)*r)+h)+256*(Math.round((l-o)*r)+o)+(Math.round((l-s)*r)+s);return"#"+c.toString(16).slice(1)}},{key:"expandHex",value:function(t){return t[0]+t[0]+t[1]+t[1]+t[2]+t[2]}}]),t}(),r=function(){function t(){i(this,t),this.expression=null}return a(t,[{key:"setFormat",value:function(t){"function"==typeof t?this.formatter=t:(this.expression=t,this.formatter=this.stringFormatter)}},{key:"format",value:function(t,e){return Array.isArray(e)?this.formatter(t,e[0],e[1]):this.formatter(t,e,null)}},{key:"stringFormatter",value:function(t,e){var i=arguments.length<=2||void 0===arguments[2]?null:arguments[2],a=i;return null===i&&(a=this.getDefaultFormattedValue(e)),this.expression.split("{l}").join(t).split("{v}").join(e).split("{f}").join(a)}},{key:"getDefaultFormattedValue",value:function(t){return t.toLocaleString()}}]),t}(),h=function(){function t(){i(this,t)}return a(t,[{key:"plot",value:function(t){var e="";return t.forEach(function(t){e+=t[0]+t[1]+","+t[2]+" "}),e.replace(/ +/g," ").trim()}}]),t}(),o=function(){function t(){i(this,t)}return a(t,null,[{key:"extend",value:function(i,a){var n=void 0;for(n in a)a.hasOwnProperty(n)&&("object"!==e(a[n])||Array.isArray(a[n])||null===a[n]?i[n]=a[n]:"object"!==e(i[n])||Array.isArray(i[n])||null===a[n]?i[n]=t.extend({},a[n]):i[n]=t.extend(i[n],a[n]));return i}}]),t}();return n}); |
@@ -42,3 +42,6 @@ var gulp = require('gulp'); | ||
.pipe(babel({ | ||
stage: 0, | ||
presets: [ | ||
'es2015', | ||
'stage-0', | ||
], | ||
})) | ||
@@ -45,0 +48,0 @@ .pipe(umd(umdOptions)) |
{ | ||
"name": "d3-funnel", | ||
"version": "0.7.1", | ||
"version": "0.7.2", | ||
"description": "A library for rendering SVG funnel charts using D3.js", | ||
@@ -14,9 +14,11 @@ "author": "Jake Zatecky", | ||
"devDependencies": { | ||
"babel-eslint": "^4.1.3", | ||
"babel-eslint": "^4.1.5", | ||
"babel-preset-es2015": "^6.1.2", | ||
"babel-preset-stage-0": "^6.1.2", | ||
"chai": "^3.4.0", | ||
"chai-spies": "^0.7.1", | ||
"eslint": "^1.7.3", | ||
"eslint-config-airbnb": "^0.1.0", | ||
"eslint": "^1.9.0", | ||
"eslint-config-airbnb": "^1.0.0", | ||
"gulp": "^3.9.0", | ||
"gulp-babel": "^5.3.0", | ||
"gulp-babel": "^6.1.0", | ||
"gulp-concat": "^2.6.0", | ||
@@ -23,0 +25,0 @@ "gulp-eslint": "^1.0.0", |
@@ -60,21 +60,21 @@ # D3 Funnel | ||
| Option | Description | Type | Default | | ||
| --------------------- | --------------------------------------------------------------------------- | -------------- | ----------------------- | | ||
| `chart.width` | The pixel width of the chart. | int | Container's width | | ||
| `chart.height` | The pixel height of the chart. | int | Container's height | | ||
| `chart.bottomWidth` | The percent of total width the bottom should be. | float | `1 / 3` | | ||
| `chart.bottomPinch` | How many blocks to pinch on the bottom to create a "neck". | int | `0` | | ||
| `chart.inverted` | Whether the funnel is inverted (like a pyramid). | bool | `false` | | ||
| `chart.animate` | The load animation speed in milliseconds. | int/bool | `false` | | ||
| `chart.curve.enabled` | Whether the funnel is curved. | bool | `false` | | ||
| `chart.curve.height` | The curvature amount. | int | `20` | | ||
| `block.dynamicHeight` | Whether the block heights are proportional to its weight. | bool | `false` | | ||
| `block.fill.scale` | The block background color scale. Expects an index and returns a color. | function/array | `d3.scale.category10()` | | ||
| `block.fill.type` | Either `'solid'` or `'gradient'`. | string | `'solid'` | | ||
| `block.minHeight` | The minimum pixel height of a block. | int/bool | `false` | | ||
| `block.highlight` | Whether the blocks are highlighted on hover. | bool | `false` | | ||
| `label.fontSize` | Any valid font size for the labels. | string | `'14px'` | | ||
| `label.fill` | Any valid hex color for the label color | string | `'#fff'` | | ||
| `label.format` | Either `function(label, value)` or a format string. See below. | function/array | `'{l}: {f}'` | | ||
| `events.click.block` | Callback for when a block is clicked. | function | `null` | | ||
| Option | Description | Type | Default | | ||
| --------------------- | ------------------------------------------------------------------------- | -------- | ----------------------- | | ||
| `chart.width` | The pixel width of the chart. | number | Container's width | | ||
| `chart.height` | The pixel height of the chart. | number | Container's height | | ||
| `chart.bottomWidth` | The percent of total width the bottom should be. | number | `1 / 3` | | ||
| `chart.bottomPinch` | How many blocks to pinch on the bottom to create a funnel "neck". | number | `0` | | ||
| `chart.inverted` | Whether the funnel is inverted (like a pyramid). | bool | `false` | | ||
| `chart.animate` | The load animation speed in milliseconds. | number | `0` (disabled) | | ||
| `chart.curve.enabled` | Whether the funnel is curved. | bool | `false` | | ||
| `chart.curve.height` | The curvature amount. | number | `20` | | ||
| `block.dynamicHeight` | Whether the block heights are proportional to its weight. | bool | `false` | | ||
| `block.fill.scale` | The background color scale as an array or function. | mixed | `d3.scale.category10()` | | ||
| `block.fill.type` | Either `'solid'` or `'gradient'`. | string | `'solid'` | | ||
| `block.minHeight` | The minimum pixel height of a block. | number | `0` | | ||
| `block.highlight` | Whether the blocks are highlighted on hover. | bool | `false` | | ||
| `label.fontSize` | Any valid font size for the labels. | string | `'14px'` | | ||
| `label.fill` | Any valid hex color for the label color. | string | `'#fff'` | | ||
| `label.format` | Either `function(label, value)`, an array, or a format string. See below. | mixed | `'{l}: {f}'` | | ||
| `events.click.block` | Callback `function(data)` for when a block is clicked. | function | `null` | | ||
@@ -92,2 +92,30 @@ ### Label Format | ||
### Event Data | ||
Block-based events are passed a `data` object containing the following elements: | ||
| Key | Type | Description | | ||
| --------------- | ------ | ------------------------------------- | | ||
| index | number | The index of the block. | | ||
| value | number | The numerical value. | | ||
| fill | string | The background color. | | ||
| label.raw | string | The unformatted label. | | ||
| label.formatted | string | The result of `options.label.format`. | | ||
| label.color | string | The label color. | | ||
Example: | ||
``` javascript | ||
{ | ||
index: 0, | ||
value: 150, | ||
fill: '#c33', | ||
label: { | ||
raw: 'Visitors', | ||
formatted: 'Visitors: 150', | ||
color: '#fff', | ||
}, | ||
}, | ||
``` | ||
### Overriding Defaults | ||
@@ -94,0 +122,0 @@ |
@@ -42,3 +42,3 @@ /* exported Colorizer */ | ||
getBlockFill(block, index, type) { | ||
let raw = this.getBlockRawFill(block, index); | ||
const raw = this.getBlockRawFill(block, index); | ||
@@ -122,11 +122,11 @@ return { | ||
let f = parseInt(hex, 16); | ||
let t = shade < 0 ? 0 : 255; | ||
let p = shade < 0 ? shade * -1 : shade; | ||
const f = parseInt(hex, 16); | ||
const t = shade < 0 ? 0 : 255; | ||
const p = shade < 0 ? shade * -1 : shade; | ||
let R = f >> 16; | ||
let G = f >> 8 & 0x00FF; | ||
let B = f & 0x0000FF; | ||
const R = f >> 16; | ||
const G = f >> 8 & 0x00FF; | ||
const B = f & 0x0000FF; | ||
let converted = 0x1000000 + | ||
const converted = 0x1000000 + | ||
(Math.round((t - R) * p) + R) * 0x10000 + | ||
@@ -133,0 +133,0 @@ (Math.round((t - G) * p) + G) * 0x100 + |
@@ -13,3 +13,3 @@ /* global d3, Colorizer, LabelFormatter, Navigator, Utils */ | ||
inverted: false, | ||
animate: false, | ||
animate: 0, | ||
curve: { | ||
@@ -26,3 +26,3 @@ enabled: false, | ||
}, | ||
minHeight: false, | ||
minHeight: 0, | ||
highlight: false, | ||
@@ -63,3 +63,4 @@ }, | ||
destroy() { | ||
let container = d3.select(this.selector); | ||
const container = d3.select(this.selector); | ||
// D3's remove method appears to be sufficient for removing the events | ||
@@ -106,3 +107,3 @@ container.selectAll('svg').remove(); | ||
let settings = this._getSettings(options); | ||
const settings = this._getSettings(options); | ||
@@ -205,3 +206,3 @@ // Set labels | ||
_setBlocks(data) { | ||
let totalCount = this._getTotalCount(data); | ||
const totalCount = this._getTotalCount(data); | ||
@@ -235,3 +236,3 @@ this.blocks = this._standardizeData(data, totalCount); | ||
_standardizeData(data, totalCount) { | ||
let standardized = []; | ||
const standardized = []; | ||
@@ -252,3 +253,2 @@ let count; | ||
height: this.height * ratio, | ||
formatted: this.labelFormatter.format(label, count), | ||
fill: this.colorizer.getBlockFill(block, index, this.fillType), | ||
@@ -258,3 +258,3 @@ label: { | ||
formatted: this.labelFormatter.format(label, count), | ||
color: this.colorizer.getLabelFill(block, index), | ||
color: this.colorizer.getLabelFill(block), | ||
}, | ||
@@ -337,3 +337,3 @@ }); | ||
_makePaths() { | ||
let paths = []; | ||
const paths = []; | ||
@@ -360,3 +360,3 @@ // Initialize velocity | ||
let middle = this.width / 2; | ||
const middle = this.width / 2; | ||
@@ -373,3 +373,3 @@ // Move down if there is an initial curve | ||
// shared according to the remaining minus the guaranteed | ||
if (this.minHeight !== false) { | ||
if (this.minHeight !== 0) { | ||
totalHeight = this.height - this.minHeight * this.blocks.length; | ||
@@ -396,3 +396,3 @@ } | ||
// iteration | ||
let slope = 2 * slopeHeight / (this.width - this.bottomWidth); | ||
const slope = 2 * slopeHeight / (this.width - this.bottomWidth); | ||
@@ -408,3 +408,3 @@ // Create the path definition for each funnel block | ||
// Add greedy minimum height | ||
if (this.minHeight !== false) { | ||
if (this.minHeight !== 0) { | ||
dy += this.minHeight; | ||
@@ -536,11 +536,11 @@ } | ||
_defineColorGradients(svg) { | ||
let defs = svg.append('defs'); | ||
const defs = svg.append('defs'); | ||
// Create a gradient for each block | ||
this.blocks.forEach((block, index) => { | ||
let color = block.fill.raw; | ||
let shade = Colorizer.shade(color, -0.2); | ||
const color = block.fill.raw; | ||
const shade = Colorizer.shade(color, -0.2); | ||
// Create linear gradient | ||
let gradient = defs.append('linearGradient') | ||
const gradient = defs.append('linearGradient') | ||
.attr({ | ||
@@ -551,3 +551,3 @@ id: 'gradient-' + index, | ||
// Define the gradient stops | ||
let stops = [ | ||
const stops = [ | ||
[0, shade], | ||
@@ -580,3 +580,3 @@ [40, color], | ||
let rightX = this.width; | ||
let centerX = this.width / 2; | ||
const centerX = this.width / 2; | ||
@@ -589,6 +589,6 @@ if (this.isInverted) { | ||
// Create path from top-most block | ||
let paths = blockPaths[0]; | ||
let topCurve = paths[1][1] + this.curveHeight - 10; | ||
const paths = blockPaths[0]; | ||
const topCurve = paths[1][1] + this.curveHeight - 10; | ||
let path = this.navigator.plot([ | ||
const path = this.navigator.plot([ | ||
['M', leftX, paths[0][1]], | ||
@@ -621,10 +621,10 @@ ['Q', centerX, topCurve], | ||
// Create a group just for this block | ||
let group = this.svg.append('g'); | ||
const group = this.svg.append('g'); | ||
// Fetch path element | ||
let path = this._getBlockPath(group, index); | ||
const path = this._getBlockPath(group, index); | ||
path.data(this._getD3Data(index)); | ||
// Add animation components | ||
if (this.animation !== false) { | ||
if (this.animation !== 0) { | ||
path.transition() | ||
@@ -665,5 +665,5 @@ .duration(this.animation) | ||
_getBlockPath(group, index) { | ||
let path = group.append('path'); | ||
const path = group.append('path'); | ||
if (this.animation !== false) { | ||
if (this.animation !== 0) { | ||
this._addBeforeTransition(path, index); | ||
@@ -684,3 +684,3 @@ } | ||
_addBeforeTransition(path, index) { | ||
let paths = this.blockPaths[index]; | ||
const paths = this.blockPaths[index]; | ||
@@ -740,3 +740,3 @@ let beforePath = ''; | ||
_getPathDefinition(index) { | ||
let commands = []; | ||
const commands = []; | ||
@@ -759,3 +759,3 @@ this.blockPaths[index].forEach((command) => { | ||
/** | ||
/** | ||
* @param {Object} data | ||
@@ -775,9 +775,9 @@ * | ||
_addBlockLabel(group, index) { | ||
let paths = this.blockPaths[index]; | ||
const paths = this.blockPaths[index]; | ||
let text = this.blocks[index].label.formatted; | ||
let fill = this.blocks[index].label.color; | ||
const text = this.blocks[index].label.formatted; | ||
const fill = this.blocks[index].label.color; | ||
let x = this.width / 2; // Center the text | ||
let y = this._getTextY(paths); | ||
const x = this.width / 2; // Center the text | ||
const y = this._getTextY(paths); | ||
@@ -784,0 +784,0 @@ group.append('text') |
@@ -21,4 +21,4 @@ /* exported Utils */ | ||
if (b.hasOwnProperty(prop)) { | ||
if (typeof b[prop] === 'object' && !Array.isArray(b[prop])) { | ||
if (typeof a[prop] === 'object' && !Array.isArray(a[prop])) { | ||
if (typeof b[prop] === 'object' && !Array.isArray(b[prop]) && b[prop] !== null) { | ||
if (typeof a[prop] === 'object' && !Array.isArray(a[prop]) && b[prop] !== null) { | ||
a[prop] = Utils.extend(a[prop], b[prop]); | ||
@@ -25,0 +25,0 @@ } else { |
@@ -15,12 +15,35 @@ /* global d3, assert, chai, D3Funnel */ | ||
function getPathBottomWidth(path) { | ||
var commands = path.attr('d').split(' '); | ||
return getCommandPoint(commands[2]).x - getCommandPoint(commands[3]).x; | ||
} | ||
function getPathHeight(path) { | ||
var commands = path.attr('d').split(' '); | ||
return getCommandHeight(commands[2]) - getCommandHeight(commands[0]); | ||
return getCommandPoint(commands[2]).y - getCommandPoint(commands[0]).y; | ||
} | ||
function getCommandHeight(command) { | ||
return parseFloat(command.split(',')[1]); | ||
function getCommandPoint(command) { | ||
var points = command.split(','); | ||
var x = points[0]; | ||
var y = points[1]; | ||
// Strip any letter in front of number | ||
if (isLetter(x[0])) { | ||
x = x.substr(1); | ||
} | ||
return { | ||
x: parseFloat(x), | ||
y: parseFloat(y), | ||
}; | ||
} | ||
function isLetter(str) { | ||
return str.length === 1 && str.match(/[a-z]/i); | ||
} | ||
var defaults = _.clone(D3Funnel.defaults, true); | ||
@@ -140,4 +163,4 @@ | ||
it('should remove other elements from container', function () { | ||
var container = d3.select('#funnel'), | ||
funnel = getFunnel(); | ||
var container = d3.select('#funnel'); | ||
var funnel = getFunnel(); | ||
@@ -150,6 +173,5 @@ // Make sure the container has no children | ||
var funnelChildrenSize = getSvg().selectAll('*').size(), | ||
// expect funnel children count plus funnel itself | ||
expected = funnelChildrenSize + 1, | ||
actual = container.selectAll('*').size(); | ||
// Expect funnel children count plus funnel itself | ||
var expected = getSvg().selectAll('*').size() + 1; | ||
var actual = container.selectAll('*').size(); | ||
@@ -160,4 +182,4 @@ assert.equal(expected, actual); | ||
it('should remove inner text from container', function () { | ||
var container = d3.select('#funnel'), | ||
funnel = getFunnel(); | ||
var container = d3.select('#funnel'); | ||
var funnel = getFunnel(); | ||
@@ -199,3 +221,3 @@ // Make sure the container has no text | ||
describe('chart.width', function () { | ||
it ('should default to the container\'s width', function () { | ||
it('should default to the container\'s width', function () { | ||
d3.select('#funnel').style('width', '250px'); | ||
@@ -220,3 +242,3 @@ | ||
describe('chart.height', function () { | ||
it ('should default to the container\'s height', function () { | ||
it('should default to the container\'s height', function () { | ||
d3.select('#funnel').style('height', '250px'); | ||
@@ -240,2 +262,36 @@ | ||
describe('chart.bottomWidth', function () { | ||
it('should set the bottom tip width to the specified percentage', function () { | ||
getFunnel().draw(getBasicData(), { | ||
chart: { | ||
width: 200, | ||
bottomWidth: 1 / 2, | ||
}, | ||
}); | ||
assert.equal(100, getPathBottomWidth(d3.select('path'))); | ||
}); | ||
}); | ||
describe('chart.bottomPinch', function () { | ||
it('should set the last n number of blocks to have the width of chart.bottomWidth', function () { | ||
getFunnel().draw([ | ||
['A', 1], | ||
['B', 2], | ||
['C', 3], | ||
], { | ||
chart: { | ||
width: 450, | ||
bottomWidth: 1 / 3, | ||
bottomPinch: 2, | ||
}, | ||
}); | ||
var paths = d3.selectAll('path'); | ||
assert.equal(150, paths[0][1].getBBox().width); | ||
assert.equal(150, paths[0][2].getBBox().width); | ||
}); | ||
}); | ||
describe('chart.curve.enabled', function () { | ||
@@ -334,8 +390,6 @@ it('should create an additional path on top of the trapezoids', function () { | ||
assert.equal(-1, d3.select(paths[3]).attr('d').indexOf('NaN')) | ||
assert.equal(-1, d3.select(paths[3]).attr('d').indexOf('NaN')); | ||
}); | ||
it('should not error when bottomWidth is equal to 100%', function () { | ||
var paths; | ||
getFunnel().draw([ | ||
@@ -353,5 +407,2 @@ ['A', 1], | ||
}); | ||
paths = d3.selectAll('#funnel path')[0]; | ||
}); | ||
@@ -362,2 +413,4 @@ }); | ||
it('should use a function\'s return value', function () { | ||
var paths; | ||
getFunnel().draw([ | ||
@@ -387,2 +440,4 @@ ['A', 1], | ||
it('should use an array\'s return value', function () { | ||
var paths; | ||
getFunnel().draw([ | ||
@@ -544,4 +599,4 @@ ['A', 1], | ||
return label + '/' + value + '/' + fValue; | ||
} | ||
} | ||
}, | ||
}, | ||
}); | ||
@@ -582,4 +637,19 @@ | ||
}); | ||
it('should not trigger when null', function () { | ||
var event = document.createEvent('CustomEvent'); | ||
event.initCustomEvent('click', false, false, null); | ||
getFunnel().draw(getBasicData(), { | ||
events: { | ||
click: { | ||
block: null, | ||
}, | ||
}, | ||
}); | ||
d3.select('#funnel path').node().dispatchEvent(event); | ||
}); | ||
}); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
97832
22
2651
189
18