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.3 to 0.7.4

src/index.js

11

CHANGELOG.md

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

## v0.7.4 (December 11, 2015)
## Build Changes
* [#42]: Use ES6 imports and exports in source files
* [#43]: Require D3.js for CommonJS environments
## v0.7.3 (skipped)
D3Funnel v0.7.3 is an NPM-only hotfix that adds in missing compiled files.
## v0.7.2 (November 18, 2015)

@@ -2,0 +13,0 @@

2017

dist/d3-funnel.js

@@ -0,1203 +1,1344 @@

(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory(require("d3"));
else if(typeof define === 'function' && define.amd)
define(["d3"], factory);
else if(typeof exports === 'object')
exports["D3Funnel"] = factory(require("d3"));
else
root["D3Funnel"] = factory(root["d3"]);
})(this, function(__WEBPACK_EXTERNAL_MODULE_2__) {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
(function(root, factory) {
if (typeof define === 'function' && define.amd) {
define(["d3"], factory);
} else if (typeof exports === 'object') {
module.exports = factory(require('d3'));
} else {
root.D3Funnel = factory(root.d3);
}
}(this, function(d3) {
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
'use strict';
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
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; }; })();
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
function _typeof(obj) { return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj; }
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/* global d3, Colorizer, LabelFormatter, Navigator, Utils */
/* exported D3Funnel */
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
var D3Funnel = (function () {
/**
* @param {string} selector A selector for the container element.
*
* @return {void}
*/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
function D3Funnel(selector) {
_classCallCheck(this, D3Funnel);
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
this.selector = selector;
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
this.colorizer = new Colorizer();
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {
this.labelFormatter = new LabelFormatter();
'use strict';
this.navigator = new Navigator();
}
// Use CommonJS export to trick Webpack into working around the issues that
// window.[module].default is set rather than window.[module]
//
// See: https://github.com/webpack/webpack/issues/706
/**
* Remove the funnel and its events from the DOM.
*
* @return {void}
*/
module.exports = __webpack_require__(1).default;
_createClass(D3Funnel, [{
key: 'destroy',
value: function destroy() {
var container = d3.select(this.selector);
/***/ },
/* 1 */
/***/ function(module, exports, __webpack_require__) {
// D3's remove method appears to be sufficient for removing the events
container.selectAll('svg').remove();
'use strict';
// Remove other elements from container
container.selectAll('*').remove();
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; }; })();
// Remove inner text from container
container.text('');
}
Object.defineProperty(exports, "__esModule", {
value: true
});
/**
* Draw the chart inside the container with the data and configuration
* specified. This will remove any previous SVG elements in the container
* and draw a new funnel chart on top of it.
*
* @param {Array} data A list of rows containing a category, a count,
* and optionally a color (in hex).
* @param {Object} options An optional configuration object to override
* defaults. See the docs.
*
* @return {void}
*/
var _d = __webpack_require__(2);
}, {
key: 'draw',
value: function draw(data) {
var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
var _d2 = _interopRequireDefault(_d);
this.destroy();
var _colorizer = __webpack_require__(3);
this._initialize(data, options);
var _colorizer2 = _interopRequireDefault(_colorizer);
this._draw();
}
var _labelFormatter = __webpack_require__(4);
/**
* Initialize and calculate important variables for drawing the chart.
*
* @param {Array} data
* @param {Object} options
*
* @return {void}
*/
var _labelFormatter2 = _interopRequireDefault(_labelFormatter);
}, {
key: '_initialize',
value: function _initialize(data, options) {
this._validateData(data);
var _navigator = __webpack_require__(5);
var settings = this._getSettings(options);
var _navigator2 = _interopRequireDefault(_navigator);
// Set labels
this.label = settings.label;
this.labelFormatter.setFormat(this.label.format);
var _utils = __webpack_require__(6);
// Set color scales
this.colorizer.setLabelFill(settings.label.fill);
this.colorizer.setScale(settings.block.fill.scale);
var _utils2 = _interopRequireDefault(_utils);
// Initialize funnel chart settings
this.width = settings.chart.width;
this.height = settings.chart.height;
this.bottomWidth = settings.chart.width * settings.chart.bottomWidth;
this.bottomPinch = settings.chart.bottomPinch;
this.isInverted = settings.chart.inverted;
this.isCurved = settings.chart.curve.enabled;
this.curveHeight = settings.chart.curve.height;
this.fillType = settings.block.fill.type;
this.hoverEffects = settings.block.highlight;
this.dynamicHeight = settings.block.dynamicHeight;
this.minHeight = settings.block.minHeight;
this.animation = settings.chart.animate;
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// Support for events
this.onBlockClick = settings.events.click.block;
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
this._setBlocks(data);
var D3Funnel = (function () {
// Calculate the bottom left x position
this.bottomLeftX = (this.width - this.bottomWidth) / 2;
/**
* @param {string} selector A selector for the container element.
*
* @return {void}
*/
// Change in x direction
this.dx = this._getDx();
function D3Funnel(selector) {
_classCallCheck(this, D3Funnel);
// Change in y direction
this.dy = this._getDy();
this.selector = selector;
this.colorizer = new _colorizer2.default();
this.labelFormatter = new _labelFormatter2.default();
this.navigator = new _navigator2.default();
}
/**
* @param {Array} data
*
* @return void
*/
* Remove the funnel and its events from the DOM.
*
* @return {void}
*/
}, {
key: '_validateData',
value: function _validateData(data) {
if (Array.isArray(data) === false) {
throw new Error('Data must be an array.');
}
_createClass(D3Funnel, [{
key: 'destroy',
value: function destroy() {
var container = _d2.default.select(this.selector);
if (data.length === 0) {
throw new Error('Data array must contain at least one element.');
}
// D3's remove method appears to be sufficient for removing the events
container.selectAll('svg').remove();
if (Array.isArray(data[0]) === false) {
throw new Error('Data array elements must be arrays.');
}
// Remove other elements from container
container.selectAll('*').remove();
if (data[0].length < 2) {
throw new Error('Data array elements must contain a label and value.');
// Remove inner text from container
container.text('');
}
}
/**
* @param {Object} options
*
* @returns {Object}
*/
/**
* Draw the chart inside the container with the data and configuration
* specified. This will remove any previous SVG elements in the container
* and draw a new funnel chart on top of it.
*
* @param {Array} data A list of rows containing a category, a count,
* and optionally a color (in hex).
* @param {Object} options An optional configuration object to override
* defaults. See the docs.
*
* @return {void}
*/
}, {
key: '_getSettings',
value: function _getSettings(options) {
// Prepare the configuration settings based on the defaults
// Set the default width and height based on the container
var settings = Utils.extend({}, D3Funnel.defaults);
settings.chart.width = parseInt(d3.select(this.selector).style('width'), 10);
settings.chart.height = parseInt(d3.select(this.selector).style('height'), 10);
}, {
key: 'draw',
value: function draw(data) {
var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
// Overwrite default settings with user options
settings = Utils.extend(settings, options);
this.destroy();
// In the case that the width or height is not valid, set
// the width/height as its default hard-coded value
if (settings.chart.width <= 0) {
settings.chart.width = D3Funnel.defaults.chart.width;
this._initialize(data, options);
this._draw();
}
if (settings.chart.height <= 0) {
settings.chart.height = D3Funnel.defaults.chart.height;
}
return settings;
}
/**
* Initialize and calculate important variables for drawing the chart.
*
* @param {Array} data
* @param {Object} options
*
* @return {void}
*/
/**
* Register the raw data into a standard block format and pre-calculate
* some values.
*
* @param {Array} data
*
* @return void
*/
}, {
key: '_initialize',
value: function _initialize(data, options) {
this._validateData(data);
}, {
key: '_setBlocks',
value: function _setBlocks(data) {
var totalCount = this._getTotalCount(data);
var settings = this._getSettings(options);
this.blocks = this._standardizeData(data, totalCount);
}
// Set labels
this.label = settings.label;
this.labelFormatter.setFormat(this.label.format);
/**
* Return the total count of all blocks.
*
* @return {Number}
*/
// Set color scales
this.colorizer.setLabelFill(settings.label.fill);
this.colorizer.setScale(settings.block.fill.scale);
}, {
key: '_getTotalCount',
value: function _getTotalCount(data) {
var _this = this;
// Initialize funnel chart settings
this.width = settings.chart.width;
this.height = settings.chart.height;
this.bottomWidth = settings.chart.width * settings.chart.bottomWidth;
this.bottomPinch = settings.chart.bottomPinch;
this.isInverted = settings.chart.inverted;
this.isCurved = settings.chart.curve.enabled;
this.curveHeight = settings.chart.curve.height;
this.fillType = settings.block.fill.type;
this.hoverEffects = settings.block.highlight;
this.dynamicHeight = settings.block.dynamicHeight;
this.minHeight = settings.block.minHeight;
this.animation = settings.chart.animate;
var total = 0;
// Support for events
this.onBlockClick = settings.events.click.block;
data.forEach(function (block) {
total += _this._getRawBlockCount(block);
});
this._setBlocks(data);
return total;
}
// Calculate the bottom left x position
this.bottomLeftX = (this.width - this.bottomWidth) / 2;
/**
* Convert the raw data into a standardized format.
*
* @param {Array} data
* @param {Number} totalCount
*
* @return {Array}
*/
// Change in x direction
this.dx = this._getDx();
}, {
key: '_standardizeData',
value: function _standardizeData(data, totalCount) {
var _this2 = this;
// Change in y direction
this.dy = this._getDy();
}
var standardized = [];
/**
* @param {Array} data
*
* @return void
*/
var count = undefined;
var ratio = undefined;
var label = undefined;
}, {
key: '_validateData',
value: function _validateData(data) {
if (Array.isArray(data) === false) {
throw new Error('Data must be an array.');
}
data.forEach(function (block, index) {
count = _this2._getRawBlockCount(block);
ratio = count / totalCount;
label = block[0];
if (data.length === 0) {
throw new Error('Data array must contain at least one element.');
}
standardized.push({
index: index,
value: count,
ratio: ratio,
height: _this2.height * ratio,
fill: _this2.colorizer.getBlockFill(block, index, _this2.fillType),
label: {
raw: label,
formatted: _this2.labelFormatter.format(label, count),
color: _this2.colorizer.getLabelFill(block)
}
});
});
if (Array.isArray(data[0]) === false) {
throw new Error('Data array elements must be arrays.');
}
return standardized;
}
if (data[0].length < 2) {
throw new Error('Data array elements must contain a label and value.');
}
}
/**
* Given a raw data block, return its count.
*
* @param {Array} block
*
* @return {Number}
*/
/**
* @param {Object} options
*
* @returns {Object}
*/
}, {
key: '_getRawBlockCount',
value: function _getRawBlockCount(block) {
return Array.isArray(block[1]) ? block[1][0] : block[1];
}
}, {
key: '_getSettings',
value: function _getSettings(options) {
// Prepare the configuration settings based on the defaults
// Set the default width and height based on the container
var settings = _utils2.default.extend({}, D3Funnel.defaults);
settings.chart.width = parseInt(_d2.default.select(this.selector).style('width'), 10);
settings.chart.height = parseInt(_d2.default.select(this.selector).style('height'), 10);
/**
* @return {Number}
*/
// Overwrite default settings with user options
settings = _utils2.default.extend(settings, options);
}, {
key: '_getDx',
value: function _getDx() {
// Will be sharper if there is a pinch
if (this.bottomPinch > 0) {
return this.bottomLeftX / (this.blocks.length - this.bottomPinch);
// In the case that the width or height is not valid, set
// the width/height as its default hard-coded value
if (settings.chart.width <= 0) {
settings.chart.width = D3Funnel.defaults.chart.width;
}
if (settings.chart.height <= 0) {
settings.chart.height = D3Funnel.defaults.chart.height;
}
return settings;
}
return this.bottomLeftX / this.blocks.length;
}
/**
* Register the raw data into a standard block format and pre-calculate
* some values.
*
* @param {Array} data
*
* @return void
*/
/**
* @return {Number}
*/
}, {
key: '_setBlocks',
value: function _setBlocks(data) {
var totalCount = this._getTotalCount(data);
}, {
key: '_getDy',
value: function _getDy() {
// Curved chart needs reserved pixels to account for curvature
if (this.isCurved) {
return (this.height - this.curveHeight) / this.blocks.length;
this.blocks = this._standardizeData(data, totalCount);
}
return this.height / this.blocks.length;
}
/**
* Return the total count of all blocks.
*
* @return {Number}
*/
/**
* Draw the chart onto the DOM.
*
* @return {void}
*/
}, {
key: '_getTotalCount',
value: function _getTotalCount(data) {
var _this = this;
}, {
key: '_draw',
value: function _draw() {
// Add the SVG
this.svg = d3.select(this.selector).append('svg').attr('width', this.width).attr('height', this.height);
var total = 0;
this.blockPaths = this._makePaths();
data.forEach(function (block) {
total += _this._getRawBlockCount(block);
});
// Define color gradients
if (this.fillType === 'gradient') {
this._defineColorGradients(this.svg);
return total;
}
// Add top oval if curved
if (this.isCurved) {
this._drawTopOval(this.svg, this.blockPaths);
}
/**
* Convert the raw data into a standardized format.
*
* @param {Array} data
* @param {Number} totalCount
*
* @return {Array}
*/
// Add each block
this._drawBlock(0);
}
}, {
key: '_standardizeData',
value: function _standardizeData(data, totalCount) {
var _this2 = this;
/**
* Create the paths to be used to define the discrete funnel blocks and
* returns the results in an array.
*
* @return {Array}
*/
var standardized = [];
}, {
key: '_makePaths',
value: function _makePaths() {
var _this3 = this;
var count = undefined;
var ratio = undefined;
var label = undefined;
var paths = [];
data.forEach(function (block, index) {
count = _this2._getRawBlockCount(block);
ratio = count / totalCount;
label = block[0];
// Initialize velocity
var dx = this.dx;
var dy = this.dy;
standardized.push({
index: index,
value: count,
ratio: ratio,
height: _this2.height * ratio,
fill: _this2.colorizer.getBlockFill(block, index, _this2.fillType),
label: {
raw: label,
formatted: _this2.labelFormatter.format(label, count),
color: _this2.colorizer.getLabelFill(block)
}
});
});
// Initialize starting positions
var prevLeftX = 0;
var prevRightX = this.width;
var prevHeight = 0;
return standardized;
}
// Start from the bottom for inverted
if (this.isInverted) {
prevLeftX = this.bottomLeftX;
prevRightX = this.width - this.bottomLeftX;
/**
* Given a raw data block, return its count.
*
* @param {Array} block
*
* @return {Number}
*/
}, {
key: '_getRawBlockCount',
value: function _getRawBlockCount(block) {
return Array.isArray(block[1]) ? block[1][0] : block[1];
}
// Initialize next positions
var nextLeftX = 0;
var nextRightX = 0;
var nextHeight = 0;
/**
* @return {Number}
*/
var middle = this.width / 2;
}, {
key: '_getDx',
value: function _getDx() {
// Will be sharper if there is a pinch
if (this.bottomPinch > 0) {
return this.bottomLeftX / (this.blocks.length - this.bottomPinch);
}
// Move down if there is an initial curve
if (this.isCurved) {
prevHeight = 10;
return this.bottomLeftX / this.blocks.length;
}
var totalHeight = this.height;
/**
* @return {Number}
*/
// This is greedy in that the block will have a guaranteed height
// and the remaining is shared among the ratio, instead of being
// shared according to the remaining minus the guaranteed
if (this.minHeight !== 0) {
totalHeight = this.height - this.minHeight * this.blocks.length;
}, {
key: '_getDy',
value: function _getDy() {
// Curved chart needs reserved pixels to account for curvature
if (this.isCurved) {
return (this.height - this.curveHeight) / this.blocks.length;
}
return this.height / this.blocks.length;
}
var slopeHeight = this.height;
/**
* Draw the chart onto the DOM.
*
* @return {void}
*/
// Correct slope height if there are blocks being pinched (and thus
// requiring a sharper curve)
this.blocks.forEach(function (block, i) {
if (_this3.bottomPinch > 0) {
if (_this3.isInverted) {
if (i < _this3.bottomPinch) {
slopeHeight -= block.height;
}
} else if (i >= _this3.blocks.length - _this3.bottomPinch) {
slopeHeight -= block.height;
}
}, {
key: '_draw',
value: function _draw() {
// Add the SVG
this.svg = _d2.default.select(this.selector).append('svg').attr('width', this.width).attr('height', this.height);
this.blockPaths = this._makePaths();
// Define color gradients
if (this.fillType === 'gradient') {
this._defineColorGradients(this.svg);
}
});
// The slope will determine the where the x points on each block
// iteration
var slope = 2 * slopeHeight / (this.width - this.bottomWidth);
// Add top oval if curved
if (this.isCurved) {
this._drawTopOval(this.svg, this.blockPaths);
}
// Create the path definition for each funnel block
// Remember to loop back to the beginning point for a closed path
this.blocks.forEach(function (block, i) {
// Make heights proportional to block weight
if (_this3.dynamicHeight) {
// Slice off the height proportional to this block
dy = totalHeight * block.ratio;
// Add each block
this._drawBlock(0);
}
// Add greedy minimum height
if (_this3.minHeight !== 0) {
dy += _this3.minHeight;
}
/**
* Create the paths to be used to define the discrete funnel blocks and
* returns the results in an array.
*
* @return {Array}
*/
// Account for any curvature
if (_this3.isCurved) {
dy = dy - _this3.curveHeight / _this3.blocks.length;
}
}, {
key: '_makePaths',
value: function _makePaths() {
var _this3 = this;
// Given: y = mx + b
// Given: b = 0 (when funnel), b = this.height (when pyramid)
// For funnel, x_i = y_i / slope
nextLeftX = (prevHeight + dy) / slope;
var paths = [];
// For pyramid, x_i = y_i - this.height / -slope
if (_this3.isInverted) {
nextLeftX = (prevHeight + dy - _this3.height) / (-1 * slope);
}
// Initialize velocity
var dx = this.dx;
var dy = this.dy;
// If bottomWidth is 0, adjust last x position (to circumvent
// errors associated with rounding)
if (_this3.bottomWidth === 0 && i === _this3.blocks.length - 1) {
// For funnel, last position is the center
nextLeftX = _this3.width / 2;
// Initialize starting positions
var prevLeftX = 0;
var prevRightX = this.width;
var prevHeight = 0;
// For pyramid, last position is the origin
// Start from the bottom for inverted
if (this.isInverted) {
prevLeftX = this.bottomLeftX;
prevRightX = this.width - this.bottomLeftX;
}
// Initialize next positions
var nextLeftX = 0;
var nextRightX = 0;
var nextHeight = 0;
var middle = this.width / 2;
// Move down if there is an initial curve
if (this.isCurved) {
prevHeight = 10;
}
var totalHeight = this.height;
// This is greedy in that the block will have a guaranteed height
// and the remaining is shared among the ratio, instead of being
// shared according to the remaining minus the guaranteed
if (this.minHeight !== 0) {
totalHeight = this.height - this.minHeight * this.blocks.length;
}
var slopeHeight = this.height;
// Correct slope height if there are blocks being pinched (and thus
// requiring a sharper curve)
this.blocks.forEach(function (block, i) {
if (_this3.bottomPinch > 0) {
if (_this3.isInverted) {
nextLeftX = 0;
if (i < _this3.bottomPinch) {
slopeHeight -= block.height;
}
} else if (i >= _this3.blocks.length - _this3.bottomPinch) {
slopeHeight -= block.height;
}
}
});
// If bottomWidth is same as width, stop x velocity
if (_this3.bottomWidth === _this3.width) {
nextLeftX = prevLeftX;
}
// The slope will determine the where the x points on each block
// iteration
var slope = 2 * slopeHeight / (this.width - this.bottomWidth);
// Calculate the shift necessary for both x points
dx = nextLeftX - prevLeftX;
// Create the path definition for each funnel block
// Remember to loop back to the beginning point for a closed path
this.blocks.forEach(function (block, i) {
// Make heights proportional to block weight
if (_this3.dynamicHeight) {
// Slice off the height proportional to this block
dy = totalHeight * block.ratio;
if (_this3.isInverted) {
dx = prevLeftX - nextLeftX;
}
}
// Add greedy minimum height
if (_this3.minHeight !== 0) {
dy += _this3.minHeight;
}
// Stop velocity for pinched blocks
if (_this3.bottomPinch > 0) {
// Check if we've reached the bottom of the pinch
// If so, stop changing on x
if (!_this3.isInverted) {
if (i >= _this3.blocks.length - _this3.bottomPinch) {
dx = 0;
// Account for any curvature
if (_this3.isCurved) {
dy = dy - _this3.curveHeight / _this3.blocks.length;
}
// Pinch at the first blocks relating to the bottom pinch
// Revert back to normal velocity after pinch
} else {
// Revert velocity back to the initial if we are using
// static area's (prevents zero velocity if isInverted
// and bottomPinch are non trivial and dynamicHeight is
// false)
if (!_this3.dynamicHeight) {
dx = _this3.dx;
// Given: y = mx + b
// Given: b = 0 (when funnel), b = this.height (when pyramid)
// For funnel, x_i = y_i / slope
nextLeftX = (prevHeight + dy) / slope;
// For pyramid, x_i = y_i - this.height / -slope
if (_this3.isInverted) {
nextLeftX = (prevHeight + dy - _this3.height) / (-1 * slope);
}
// If bottomWidth is 0, adjust last x position (to circumvent
// errors associated with rounding)
if (_this3.bottomWidth === 0 && i === _this3.blocks.length - 1) {
// For funnel, last position is the center
nextLeftX = _this3.width / 2;
// For pyramid, last position is the origin
if (_this3.isInverted) {
nextLeftX = 0;
}
}
dx = i < _this3.bottomPinch ? 0 : dx;
// If bottomWidth is same as width, stop x velocity
if (_this3.bottomWidth === _this3.width) {
nextLeftX = prevLeftX;
}
}
// Calculate the position of next block
nextLeftX = prevLeftX + dx;
nextRightX = prevRightX - dx;
nextHeight = prevHeight + dy;
// Calculate the shift necessary for both x points
dx = nextLeftX - prevLeftX;
// Expand outward if inverted
if (_this3.isInverted) {
nextLeftX = prevLeftX - dx;
nextRightX = prevRightX + dx;
}
if (_this3.isInverted) {
dx = prevLeftX - nextLeftX;
}
}
// Plot curved lines
if (_this3.isCurved) {
paths.push([
// Top Bezier curve
[prevLeftX, prevHeight, 'M'], [middle, prevHeight + (_this3.curveHeight - 10), 'Q'], [prevRightX, prevHeight, ''],
// Right line
[nextRightX, nextHeight, 'L'],
// Bottom Bezier curve
[nextRightX, nextHeight, 'M'], [middle, nextHeight + _this3.curveHeight, 'Q'], [nextLeftX, nextHeight, ''],
// Left line
[prevLeftX, prevHeight, 'L']]);
// Plot straight lines
} else {
// Stop velocity for pinched blocks
if (_this3.bottomPinch > 0) {
// Check if we've reached the bottom of the pinch
// If so, stop changing on x
if (!_this3.isInverted) {
if (i >= _this3.blocks.length - _this3.bottomPinch) {
dx = 0;
}
// Pinch at the first blocks relating to the bottom pinch
// Revert back to normal velocity after pinch
} else {
// Revert velocity back to the initial if we are using
// static area's (prevents zero velocity if isInverted
// and bottomPinch are non trivial and dynamicHeight is
// false)
if (!_this3.dynamicHeight) {
dx = _this3.dx;
}
dx = i < _this3.bottomPinch ? 0 : dx;
}
}
// Calculate the position of next block
nextLeftX = prevLeftX + dx;
nextRightX = prevRightX - dx;
nextHeight = prevHeight + dy;
// Expand outward if inverted
if (_this3.isInverted) {
nextLeftX = prevLeftX - dx;
nextRightX = prevRightX + dx;
}
// Plot curved lines
if (_this3.isCurved) {
paths.push([
// Start position
[prevLeftX, prevHeight, 'M'],
// Move to right
[prevRightX, prevHeight, 'L'],
// Move down
// Top Bezier curve
[prevLeftX, prevHeight, 'M'], [middle, prevHeight + (_this3.curveHeight - 10), 'Q'], [prevRightX, prevHeight, ''],
// Right line
[nextRightX, nextHeight, 'L'],
// Move to left
[nextLeftX, nextHeight, 'L'],
// Wrap back to top
// Bottom Bezier curve
[nextRightX, nextHeight, 'M'], [middle, nextHeight + _this3.curveHeight, 'Q'], [nextLeftX, nextHeight, ''],
// Left line
[prevLeftX, prevHeight, 'L']]);
}
// Plot straight lines
} else {
paths.push([
// Start position
[prevLeftX, prevHeight, 'M'],
// Move to right
[prevRightX, prevHeight, 'L'],
// Move down
[nextRightX, nextHeight, 'L'],
// Move to left
[nextLeftX, nextHeight, 'L'],
// Wrap back to top
[prevLeftX, prevHeight, 'L']]);
}
// Set the next block's previous position
prevLeftX = nextLeftX;
prevRightX = nextRightX;
prevHeight = nextHeight;
});
// Set the next block's previous position
prevLeftX = nextLeftX;
prevRightX = nextRightX;
prevHeight = nextHeight;
});
return paths;
}
return paths;
}
/**
* Define the linear color gradients.
*
* @param {Object} svg
*
* @return {void}
*/
/**
* Define the linear color gradients.
*
* @param {Object} svg
*
* @return {void}
*/
}, {
key: '_defineColorGradients',
value: function _defineColorGradients(svg) {
var defs = svg.append('defs');
}, {
key: '_defineColorGradients',
value: function _defineColorGradients(svg) {
var defs = svg.append('defs');
// Create a gradient for each block
this.blocks.forEach(function (block, index) {
var color = block.fill.raw;
var shade = Colorizer.shade(color, -0.2);
// Create a gradient for each block
this.blocks.forEach(function (block, index) {
var color = block.fill.raw;
var shade = _colorizer2.default.shade(color, -0.2);
// Create linear gradient
var gradient = defs.append('linearGradient').attr({
id: 'gradient-' + index
});
// Create linear gradient
var gradient = defs.append('linearGradient').attr({
id: 'gradient-' + index
});
// Define the gradient stops
var stops = [[0, shade], [40, color], [60, color], [100, shade]];
// Define the gradient stops
var stops = [[0, shade], [40, color], [60, color], [100, shade]];
// Add the gradient stops
stops.forEach(function (stop) {
gradient.append('stop').attr({
offset: stop[0] + '%',
style: 'stop-color:' + stop[1]
// Add the gradient stops
stops.forEach(function (stop) {
gradient.append('stop').attr({
offset: stop[0] + '%',
style: 'stop-color:' + stop[1]
});
});
});
});
}
}
/**
* Draw the top oval of a curved funnel.
*
* @param {Object} svg
* @param {Array} blockPaths
*
* @return {void}
*/
/**
* Draw the top oval of a curved funnel.
*
* @param {Object} svg
* @param {Array} blockPaths
*
* @return {void}
*/
}, {
key: '_drawTopOval',
value: function _drawTopOval(svg, blockPaths) {
var leftX = 0;
var rightX = this.width;
var centerX = this.width / 2;
}, {
key: '_drawTopOval',
value: function _drawTopOval(svg, blockPaths) {
var leftX = 0;
var rightX = this.width;
var centerX = this.width / 2;
if (this.isInverted) {
leftX = this.bottomLeftX;
rightX = this.width - this.bottomLeftX;
if (this.isInverted) {
leftX = this.bottomLeftX;
rightX = this.width - this.bottomLeftX;
}
// Create path from top-most block
var paths = blockPaths[0];
var topCurve = paths[1][1] + this.curveHeight - 10;
var path = this.navigator.plot([['M', leftX, paths[0][1]], ['Q', centerX, topCurve], [' ', rightX, paths[2][1]], ['M', rightX, 10], ['Q', centerX, 0], [' ', leftX, 10]]);
// Draw top oval
svg.append('path').attr('fill', _colorizer2.default.shade(this.blocks[0].fill.raw, -0.4)).attr('d', path);
}
// Create path from top-most block
var paths = blockPaths[0];
var topCurve = paths[1][1] + this.curveHeight - 10;
/**
* Draw the next block in the iteration.
*
* @param {int} index
*
* @return {void}
*/
var path = this.navigator.plot([['M', leftX, paths[0][1]], ['Q', centerX, topCurve], [' ', rightX, paths[2][1]], ['M', rightX, 10], ['Q', centerX, 0], [' ', leftX, 10]]);
}, {
key: '_drawBlock',
value: function _drawBlock(index) {
var _this4 = this;
// Draw top oval
svg.append('path').attr('fill', Colorizer.shade(this.blocks[0].fill.raw, -0.4)).attr('d', path);
}
if (index === this.blocks.length) {
return;
}
/**
* Draw the next block in the iteration.
*
* @param {int} index
*
* @return {void}
*/
// Create a group just for this block
var group = this.svg.append('g');
}, {
key: '_drawBlock',
value: function _drawBlock(index) {
var _this4 = this;
// Fetch path element
var path = this._getBlockPath(group, index);
path.data(this._getD3Data(index));
if (index === this.blocks.length) {
return;
// Add animation components
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 () {
_this4._drawBlock(index + 1);
});
} else {
path.attr('fill', this.blocks[index].fill.actual).attr('d', this._getPathDefinition(index));
this._drawBlock(index + 1);
}
// Add the hover events
if (this.hoverEffects) {
path.on('mouseover', this._onMouseOver).on('mouseout', this._onMouseOut);
}
// Add block click event
if (this.onBlockClick !== null) {
path.on('click', this.onBlockClick);
}
this._addBlockLabel(group, index);
}
// Create a group just for this block
var group = this.svg.append('g');
/**
* @param {Object} group
* @param {int} index
*
* @return {Object}
*/
// Fetch path element
var path = this._getBlockPath(group, index);
path.data(this._getD3Data(index));
}, {
key: '_getBlockPath',
value: function _getBlockPath(group, index) {
var path = group.append('path');
// Add animation components
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 () {
_this4._drawBlock(index + 1);
});
} else {
path.attr('fill', this.blocks[index].fill.actual).attr('d', this._getPathDefinition(index));
this._drawBlock(index + 1);
if (this.animation !== 0) {
this._addBeforeTransition(path, index);
}
return path;
}
// Add the hover events
if (this.hoverEffects) {
path.on('mouseover', this._onMouseOver).on('mouseout', this._onMouseOut);
/**
* Set the attributes of a path element before its animation.
*
* @param {Object} path
* @param {int} index
*
* @return {void}
*/
}, {
key: '_addBeforeTransition',
value: function _addBeforeTransition(path, index) {
var paths = this.blockPaths[index];
var beforePath = '';
var beforeFill = '';
// Construct the top of the trapezoid and leave the other elements
// hovering around to expand downward on animation
if (!this.isCurved) {
beforePath = this.navigator.plot([['M', paths[0][0], paths[0][1]], ['L', paths[1][0], paths[1][1]], ['L', paths[1][0], paths[1][1]], ['L', paths[0][0], paths[0][1]]]);
} else {
beforePath = this.navigator.plot([['M', paths[0][0], paths[0][1]], ['Q', paths[1][0], paths[1][1]], [' ', paths[2][0], paths[2][1]], ['L', paths[2][0], paths[2][1]], ['M', paths[2][0], paths[2][1]], ['Q', paths[1][0], paths[1][1]], [' ', paths[0][0], paths[0][1]]]);
}
// Use previous fill color, if available
if (this.fillType === 'solid' && index > 0) {
beforeFill = this.blocks[index - 1].fill.actual;
// Otherwise use current background
} else {
beforeFill = this.blocks[index].fill.actual;
}
path.attr('d', beforePath).attr('fill', beforeFill);
}
// Add block click event
if (this.onBlockClick !== null) {
path.on('click', this.onBlockClick);
/**
* Return d3 formatted data for the given block.
*
* @param {int} index
*
* @return {Array}
*/
}, {
key: '_getD3Data',
value: function _getD3Data(index) {
return [this.blocks[index]];
}
this._addBlockLabel(group, index);
}
/**
* @param {int} index
*
* @return {string}
*/
/**
* @param {Object} group
* @param {int} index
*
* @return {Object}
*/
}, {
key: '_getPathDefinition',
value: function _getPathDefinition(index) {
var commands = [];
}, {
key: '_getBlockPath',
value: function _getBlockPath(group, index) {
var path = group.append('path');
this.blockPaths[index].forEach(function (command) {
commands.push([command[2], command[0], command[1]]);
});
if (this.animation !== 0) {
this._addBeforeTransition(path, index);
return this.navigator.plot(commands);
}
return path;
}
/**
* @param {Object} data
*
* @return {void}
*/
/**
* Set the attributes of a path element before its animation.
*
* @param {Object} path
* @param {int} index
*
* @return {void}
*/
}, {
key: '_onMouseOver',
value: function _onMouseOver(data) {
_d2.default.select(this).attr('fill', _colorizer2.default.shade(data.fill.raw, -0.2));
}
}, {
key: '_addBeforeTransition',
value: function _addBeforeTransition(path, index) {
var paths = this.blockPaths[index];
/**
* @param {Object} data
*
* @return {void}
*/
var beforePath = '';
var beforeFill = '';
}, {
key: '_onMouseOut',
value: function _onMouseOut(data) {
_d2.default.select(this).attr('fill', data.fill.actual);
}
// Construct the top of the trapezoid and leave the other elements
// hovering around to expand downward on animation
if (!this.isCurved) {
beforePath = this.navigator.plot([['M', paths[0][0], paths[0][1]], ['L', paths[1][0], paths[1][1]], ['L', paths[1][0], paths[1][1]], ['L', paths[0][0], paths[0][1]]]);
} else {
beforePath = this.navigator.plot([['M', paths[0][0], paths[0][1]], ['Q', paths[1][0], paths[1][1]], [' ', paths[2][0], paths[2][1]], ['L', paths[2][0], paths[2][1]], ['M', paths[2][0], paths[2][1]], ['Q', paths[1][0], paths[1][1]], [' ', paths[0][0], paths[0][1]]]);
/**
* @param {Object} group
* @param {int} index
* @return {void}
*/
}, {
key: '_addBlockLabel',
value: function _addBlockLabel(group, index) {
var paths = this.blockPaths[index];
var text = this.blocks[index].label.formatted;
var fill = this.blocks[index].label.color;
var x = this.width / 2; // Center the text
var y = this._getTextY(paths);
group.append('text').text(text).attr({
'x': x,
'y': y,
'text-anchor': 'middle',
'dominant-baseline': 'middle',
'fill': fill,
'pointer-events': 'none'
}).style('font-size', this.label.fontSize);
}
// Use previous fill color, if available
if (this.fillType === 'solid' && index > 0) {
beforeFill = this.blocks[index - 1].fill.actual;
// Otherwise use current background
} else {
beforeFill = this.blocks[index].fill.actual;
/**
* Returns the y position of the given label's text. This is determined by
* taking the mean of the bases.
*
* @param {Array} paths
*
* @return {Number}
*/
}, {
key: '_getTextY',
value: function _getTextY(paths) {
if (this.isCurved) {
return (paths[2][1] + paths[3][1]) / 2 + this.curveHeight / this.blocks.length;
}
path.attr('d', beforePath).attr('fill', beforeFill);
}
return (paths[1][1] + paths[2][1]) / 2;
}
}]);
/**
* Return d3 formatted data for the given block.
*
* @param {int} index
*
* @return {Array}
*/
return D3Funnel;
})();
}, {
key: '_getD3Data',
value: function _getD3Data(index) {
return [this.blocks[index]];
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: _d2.default.scale.category10().domain(_d2.default.range(0, 10)),
type: 'solid'
},
minHeight: 0,
highlight: false
},
label: {
fontSize: '14px',
fill: '#fff',
format: '{l}: {f}'
},
events: {
click: {
block: null
}
}
};
exports.default = D3Funnel;
/**
* @param {int} index
*
* @return {string}
*/
/***/ },
/* 2 */
/***/ function(module, exports) {
}, {
key: '_getPathDefinition',
value: function _getPathDefinition(index) {
var commands = [];
module.exports = __WEBPACK_EXTERNAL_MODULE_2__;
this.blockPaths[index].forEach(function (command) {
commands.push([command[2], command[0], command[1]]);
});
/***/ },
/* 3 */
/***/ function(module, exports) {
return this.navigator.plot(commands);
}
'use strict';
/**
* @param {Object} data
*
* @return {void}
*/
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; }; })();
}, {
key: '_onMouseOver',
value: function _onMouseOver(data) {
d3.select(this).attr('fill', Colorizer.shade(data.fill.raw, -0.2));
}
Object.defineProperty(exports, "__esModule", {
value: true
});
/**
* @param {Object} data
*
* @return {void}
*/
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
}, {
key: '_onMouseOut',
value: function _onMouseOut(data) {
d3.select(this).attr('fill', data.fill.actual);
var Colorizer = (function () {
function Colorizer() {
_classCallCheck(this, Colorizer);
this.hexExpression = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i;
this.labelFill = null;
this.scale = null;
}
/**
* @param {Object} group
* @param {int} index
* @return {void}
*/
* @param {string} fill
*
* @return {void}
*/
}, {
key: '_addBlockLabel',
value: function _addBlockLabel(group, index) {
var paths = this.blockPaths[index];
_createClass(Colorizer, [{
key: 'setLabelFill',
value: function setLabelFill(fill) {
this.labelFill = fill;
}
var text = this.blocks[index].label.formatted;
var fill = this.blocks[index].label.color;
/**
* @param {function|Array} scale
*
* @return {void}
*/
var x = this.width / 2; // Center the text
var y = this._getTextY(paths);
}, {
key: 'setScale',
value: function setScale(scale) {
this.scale = scale;
}
group.append('text').text(text).attr({
'x': x,
'y': y,
'text-anchor': 'middle',
'dominant-baseline': 'middle',
'fill': fill,
'pointer-events': 'none'
}).style('font-size', this.label.fontSize);
}
/**
* Given a raw data block, return an appropriate color for the block.
*
* @param {Array} block
* @param {Number} index
* @param {string} type
*
* @return {Object}
*/
/**
* Returns the y position of the given label's text. This is determined by
* taking the mean of the bases.
*
* @param {Array} paths
*
* @return {Number}
*/
}, {
key: 'getBlockFill',
value: function getBlockFill(block, index, type) {
var raw = this.getBlockRawFill(block, index);
}, {
key: '_getTextY',
value: function _getTextY(paths) {
if (this.isCurved) {
return (paths[2][1] + paths[3][1]) / 2 + this.curveHeight / this.blocks.length;
return {
raw: raw,
actual: this.getBlockActualFill(raw, index, type)
};
}
return (paths[1][1] + paths[2][1]) / 2;
}
}]);
/**
* Return the raw hex color for the block.
*
* @param {Array} block
* @param {Number} index
*
* @return {string}
*/
return D3Funnel;
})();
}, {
key: 'getBlockRawFill',
value: function getBlockRawFill(block, index) {
// Use the block's color, if set and valid
if (block.length > 2 && this.hexExpression.test(block[2])) {
return block[2];
}
/* exported Colorizer */
/* jshint bitwise: false */
// Otherwise, attempt to use the array scale
if (Array.isArray(this.scale)) {
return this.scale[index];
}
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
}
}
};
// Finally, use a functional scale
return this.scale(index);
}
var Colorizer = (function () {
function Colorizer() {
_classCallCheck(this, Colorizer);
/**
* Return the actual background for the block.
*
* @param {string} raw
* @param {Number} index
* @param {string} type
*
* @return {string}
*/
this.hexExpression = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i;
}, {
key: 'getBlockActualFill',
value: function getBlockActualFill(raw, index, type) {
if (type === 'solid') {
return raw;
}
this.labelFill = null;
return 'url(#gradient-' + index + ')';
}
this.scale = null;
}
/**
* Given a raw data block, return an appropriate label color.
*
* @param {Array} block
*
* @return {string}
*/
/**
* @param {string} fill
*
* @return {void}
*/
}, {
key: 'getLabelFill',
value: function getLabelFill(block) {
// Use the label's color, if set and valid
if (block.length > 3 && this.hexExpression.test(block[3])) {
return block[3];
}
_createClass(Colorizer, [{
key: 'setLabelFill',
value: function setLabelFill(fill) {
this.labelFill = fill;
}
return this.labelFill;
}
/**
* @param {function|Array} scale
*
* @return {void}
*/
/**
* Shade a color to the given percentage.
*
* @param {string} color A hex color.
* @param {number} shade The shade adjustment. Can be positive or negative.
*
* @return {string}
*/
}, {
key: 'setScale',
value: function setScale(scale) {
this.scale = scale;
}
}], [{
key: 'shade',
value: function shade(color, _shade) {
var hex = color.slice(1);
/**
* Given a raw data block, return an appropriate color for the block.
*
* @param {Array} block
* @param {Number} index
* @param {string} type
*
* @return {Object}
*/
if (hex.length === 3) {
hex = Colorizer.expandHex(hex);
}
}, {
key: 'getBlockFill',
value: function getBlockFill(block, index, type) {
var raw = this.getBlockRawFill(block, index);
var f = parseInt(hex, 16);
var t = _shade < 0 ? 0 : 255;
var p = _shade < 0 ? _shade * -1 : _shade;
return {
raw: raw,
actual: this.getBlockActualFill(raw, index, type)
};
}
var R = f >> 16;
var G = f >> 8 & 0x00FF;
var B = f & 0x0000FF;
/**
* Return the raw hex color for the block.
*
* @param {Array} block
* @param {Number} index
*
* @return {string}
*/
var converted = 0x1000000 + (Math.round((t - R) * p) + R) * 0x10000 + (Math.round((t - G) * p) + G) * 0x100 + (Math.round((t - B) * p) + B);
}, {
key: 'getBlockRawFill',
value: function getBlockRawFill(block, index) {
// Use the block's color, if set and valid
if (block.length > 2 && this.hexExpression.test(block[2])) {
return block[2];
return '#' + converted.toString(16).slice(1);
}
// Otherwise, attempt to use the array scale
if (Array.isArray(this.scale)) {
return this.scale[index];
}
/**
* Expands a three character hex code to six characters.
*
* @param {string} hex
*
* @return {string}
*/
// Finally, use a functional scale
return this.scale(index);
}
/**
* 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;
}, {
key: 'expandHex',
value: function expandHex(hex) {
return hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
}
}]);
return 'url(#gradient-' + index + ')';
}
return Colorizer;
})();
/**
* Given a raw data block, return an appropriate label color.
*
* @param {Array} block
*
* @return {string}
*/
exports.default = Colorizer;
}, {
key: 'getLabelFill',
value: function getLabelFill(block) {
// Use the label's color, if set and valid
if (block.length > 3 && this.hexExpression.test(block[3])) {
return block[3];
}
/***/ },
/* 4 */
/***/ function(module, exports) {
return this.labelFill;
}
'use strict';
/**
* Shade a color to the given percentage.
*
* @param {string} color A hex color.
* @param {number} shade The shade adjustment. Can be positive or negative.
*
* @return {string}
*/
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; }; })();
}], [{
key: 'shade',
value: function shade(color, _shade) {
var hex = color.slice(1);
Object.defineProperty(exports, "__esModule", {
value: true
});
if (hex.length === 3) {
hex = Colorizer.expandHex(hex);
}
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var f = parseInt(hex, 16);
var t = _shade < 0 ? 0 : 255;
var p = _shade < 0 ? _shade * -1 : _shade;
var LabelFormatter = (function () {
var R = f >> 16;
var G = f >> 8 & 0x00FF;
var B = f & 0x0000FF;
/**
* Initial the formatter.
*
* @return {void}
*/
var converted = 0x1000000 + (Math.round((t - R) * p) + R) * 0x10000 + (Math.round((t - G) * p) + G) * 0x100 + (Math.round((t - B) * p) + B);
function LabelFormatter() {
_classCallCheck(this, LabelFormatter);
return '#' + converted.toString(16).slice(1);
this.expression = null;
}
/**
* Expands a three character hex code to six characters.
*
* @param {string} hex
*
* @return {string}
*/
* Register the format function.
*
* @param {string|function} format
*
* @return {void}
*/
}, {
key: 'expandHex',
value: function expandHex(hex) {
return hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
}
}]);
_createClass(LabelFormatter, [{
key: 'setFormat',
value: function setFormat(format) {
if (typeof format === 'function') {
this.formatter = format;
} else {
this.expression = format;
this.formatter = this.stringFormatter;
}
}
return Colorizer;
})();
/**
* Format the given value according to the data point or the format.
*
* @param {string} label
* @param {number} value
*
* @return string
*/
/* exported LabelFormatter */
}, {
key: 'format',
value: function format(label, value) {
// Try to use any formatted value specified through the data
// Otherwise, attempt to use the format function
if (Array.isArray(value)) {
return this.formatter(label, value[0], value[1]);
}
var LabelFormatter = (function () {
return this.formatter(label, value, null);
}
/**
* Initial the formatter.
*
* @return {void}
*/
/**
* Format the string according to a simple expression.
*
* {l}: label
* {v}: raw value
* {f}: formatted value
*
* @param {string} label
* @param {number} value
* @param {*} fValue
*
* @return {string}
*/
function LabelFormatter() {
_classCallCheck(this, LabelFormatter);
}, {
key: 'stringFormatter',
value: function stringFormatter(label, value) {
var fValue = arguments.length <= 2 || arguments[2] === undefined ? null : arguments[2];
this.expression = null;
}
var formatted = fValue;
/**
* Register the format function.
*
* @param {string|function} format
*
* @return {void}
*/
// Attempt to use supplied formatted value
// Otherwise, use the default
if (fValue === null) {
formatted = this.getDefaultFormattedValue(value);
}
_createClass(LabelFormatter, [{
key: 'setFormat',
value: function setFormat(format) {
if (typeof format === 'function') {
this.formatter = format;
} else {
this.expression = format;
this.formatter = this.stringFormatter;
return this.expression.split('{l}').join(label).split('{v}').join(value).split('{f}').join(formatted);
}
}
/**
* Format the given value according to the data point or the format.
*
* @param {string} label
* @param {number} value
*
* @return string
*/
/**
* @param {number} value
*
* @return {string}
*/
}, {
key: 'format',
value: function format(label, value) {
// Try to use any formatted value specified through the data
// Otherwise, attempt to use the format function
if (Array.isArray(value)) {
return this.formatter(label, value[0], value[1]);
}, {
key: 'getDefaultFormattedValue',
value: function getDefaultFormattedValue(value) {
return value.toLocaleString();
}
}]);
return this.formatter(label, value, null);
}
return LabelFormatter;
})();
/**
* Format the string according to a simple expression.
*
* {l}: label
* {v}: raw value
* {f}: formatted value
*
* @param {string} label
* @param {number} value
* @param {*} fValue
*
* @return {string}
*/
exports.default = LabelFormatter;
}, {
key: 'stringFormatter',
value: function stringFormatter(label, value) {
var fValue = arguments.length <= 2 || arguments[2] === undefined ? null : arguments[2];
/***/ },
/* 5 */
/***/ function(module, exports) {
var formatted = fValue;
'use strict';
// Attempt to use supplied formatted value
// Otherwise, use the default
if (fValue === null) {
formatted = this.getDefaultFormattedValue(value);
}
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; }; })();
return this.expression.split('{l}').join(label).split('{v}').join(value).split('{f}').join(formatted);
}
Object.defineProperty(exports, "__esModule", {
value: true
});
/**
* @param {number} value
*
* @return {string}
*/
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
}, {
key: 'getDefaultFormattedValue',
value: function getDefaultFormattedValue(value) {
return value.toLocaleString();
var Navigator = (function () {
function Navigator() {
_classCallCheck(this, Navigator);
}
}]);
return LabelFormatter;
})();
_createClass(Navigator, [{
key: 'plot',
/* exported Navigator */
/**
* Given a list of path commands, returns the compiled description.
*
* @param {Array} commands
*
* @returns {string}
*/
value: function plot(commands) {
var path = '';
var Navigator = (function () {
function Navigator() {
_classCallCheck(this, Navigator);
}
commands.forEach(function (command) {
path += command[0] + command[1] + ',' + command[2] + ' ';
});
_createClass(Navigator, [{
key: 'plot',
return path.replace(/ +/g, ' ').trim();
}
}]);
/**
* Given a list of path commands, returns the compiled description.
*
* @param {Array} commands
*
* @returns {string}
*/
value: function plot(commands) {
var path = '';
return Navigator;
})();
commands.forEach(function (command) {
path += command[0] + command[1] + ',' + command[2] + ' ';
});
exports.default = Navigator;
return path.replace(/ +/g, ' ').trim();
}
}]);
/***/ },
/* 6 */
/***/ function(module, exports) {
return Navigator;
})();
'use strict';
/* exported Utils */
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; }; })();
/**
* Simple utility class.
*/
Object.defineProperty(exports, "__esModule", {
value: true
});
var Utils = (function () {
function Utils() {
_classCallCheck(this, Utils);
}
function _typeof(obj) { return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj; }
_createClass(Utils, null, [{
key: 'extend',
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/**
* Extends an object with the members of another.
*
* @param {Object} a The object to be extended.
* @param {Object} b The object to clone from.
*
* @return {Object}
*/
value: function extend(a, b) {
var prop = undefined;
var Utils = (function () {
function Utils() {
_classCallCheck(this, Utils);
}
for (prop in b) {
if (b.hasOwnProperty(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]);
_createClass(Utils, null, [{
key: 'extend',
/**
* Extends an object with the members of another.
*
* @param {Object} a The object to be extended.
* @param {Object} b The object to clone from.
*
* @return {Object}
*/
value: function extend(a, b) {
var prop = undefined;
for (prop in b) {
if (b.hasOwnProperty(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]);
} else {
a[prop] = Utils.extend({}, b[prop]);
}
} else {
a[prop] = Utils.extend({}, b[prop]);
a[prop] = b[prop];
}
} else {
a[prop] = b[prop];
}
}
return a;
}
}]);
return a;
}
}]);
return Utils;
})();
return Utils;
})();
return D3Funnel;
exports.default = Utils;
}));
/***/ }
/******/ ])
});
;
/*! d3-funnel - v0.7.3 | 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){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});
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e(require("d3")):"function"==typeof define&&define.amd?define(["d3"],e):"object"==typeof exports?exports.D3Funnel=e(require("d3")):t.D3Funnel=e(t.d3)}(this,function(t){return function(t){function e(n){if(i[n])return i[n].exports;var a=i[n]={exports:{},id:n,loaded:!1};return t[n].call(a.exports,a,a.exports,e),a.loaded=!0,a.exports}var i={};return e.m=t,e.c=i,e.p="",e(0)}([function(t,e,i){"use strict";t.exports=i(1)["default"]},function(t,e,i){"use strict";function n(t){return t&&t.__esModule?t:{"default":t}}function a(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var r=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}}();Object.defineProperty(e,"__esModule",{value:!0});var o=i(2),l=n(o),s=i(3),h=n(s),u=i(4),c=n(u),f=i(5),d=n(f),v=i(6),g=n(v),b=function(){function t(e){a(this,t),this.selector=e,this.colorizer=new h["default"],this.labelFormatter=new c["default"],this.navigator=new d["default"]}return r(t,[{key:"destroy",value:function(){var t=l["default"].select(this.selector);t.selectAll("svg").remove(),t.selectAll("*").remove(),t.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=g["default"].extend({},t.defaults);return i.chart.width=parseInt(l["default"].select(this.selector).style("width"),10),i.chart.height=parseInt(l["default"].select(this.selector).style("height"),10),i=g["default"].extend(i,e),i.chart.width<=0&&(i.chart.width=t.defaults.chart.width),i.chart.height<=0&&(i.chart.height=t.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=[],a=void 0,r=void 0,o=void 0;return t.forEach(function(t,l){a=i._getRawBlockCount(t),r=a/e,o=t[0],n.push({index:l,value:a,ratio:r,height:i.height*r,fill:i.colorizer.getBlockFill(t,l,i.fillType),label:{raw:o,formatted:i.labelFormatter.format(o,a),color:i.colorizer.getLabelFill(t)}})}),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=l["default"].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,a=0,r=this.width,o=0;this.isInverted&&(a=this.bottomLeftX,r=this.width-this.bottomLeftX);var l=0,s=0,h=0,u=this.width/2;this.isCurved&&(o=10);var c=this.height;0!==this.minHeight&&(c=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&&(n=c*f.ratio,0!==t.minHeight&&(n+=t.minHeight),t.isCurved&&(n-=t.curveHeight/t.blocks.length),l=(o+n)/d,t.isInverted&&(l=(o+n-t.height)/(-1*d)),0===t.bottomWidth&&v===t.blocks.length-1&&(l=t.width/2,t.isInverted&&(l=0)),t.bottomWidth===t.width&&(l=a),i=l-a,t.isInverted&&(i=a-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=a+i,s=r-i,h=o+n,t.isInverted&&(l=a-i,s=r+i),t.isCurved?e.push([[a,o,"M"],[u,o+(t.curveHeight-10),"Q"],[r,o,""],[s,h,"L"],[s,h,"M"],[u,h+t.curveHeight,"Q"],[l,h,""],[a,o,"L"]]):e.push([[a,o,"M"],[r,o,"L"],[s,h,"L"],[l,h,"L"],[a,o,"L"]]),a=l,r=s,o=h}),e}},{key:"_defineColorGradients",value:function(t){var e=t.append("defs");this.blocks.forEach(function(t,i){var n=t.fill.raw,a=h["default"].shade(n,-.2),r=e.append("linearGradient").attr({id:"gradient-"+i}),o=[[0,a],[40,n],[60,n],[100,a]];o.forEach(function(t){r.append("stop").attr({offset:t[0]+"%",style:"stop-color:"+t[1]})})})}},{key:"_drawTopOval",value:function(t,e){var i=0,n=this.width,a=this.width/2;this.isInverted&&(i=this.bottomLeftX,n=this.width-this.bottomLeftX);var r=e[0],o=r[1][1]+this.curveHeight-10,l=this.navigator.plot([["M",i,r[0][1]],["Q",a,o],[" ",n,r[2][1]],["M",n,10],["Q",a,0],[" ",i,10]]);t.append("path").attr("fill",h["default"].shade(this.blocks[0].fill.raw,-.4)).attr("d",l)}},{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)),0!==this.animation?n.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)}):(n.attr("fill",this.blocks[t].fill.actual).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 0!==this.animation&&this._addBeforeTransition(i,e),i}},{key:"_addBeforeTransition",value:function(t,e){var i=this.blockPaths[e],n="",a="";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]]]),a="solid"===this.fillType&&e>0?this.blocks[e-1].fill.actual:this.blocks[e].fill.actual,t.attr("d",n).attr("fill",a)}},{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(t){l["default"].select(this).attr("fill",h["default"].shade(t.fill.raw,-.2))}},{key:"_onMouseOut",value:function(t){l["default"].select(this).attr("fill",t.fill.actual)}},{key:"_addBlockLabel",value:function(t,e){var i=this.blockPaths[e],n=this.blocks[e].label.formatted,a=this.blocks[e].label.color,r=this.width/2,o=this._getTextY(i);t.append("text").text(n).attr({x:r,y:o,"text-anchor":"middle","dominant-baseline":"middle",fill:a,"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}}]),t}();b.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:l["default"].scale.category10().domain(l["default"].range(0,10)),type:"solid"},minHeight:0,highlight:!1},label:{fontSize:"14px",fill:"#fff",format:"{l}: {f}"},events:{click:{block:null}}},e["default"]=b},function(e,i){e.exports=t},function(t,e){"use strict";function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var n=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}}();Object.defineProperty(e,"__esModule",{value:!0});var a=function(){function t(){i(this,t),this.hexExpression=/^#([0-9a-f]{3}|[0-9a-f]{6})$/i,this.labelFill=null,this.scale=null}return n(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 n=this.getBlockRawFill(t,e);return{raw:n,actual:this.getBlockActualFill(n,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 n=e.slice(1);3===n.length&&(n=t.expandHex(n));var a=parseInt(n,16),r=0>i?0:255,o=0>i?-1*i:i,l=a>>16,s=a>>8&255,h=255&a,u=16777216+65536*(Math.round((r-l)*o)+l)+256*(Math.round((r-s)*o)+s)+(Math.round((r-h)*o)+h);return"#"+u.toString(16).slice(1)}},{key:"expandHex",value:function(t){return t[0]+t[0]+t[1]+t[1]+t[2]+t[2]}}]),t}();e["default"]=a},function(t,e){"use strict";function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var n=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}}();Object.defineProperty(e,"__esModule",{value:!0});var a=function(){function t(){i(this,t),this.expression=null}return n(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}();e["default"]=a},function(t,e){"use strict";function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var n=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}}();Object.defineProperty(e,"__esModule",{value:!0});var a=function(){function t(){i(this,t)}return n(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}();e["default"]=a},function(t,e){"use strict";function i(t){return t&&"undefined"!=typeof Symbol&&t.constructor===Symbol?"symbol":typeof t}function n(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 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}}();Object.defineProperty(e,"__esModule",{value:!0});var r=function(){function t(){n(this,t)}return a(t,null,[{key:"extend",value:function(e,n){var a=void 0;for(a in n)n.hasOwnProperty(a)&&("object"!==i(n[a])||Array.isArray(n[a])||null===n[a]?e[a]=n[a]:"object"!==i(e[a])||Array.isArray(e[a])||null===n[a]?e[a]=t.extend({},n[a]):e[a]=t.extend(e[a],n[a]));return e}}]),t}();e["default"]=r}])});

@@ -1,11 +0,9 @@

var gulp = require('gulp');
var umd = require('gulp-wrap-umd');
var concat = require('gulp-concat');
var eslint = require('gulp-eslint');
var babel = require('gulp-babel');
var mocha = require('gulp-mocha-phantomjs');
var rename = require('gulp-rename');
var uglify = require('gulp-uglify');
var header = require('gulp-header');
var pkg = require('./package.json');
var gulp = require('gulp');
var eslint = require('gulp-eslint');
var mocha = require('gulp-mocha-phantomjs');
var rename = require('gulp-rename');
var uglify = require('gulp-uglify');
var header = require('gulp-header');
var webpack = require('webpack-stream');
var pkg = require('./package.json');

@@ -21,14 +19,5 @@ var banner = '/*! <%= pkg.name %> - v<%= pkg.version %> | <%= new Date().getFullYear() %> */\n';

];
var umdOptions = {
exports: 'D3Funnel',
namespace: 'D3Funnel',
deps: [{
name: 'd3',
globalName: 'd3',
paramName: 'd3',
}],
};
gulp.task('test-format', function () {
return gulp.src(src)
return gulp.src(['./src/d3-funnel/**/*.js'])
.pipe(eslint())

@@ -40,11 +29,4 @@ .pipe(eslint.format())

gulp.task('compile', function () {
return gulp.src(src)
.pipe(concat('d3-funnel.js'))
.pipe(babel({
presets: [
'es2015',
'stage-0',
],
}))
.pipe(umd(umdOptions))
return gulp.src(['./src/index.js'])
.pipe(webpack(require('./webpack.config.js')))
.pipe(gulp.dest('./compiled/'));

@@ -51,0 +33,0 @@ });

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

@@ -14,3 +14,5 @@ "author": "Jake Zatecky",

"devDependencies": {
"babel-core": "^6.3.17",
"babel-eslint": "^4.1.5",
"babel-loader": "^6.2.0",
"babel-preset-es2015": "^6.1.2",

@@ -21,6 +23,4 @@ "babel-preset-stage-0": "^6.1.2",

"eslint": "^1.9.0",
"eslint-config-airbnb": "^1.0.0",
"eslint-config-airbnb": "^2.0.0",
"gulp": "^3.9.0",
"gulp-babel": "^6.1.0",
"gulp-concat": "^2.6.0",
"gulp-eslint": "^1.0.0",

@@ -31,5 +31,5 @@ "gulp-header": "^1.7.1",

"gulp-uglify": "^1.4.2",
"gulp-wrap-umd": "^0.2.1",
"lodash": "^3.10.1",
"mocha": "^2.3.3"
"mocha": "^2.3.3",
"webpack-stream": "^3.0.0"
},

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

@@ -26,3 +26,4 @@ # D3 Funnel

Alternatively, if you are using Webpack or Browserify, you can install the npm
package and `require` the module:
package and `require` or `import` the module. This will include a compatible
version of D3.js for you:

@@ -34,3 +35,7 @@ ```

``` javascript
// CommonJS
var D3Funnel = require('d3-funnel');
// ES6
import D3Funnel from 'd3-funnel';
```

@@ -171,4 +176,4 @@

If you want to pass formatted values to be shown in the funnel, pass in an array
containing the value and formatted value:
In addition to using `label.format`, you can also pass formatted values in an
array:

@@ -175,0 +180,0 @@ ``` javascript

@@ -1,4 +0,1 @@

/* exported Colorizer */
/* jshint bitwise: false */
class Colorizer {

@@ -149,1 +146,3 @@

}
export default Colorizer;

@@ -1,4 +0,8 @@

/* global d3, Colorizer, LabelFormatter, Navigator, Utils */
/* exported D3Funnel */
import d3 from 'd3';
import Colorizer from './colorizer';
import LabelFormatter from './label-formatter';
import Navigator from './navigator';
import Utils from './utils';
class D3Funnel {

@@ -791,1 +795,3 @@

}
export default D3Funnel;

@@ -1,3 +0,1 @@

/* exported LabelFormatter */
class LabelFormatter {

@@ -86,1 +84,3 @@

}
export default LabelFormatter;

@@ -1,3 +0,1 @@

/* exported Navigator */
class Navigator {

@@ -23,1 +21,3 @@

}
export default Navigator;

@@ -1,6 +0,1 @@

/* exported Utils */
/**
* Simple utility class.
*/
class Utils {

@@ -37,1 +32,3 @@

}
export default Utils;

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

it('should not trigger when null', function () {
it('should not trigger errors when null', function () {
var event = document.createEvent('CustomEvent');

@@ -629,0 +629,0 @@ event.initCustomEvent('click', false, false, null);

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