Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

d3-funnel

Package Overview
Dependencies
Maintainers
1
Versions
32
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

d3-funnel - npm Package Compare versions

Comparing version 0.7.0 to 0.7.1

15

CHANGELOG.md

@@ -0,1 +1,12 @@

## v0.7.1 (October 28, 2015)
### Behavior Changes
* Errors thrown on data validation are now more descriptive and context-aware
### Bug Fixes
* [#35]: Fix issue where gradient background would not persist after mouse out
* [#36]: Fix issue where non-SVG entities were not being removed from container
## v0.7.0 (October 4, 2015)

@@ -14,3 +25,3 @@

* Heights determined by weighted area: http://jsfiddle.net/zq4L82kv/2/ (legacy v0.6.x)
* Heights determined by weighted height: http://jsfiddle.net/bawv6m0j/1/ (v0.7+)
* Heights determined by weighted height: http://jsfiddle.net/bawv6m0j/3/ (v0.7+)

@@ -37,3 +48,3 @@ ### New Features

| `bottomWidth` | `chart.bottomWidth` | |
| `curveHeight | `chart.curve.height` | |
| `curveHeight` | `chart.curve.height` | |
| `dynamicArea` | `block.dynamicHeight` | See change #29. |

@@ -40,0 +51,0 @@ | `fillType` | `block.fill.type` | |

118

dist/d3-funnel.js

@@ -90,4 +90,11 @@

value: function destroy() {
var container = d3.select(this.selector);
// D3's remove method appears to be sufficient for removing the events
d3.select(this.selector).selectAll('svg').remove();
container.selectAll('svg').remove();
// Remove other elements from container
container.selectAll('*').remove();
// Remove inner text from container
container.text('');
}

@@ -179,5 +186,17 @@

value: function _validateData(data) {
if (Array.isArray(data) === false || data.length === 0 || Array.isArray(data[0]) === false || data[0].length < 2) {
throw new Error('Funnel data is not valid.');
if (Array.isArray(data) === false) {
throw new Error('Data must be an array.');
}
if (data.length === 0) {
throw new Error('Data array must contain at least one element.');
}
if (Array.isArray(data[0]) === false) {
throw new Error('Data array elements must be arrays.');
}
if (data[0].length < 2) {
throw new Error('Data array elements must contain a label and value.');
}
}

@@ -279,3 +298,3 @@

formatted: _this2.labelFormatter.format(label, count),
fill: _this2.colorizer.getBlockFill(block, index),
fill: _this2.colorizer.getBlockFill(block, index, _this2.fillType),
label: {

@@ -565,4 +584,4 @@ raw: label,

this.blocks.forEach(function (block, index) {
var color = block.fill;
var shade = Colorizer.shade(color, -0.25);
var color = block.fill.raw;
var shade = Colorizer.shade(color, -0.2);

@@ -614,3 +633,3 @@ // Create linear gradient

// Draw top oval
svg.append('path').attr('fill', Colorizer.shade(this.blocks[0].fill, -0.4)).attr('d', path);
svg.append('path').attr('fill', Colorizer.shade(this.blocks[0].fill.raw, -0.4)).attr('d', path);
}

@@ -643,7 +662,7 @@

if (this.animation !== false) {
path.transition().duration(this.animation).ease('linear').attr('fill', this._getFillColor(index)).attr('d', this._getPathDefinition(index)).each('end', function () {
path.transition().duration(this.animation).ease('linear').attr('fill', this.blocks[index].fill.actual).attr('d', this._getPathDefinition(index)).each('end', function () {
_this4._drawBlock(index + 1);
});
} else {
path.attr('fill', this._getFillColor(index)).attr('d', this._getPathDefinition(index));
path.attr('fill', this.blocks[index].fill.actual).attr('d', this._getPathDefinition(index));
this._drawBlock(index + 1);

@@ -657,3 +676,3 @@ }

// ItemClick event
// Add block click event
if (this.onBlockClick !== null) {

@@ -710,6 +729,6 @@ path.on('click', this.onBlockClick);

if (this.fillType === 'solid' && index > 0) {
beforeFill = this._getFillColor(index - 1);
beforeFill = this.blocks[index - 1].fill.actual;
// Otherwise use current background
} else {
beforeFill = this._getFillColor(index);
beforeFill = this.blocks[index].fill.actual;
}

@@ -734,4 +753,2 @@

/**
* Return the block fill color for the given index.
*
* @param {int} index

@@ -742,17 +759,2 @@ *

}, {
key: '_getFillColor',
value: function _getFillColor(index) {
if (this.fillType === 'solid') {
return this.blocks[index].fill;
}
return 'url(#gradient-' + index + ')';
}
/**
* @param {int} index
*
* @return {string}
*/
}, {
key: '_getPathDefinition',

@@ -777,14 +779,14 @@ value: function _getPathDefinition(index) {

value: function _onMouseOver(data) {
d3.select(this).attr('fill', Colorizer.shade(data.fill, -0.2));
d3.select(this).attr('fill', Colorizer.shade(data.fill.raw, -0.2));
}
/**
* @param {Object} data
*
* @return {void}
*/
* @param {Object} data
*
* @return {void}
*/
}, {
key: '_onMouseOut',
value: function _onMouseOut(data) {
d3.select(this).attr('fill', data.fill);
d3.select(this).attr('fill', data.fill.actual);
}

@@ -795,3 +797,2 @@

* @param {int} index
*
* @return {void}

@@ -883,8 +884,28 @@ */

* @param {Number} index
* @param {string} type
*
* @return {Object}
*/
}, {
key: 'getBlockFill',
value: function getBlockFill(block, index, type) {
var raw = this.getBlockRawFill(block, index);
return {
raw: raw,
actual: this.getBlockActualFill(raw, index, type)
};
}
/**
* Return the raw hex color for the block.
*
* @param {Array} block
* @param {Number} index
*
* @return {string}
*/
}, {
key: 'getBlockFill',
value: function getBlockFill(block, index) {
key: 'getBlockRawFill',
value: function getBlockRawFill(block, index) {
// Use the block's color, if set and valid

@@ -895,2 +916,3 @@ if (block.length > 2 && this.hexExpression.test(block[2])) {

// Otherwise, attempt to use the array scale
if (Array.isArray(this.scale)) {

@@ -900,2 +922,3 @@ return this.scale[index];

// Finally, use a functional scale
return this.scale(index);

@@ -905,2 +928,21 @@ }

/**
* Return the actual background for the block.
*
* @param {string} raw
* @param {Number} index
* @param {string} type
*
* @return {string}
*/
}, {
key: 'getBlockActualFill',
value: function getBlockActualFill(raw, index, type) {
if (type === 'solid') {
return raw;
}
return 'url(#gradient-' + index + ')';
}
/**
* Given a raw data block, return an appropriate label color.

@@ -907,0 +949,0 @@ *

@@ -1,2 +0,2 @@

/*! d3-funnel - v0.7.0 | 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 n=e[i];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,i,n){return i&&t(e.prototype,i),n&&t(e,n),e}}(),n=function(){function n(t){e(this,n),this.selector=t,this.colorizer=new h,this.labelFormatter=new o,this.navigator=new a}return i(n,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(n,[{key:"destroy",value:function(){t.select(this.selector).selectAll("svg").remove()}},{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||0===t.length||Array.isArray(t[0])===!1||t[0].length<2)throw new Error("Funnel data is not valid.")}},{key:"_getSettings",value:function(e){var i=l.extend({},n.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=l.extend(i,e),i.chart.width<=0&&(i.chart.width=n.defaults.chart.width),i.chart.height<=0&&(i.chart.height=n.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,n=[],h=void 0,o=void 0,a=void 0;return t.forEach(function(t,l){h=i._getRawBlockCount(t),o=h/e,a=t[0],n.push({index:l,value:h,ratio:o,height:i.height*o,formatted:i.labelFormatter.format(a,h),fill:i.colorizer.getBlockFill(t,l),label:{raw:a,formatted:i.labelFormatter.format(a,h),color:i.colorizer.getLabelFill(t,l)}})}),n}},{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,n=this.dy,h=0,o=this.width,a=0;this.isInverted&&(h=this.bottomLeftX,o=this.width-this.bottomLeftX);var l=0,s=0,r=0,c=this.width/2;this.isCurved&&(a=10);var u=this.height;this.minHeight!==!1&&(u=this.height-this.minHeight*this.blocks.length);var d=this.height;this.blocks.forEach(function(e,i){t.bottomPinch>0&&(t.isInverted?i<t.bottomPinch&&(d-=e.height):i>=t.blocks.length-t.bottomPinch&&(d-=e.height))});var f=2*d/(this.width-this.bottomWidth);return this.blocks.forEach(function(d,v){t.dynamicHeight&&(n=u*d.ratio,t.minHeight!==!1&&(n+=t.minHeight),t.isCurved&&(n-=t.curveHeight/t.blocks.length),l=(a+n)/f,t.isInverted&&(l=(a+n-t.height)/(-1*f)),0===t.bottomWidth&&v===t.blocks.length-1&&(l=t.width/2,t.isInverted&&(l=0)),t.bottomWidth===t.width&&(l=h),i=l-h,t.isInverted&&(i=h-l)),t.bottomPinch>0&&(t.isInverted?(t.dynamicHeight||(i=t.dx),i=v<t.bottomPinch?0:i):v>=t.blocks.length-t.bottomPinch&&(i=0)),l=h+i,s=o-i,r=a+n,t.isInverted&&(l=h-i,s=o+i),t.isCurved?e.push([[h,a,"M"],[c,a+(t.curveHeight-10),"Q"],[o,a,""],[s,r,"L"],[s,r,"M"],[c,r+t.curveHeight,"Q"],[l,r,""],[h,a,"L"]]):e.push([[h,a,"M"],[o,a,"L"],[s,r,"L"],[l,r,"L"],[h,a,"L"]]),h=l,o=s,a=r}),e}},{key:"_defineColorGradients",value:function(t){var e=t.append("defs");this.blocks.forEach(function(t,i){var n=t.fill,o=h.shade(n,-.25),a=e.append("linearGradient").attr({id:"gradient-"+i}),l=[[0,o],[40,n],[60,n],[100,o]];l.forEach(function(t){a.append("stop").attr({offset:t[0]+"%",style:"stop-color:"+t[1]})})})}},{key:"_drawTopOval",value:function(t,e){var i=0,n=this.width,o=this.width/2;this.isInverted&&(i=this.bottomLeftX,n=this.width-this.bottomLeftX);var a=e[0],l=a[1][1]+this.curveHeight-10,s=this.navigator.plot([["M",i,a[0][1]],["Q",o,l],[" ",n,a[2][1]],["M",n,10],["Q",o,0],[" ",i,10]]);t.append("path").attr("fill",h.shade(this.blocks[0].fill,-.4)).attr("d",s)}},{key:"_drawBlock",value:function(t){var e=this;if(t!==this.blocks.length){var i=this.svg.append("g"),n=this._getBlockPath(i,t);n.data(this._getD3Data(t)),this.animation!==!1?n.transition().duration(this.animation).ease("linear").attr("fill",this._getFillColor(t)).attr("d",this._getPathDefinition(t)).each("end",function(){e._drawBlock(t+1)}):(n.attr("fill",this._getFillColor(t)).attr("d",this._getPathDefinition(t)),this._drawBlock(t+1)),this.hoverEffects&&n.on("mouseover",this._onMouseOver).on("mouseout",this._onMouseOut),null!==this.onBlockClick&&n.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],n="",h="";n=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]]]),h="solid"===this.fillType&&e>0?this._getFillColor(e-1):this._getFillColor(e),t.attr("d",n).attr("fill",h)}},{key:"_getD3Data",value:function(t){return[this.blocks[t]]}},{key:"_getFillColor",value:function(t){return"solid"===this.fillType?this.blocks[t].fill:"url(#gradient-"+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",h.shade(e.fill,-.2))}},{key:"_onMouseOut",value:function(e){t.select(this).attr("fill",e.fill)}},{key:"_addBlockLabel",value:function(t,e){var i=this.blockPaths[e],n=this.blocks[e].label.formatted,h=this.blocks[e].label.color,o=this.width/2,a=this._getTextY(i);t.append("text").text(n).attr({x:o,y:a,"text-anchor":"middle","dominant-baseline":"middle",fill:h,"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}}]),n}(),h=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){return t.length>2&&this.hexExpression.test(t[2])?t[2]:Array.isArray(this.scale)?this.scale[e]:this.scale(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 n=e.slice(1);3===n.length&&(n=t.expandHex(n));var h=parseInt(n,16),o=0>i?0:255,a=0>i?-1*i:i,l=h>>16,s=h>>8&255,r=255&h,c=16777216+65536*(Math.round((o-l)*a)+l)+256*(Math.round((o-s)*a)+s)+(Math.round((o-r)*a)+r);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}(),o=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],n=i;return null===i&&(n=this.getDefaultFormattedValue(e)),this.expression.split("{l}").join(t).split("{v}").join(e).split("{f}").join(n)}},{key:"getDefaultFormattedValue",value:function(t){return t.toLocaleString()}}]),t}(),a=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}(),l=function(){function t(){e(this,t)}return i(t,null,[{key:"extend",value:function(e,i){var n=void 0;for(n in i)i.hasOwnProperty(n)&&("object"!=typeof i[n]||Array.isArray(i[n])?e[n]=i[n]:"object"!=typeof e[n]||Array.isArray(e[n])?e[n]=t.extend({},i[n]):e[n]=t.extend(e[n],i[n]));return e}}]),t}();return n});
/*! 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});

@@ -0,0 +0,0 @@ The MIT License (MIT)

{
"name": "d3-funnel",
"version": "0.7.0",
"version": "0.7.1",
"description": "A library for rendering SVG funnel charts using D3.js",

@@ -15,8 +15,8 @@ "author": "Jake Zatecky",

"babel-eslint": "^4.1.3",
"chai": "^3.2.0",
"chai-spies": "^0.7.0",
"eslint": "^1.6.0",
"chai": "^3.4.0",
"chai-spies": "^0.7.1",
"eslint": "^1.7.3",
"eslint-config-airbnb": "^0.1.0",
"gulp": "^3.9.0",
"gulp-babel": "^5.2.1",
"gulp-babel": "^5.3.0",
"gulp-concat": "^2.6.0",

@@ -27,6 +27,6 @@ "gulp-eslint": "^1.0.0",

"gulp-rename": "^1.2.2",
"gulp-uglify": "^1.4.1",
"gulp-uglify": "^1.4.2",
"gulp-wrap-umd": "^0.2.1",
"lodash": "^3.10.1",
"mocha": "^2.3.2"
"mocha": "^2.3.3"
},

@@ -33,0 +33,0 @@ "dependencies": {

@@ -5,2 +5,4 @@ # D3 Funnel

[![Build Status](https://img.shields.io/travis/jakezatecky/d3-funnel/master.svg?style=flat-square)](https://travis-ci.org/jakezatecky/d3-funnel)
[![Dependency Status](https://img.shields.io/david/jakezatecky/d3-funnel.svg?style=flat-square)](https://david-dm.org/jakezatecky/d3-funnel)
[![devDependency Status](https://david-dm.org/jakezatecky/d3-funnel/dev-status.svg?style=flat-square)](https://david-dm.org/jakezatecky/d3-funnel#info=devDependencies)
[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](https://raw.githubusercontent.com/jakezatecky/d3-funnel/master/LICENSE.txt)

@@ -32,3 +34,3 @@

``` javascript
var D3Funnel = require('d3-funnel')
var D3Funnel = require('d3-funnel');
```

@@ -77,3 +79,3 @@

| `label.fill` | Any valid hex color for the label color | string | `'#fff'` |
| `label.format` | Either `function(label, value)` or a format string. See below. | mixed | `'{l}: {f}'` |
| `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` |

@@ -107,9 +109,11 @@

D3Funnel.defaults = _.merge(D3Funnel.defaults, {
chart: {
dynamicHeight: true,
animate: 200,
},
label: {
format: '{l}: ${f}',
},
block: {
dynamicHeight: true,
fill: {
type: 'gradient',
},
},
label: {
format: '{l}: ${f}',
},
});

@@ -133,6 +137,6 @@ ```

var data = [
['Teal', 12000, '#008080' '#080800'],
['Teal', 12000, '#008080', '#080800'],
['Byzantium', 4000, '#702963'],
['Persimmon', 2500, '#ff634d' '#6f34fd'],
['Azure', 1500, '#007fff' '#07fff0'],
['Persimmon', 2500, '#ff634d', '#6f34fd'],
['Azure', 1500, '#007fff', '#07fff0'],
// Background ---^ ^--- Label

@@ -139,0 +143,0 @@ ];

@@ -37,6 +37,24 @@ /* exported Colorizer */

* @param {Number} index
* @param {string} type
*
* @return {Object}
*/
getBlockFill(block, index, type) {
let raw = this.getBlockRawFill(block, index);
return {
raw: raw,
actual: this.getBlockActualFill(raw, index, type),
};
}
/**
* Return the raw hex color for the block.
*
* @param {Array} block
* @param {Number} index
*
* @return {string}
*/
getBlockFill(block, index) {
getBlockRawFill(block, index) {
// Use the block's color, if set and valid

@@ -47,2 +65,3 @@ if (block.length > 2 && this.hexExpression.test(block[2])) {

// Otherwise, attempt to use the array scale
if (Array.isArray(this.scale)) {

@@ -52,2 +71,3 @@ return this.scale[index];

// Finally, use a functional scale
return this.scale(index);

@@ -57,2 +77,19 @@ }

/**
* Return the actual background for the block.
*
* @param {string} raw
* @param {Number} index
* @param {string} type
*
* @return {string}
*/
getBlockActualFill(raw, index, type) {
if (type === 'solid') {
return raw;
}
return 'url(#gradient-' + index + ')';
}
/**
* Given a raw data block, return an appropriate label color.

@@ -59,0 +96,0 @@ *

@@ -61,4 +61,11 @@ /* global d3, Colorizer, LabelFormatter, Navigator, Utils */

destroy() {
let container = d3.select(this.selector);
// D3's remove method appears to be sufficient for removing the events
d3.select(this.selector).selectAll('svg').remove();
container.selectAll('svg').remove();
// Remove other elements from container
container.selectAll('*').remove();
// Remove inner text from container
container.text('');
}

@@ -142,8 +149,17 @@

_validateData(data) {
if (Array.isArray(data) === false ||
data.length === 0 ||
Array.isArray(data[0]) === false ||
data[0].length < 2) {
throw new Error('Funnel data is not valid.');
if (Array.isArray(data) === false) {
throw new Error('Data must be an array.');
}
if (data.length === 0) {
throw new Error('Data array must contain at least one element.');
}
if (Array.isArray(data[0]) === false) {
throw new Error('Data array elements must be arrays.');
}
if (data[0].length < 2) {
throw new Error('Data array elements must contain a label and value.');
}
}

@@ -233,3 +249,3 @@

formatted: this.labelFormatter.format(label, count),
fill: this.colorizer.getBlockFill(block, index),
fill: this.colorizer.getBlockFill(block, index, this.fillType),
label: {

@@ -514,4 +530,4 @@ raw: label,

this.blocks.forEach((block, index) => {
let color = block.fill;
let shade = Colorizer.shade(color, -0.25);
let color = block.fill.raw;
let shade = Colorizer.shade(color, -0.2);

@@ -575,3 +591,3 @@ // Create linear gradient

svg.append('path')
.attr('fill', Colorizer.shade(this.blocks[0].fill, -0.4))
.attr('fill', Colorizer.shade(this.blocks[0].fill.raw, -0.4))
.attr('d', path);

@@ -604,3 +620,3 @@ }

.ease('linear')
.attr('fill', this._getFillColor(index))
.attr('fill', this.blocks[index].fill.actual)
.attr('d', this._getPathDefinition(index))

@@ -611,3 +627,3 @@ .each('end', () => {

} else {
path.attr('fill', this._getFillColor(index))
path.attr('fill', this.blocks[index].fill.actual)
.attr('d', this._getPathDefinition(index));

@@ -623,3 +639,3 @@ this._drawBlock(index + 1);

// ItemClick event
// Add block click event
if (this.onBlockClick !== null) {

@@ -685,6 +701,6 @@ path.on('click', this.onBlockClick);

if (this.fillType === 'solid' && index > 0) {
beforeFill = this._getFillColor(index - 1);
beforeFill = this.blocks[index - 1].fill.actual;
// Otherwise use current background
} else {
beforeFill = this._getFillColor(index);
beforeFill = this.blocks[index].fill.actual;
}

@@ -708,4 +724,2 @@

/**
* Return the block fill color for the given index.
*
* @param {int} index

@@ -715,15 +729,2 @@ *

*/
_getFillColor(index) {
if (this.fillType === 'solid') {
return this.blocks[index].fill;
}
return 'url(#gradient-' + index + ')';
}
/**
* @param {int} index
*
* @return {string}
*/
_getPathDefinition(index) {

@@ -745,6 +746,6 @@ let commands = [];

_onMouseOver(data) {
d3.select(this).attr('fill', Colorizer.shade(data.fill, -0.2));
d3.select(this).attr('fill', Colorizer.shade(data.fill.raw, -0.2));
}
/**
/**
* @param {Object} data

@@ -755,3 +756,3 @@ *

_onMouseOut(data) {
d3.select(this).attr('fill', data.fill);
d3.select(this).attr('fill', data.fill.actual);
}

@@ -762,3 +763,2 @@

* @param {int} index
*
* @return {void}

@@ -765,0 +765,0 @@ */

@@ -45,3 +45,3 @@ /* global d3, assert, chai, D3Funnel */

it('should draw a chart on the identified target', function () {
getFunnel().draw(getBasicData(), {});
getFunnel().draw(getBasicData());

@@ -57,10 +57,34 @@ assert.equal(1, getSvg()[0].length);

it('should throw an exception on invalid data', function () {
it('should throw an error when the data is not an array', function () {
var funnel = getFunnel();
assert.throws(function () {
funnel.draw(['One dimensional', 2], {});
}, Error, 'Funnel data is not valid.');
funnel.draw('Not array');
}, Error, 'Data must be an array.');
});
it('should throw an error when the data array does not have an element', function () {
var funnel = getFunnel();
assert.throws(function () {
funnel.draw([]);
}, Error, 'Data array must contain at least one element.');
});
it('should throw an error when the first data array element is not an array', function () {
var funnel = getFunnel();
assert.throws(function () {
funnel.draw(['Not array']);
}, Error, 'Data array elements must be arrays.');
});
it('should throw an error when the first data array element does not have two elements', function () {
var funnel = getFunnel();
assert.throws(function () {
funnel.draw([['Only one']]);
}, Error, 'Data array elements must contain a label and value.');
});
it('should draw as many blocks as there are elements', function () {

@@ -115,2 +139,34 @@ getFunnel().draw([

});
it('should remove other elements from container', function () {
var container = d3.select('#funnel'),
funnel = getFunnel();
// Make sure the container has no children
container.selectAll('*').remove();
container.append('p');
funnel.draw(getBasicData());
var funnelChildrenSize = getSvg().selectAll('*').size(),
// expect funnel children count plus funnel itself
expected = funnelChildrenSize + 1,
actual = container.selectAll('*').size();
assert.equal(expected, actual);
});
it('should remove inner text from container', function () {
var container = d3.select('#funnel'),
funnel = getFunnel();
// Make sure the container has no text
container.text();
container.text('to be removed');
funnel.draw(getBasicData());
// Make sure the only text in container comes from the funnel
assert.equal(getSvg().text(), container.text());
});
});

@@ -122,3 +178,3 @@

funnel.draw(getBasicData(), {});
funnel.draw(getBasicData());
funnel.destroy();

@@ -135,3 +191,3 @@

getFunnel().draw(getBasicData(), {});
getFunnel().draw(getBasicData());

@@ -147,3 +203,3 @@ assert.isTrue(d3.select('#funnel text').attr('fill').indexOf('#777') > -1);

getFunnel().draw(getBasicData(), {});
getFunnel().draw(getBasicData());

@@ -168,3 +224,3 @@ assert.equal(250, getSvg().node().getBBox().width);

getFunnel().draw(getBasicData(), {});
getFunnel().draw(getBasicData());

@@ -366,3 +422,3 @@ assert.equal(250, getSvg().node().getBBox().height);

it('should use solid fill when not set to \'gradient\'', function () {
getFunnel().draw(getBasicData(), {});
getFunnel().draw(getBasicData());

@@ -369,0 +425,0 @@ // Check for valid hex string

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

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc