diff --git a/.babelrc b/.babelrc index 684fff6..9d8d516 100644 --- a/.babelrc +++ b/.babelrc @@ -1 +1 @@ -{ "presets": ["env"] } +{ "presets": ["es2015"] } diff --git a/build/webcharts.js b/build/webcharts.js index 01afe8c..baf8dad 100644 --- a/build/webcharts.js +++ b/build/webcharts.js @@ -6,73 +6,7 @@ : (global.webCharts = factory(global.d3)); })(this, function(d3) { 'use strict'; - var version = '1.11.0'; - - function init(data) { - var _this = this; - - var test = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; - - if (d3.select(this.div).select('.loader').empty()) { - d3 - .select(this.div) - .insert('div', ':first-child') - .attr('class', 'loader') - .selectAll('.blockG') - .data(d3.range(8)) - .enter() - .append('div') - .attr('class', function(d) { - return 'blockG rotate' + (d + 1); - }); - } - - this.wrap.attr('class', 'wc-chart'); - - this.setDefaults(); - - this.raw_data = data; - this.initial_data = data; - - var startup = function startup(data) { - //connect this chart and its controls, if any - if (_this.controls) { - _this.controls.targets.push(_this); - if (!_this.controls.ready) { - _this.controls.init(_this.raw_data); - } else { - _this.controls.layout(); - } - } - - //make sure container is visible (has height and width) before trying to initialize - var visible = d3.select(_this.div).property('offsetWidth') > 0 || test; - if (!visible) { - console.warn( - 'The chart cannot be initialized inside an element with 0 width. The chart will be initialized as soon as the container element is given a width > 0.' - ); - var onVisible = setInterval(function(i) { - var visible_now = d3.select(_this.div).property('offsetWidth') > 0; - if (visible_now) { - _this.layout(); - _this.draw(); - clearInterval(onVisible); - } - }, 500); - } else { - _this.layout(); - _this.draw(); - } - }; - - this.events.onInit.call(this); - if (this.raw_data.length) { - this.checkRequired(this.raw_data); - } - startup(data); - - return this; - } + var version = '1.10.0'; function checkRequired(data) { var _this = this; @@ -144,160 +78,6 @@ }; } - function layout() { - this.svg = this.wrap - .append('svg') - .datum(function() { - return null; - }) // prevent data inheritance - .attr({ - class: 'wc-svg', - xmlns: 'http://www.w3.org/2000/svg', - version: '1.1', - xlink: 'http://www.w3.org/1999/xlink' - }) - .append('g') - .style('display', 'inline-block'); - - var defs = this.svg.append('defs'); - defs - .append('pattern') - .attr({ - id: 'diagonal-stripes', - x: 0, - y: 0, - width: 3, - height: 8, - patternUnits: 'userSpaceOnUse', - patternTransform: 'rotate(30)' - }) - .append('rect') - .attr({ x: '0', y: '0', width: '2', height: '8', style: 'stroke:none; fill:black' }); - - defs.append('clipPath').attr('id', this.id).append('rect').attr('class', 'plotting-area'); - - //y axis - this.svg - .append('g') - .attr('class', 'y axis') - .append('text') - .attr('class', 'axis-title') - .attr('transform', 'rotate(-90)') - .attr('dy', '.75em') - .attr('text-anchor', 'middle'); - //x axis - this.svg - .append('g') - .attr('class', 'x axis') - .append('text') - .attr('class', 'axis-title') - .attr('dy', '-.35em') - .attr('text-anchor', 'middle'); - //overlay - this.svg - .append('rect') - .attr('class', 'overlay') - .attr('opacity', 0) - .attr('fill', 'none') - .style('pointer-events', 'all'); - //add legend - if (!this.parent) - this.wrap - .append('ul') - .datum(function() { - return null; - }) // prevent data inheritance - .attr('class', 'legend') - .style('vertical-align', 'top') - .append('span') - .attr('class', 'legend-title'); - - d3.select(this.div).select('.loader').remove(); - - this.events.onLayout.call(this); - } - - function draw(raw_data, processed_data) { - var _this = this; - - var chart = this; - var config = this.config; - - //if pre-processing callback, run it now - this.events.onPreprocess.call(this); - - ///////////////////////// - // Data prep pipeline // - ///////////////////////// - - // if user passed raw_data to chart.draw(), use that, otherwise use chart.raw_data - var raw = raw_data ? raw_data : this.raw_data ? this.raw_data : []; - - // warn the user about the perils of "processed_data" - if (processed_data) { - console.warn( - "Drawing the chart using user-defined 'processed_data', this is an experimental, untested feature." - ); - } - - //Call consolidateData - this applies filters from controls and prepares data for each set of marks. - this.consolidateData(raw); - - ///////////////////////////// - // Prepare scales and axes // - ///////////////////////////// - - var div_width = parseInt(this.wrap.style('width')); - - this.setColorScale(); - - var max_width = config.max_width ? config.max_width : div_width; - this.raw_width = config.x.type === 'ordinal' && +config.x.range_band - ? (+config.x.range_band + config.x.range_band * config.padding) * this.x_dom.length - : config.resizable ? max_width : config.width ? config.width : div_width; - this.raw_height = config.y.type === 'ordinal' && +config.y.range_band - ? (+config.y.range_band + config.y.range_band * config.padding) * this.y_dom.length - : config.resizable - ? max_width * (1 / config.aspect) - : config.height ? config.height : div_width * (1 / config.aspect); - - var pseudo_width = this.svg.select('.overlay').attr('width') - ? this.svg.select('.overlay').attr('width') - : this.raw_width; - var pseudo_height = this.svg.select('.overlay').attr('height') - ? this.svg.select('.overlay').attr('height') - : this.raw_height; - - this.svg.select('.x.axis').select('.axis-title').text(function(d) { - return typeof config.x.label === 'string' - ? config.x.label - : typeof config.x.label === 'function' ? config.x.label.call(_this) : null; - }); - this.svg.select('.y.axis').select('.axis-title').text(function(d) { - return typeof config.y.label === 'string' - ? config.y.label - : typeof config.y.label === 'function' ? config.y.label.call(_this) : null; - }); - - this.xScaleAxis(pseudo_width); - this.yScaleAxis(pseudo_height); - - if (config.resizable && typeof window !== 'undefined') { - d3.select(window).on('resize.' + this.element + this.id, function() { - chart.resize(); - }); - } else if (typeof window !== 'undefined') { - d3.select(window).on('resize.' + this.element + this.id, null); - } - - this.events.onDraw.call(this); - - ////////////////////////////////////////////////////////////////////// - // Call resize - updates marks on the chart (amongst other things) // - ///////////////////////////////////////////////////////////////////// - this.resize(); - } - function naturalSorter(a, b) { //adapted from http://www.davekoelle.com/files/alphanum.js function chunkify(t) { @@ -337,64 +117,80 @@ return aa.length - bb.length; } - function setDomain(axis) { + function consolidateData(raw) { var _this = this; - var otherAxis = axis === 'x' ? 'y' : 'x'; + var config = this.config; + var all_data = []; + var all_x = []; + var all_y = []; - if (this.config[axis].type === 'ordinal') { - //ordinal domains - if (this.config[axis].domain) { - //user-defined domain - this[axis + '_dom'] = this.config[axis].domain; - } else if (this.config[axis].order) { - //data-driven domain with user-defined domain order - this[axis + '_dom'] = d3 - .set( - d3.merge( - this.marks.map(function(mark) { - return mark[axis + '_dom']; - }) - ) - ) - .values() - .sort(function(a, b) { - return d3.ascending( - _this.config[axis].order.indexOf(a), - _this.config[axis].order.indexOf(b) - ); - }); - } else if ( - this.config[axis].sort && - this.config[axis].sort === 'alphabetical-ascending' - ) { - //data-driven domain with user-defined domain sort algorithm that sorts the axis - //alphanumerically, first to last - this[axis + '_dom'] = d3 - .set( - d3.merge( - this.marks.map(function(mark) { - return mark[axis + '_dom']; - }) - ) - ) - .values() - .sort(naturalSorter); - } else if ( - ['time', 'linear'].indexOf(this.config[otherAxis].type) > -1 && - this.config[axis].sort === 'earliest' - ) { - //data-driven domain plotted against a time or linear axis that sorts the axis values - //by earliest event/datum; generally used with timeline charts - this[axis + '_dom'] = d3 + this.setDefaults(); + + //apply filters from associated controls objects + this.filtered_data = raw; + if (this.filters.length) { + this.filters.forEach(function(e) { + _this.filtered_data = _this.filtered_data.filter(function(d) { + return e.val === 'All' + ? d + : e.val instanceof Array + ? e.val.indexOf(d[e.col]) > -1 + : d[e.col] === e.val; + }); + }); + } + + //create data for each set of marks + config.marks.forEach(function(e, i) { + if (e.type !== 'bar') { + e.arrange = null; + e.split = null; + } + var mark_info = e.per + ? _this.transformData(raw, e) + : { data: [], x_dom: [], y_dom: [] }; + + all_data.push(mark_info.data); + all_x.push(mark_info.x_dom); + all_y.push(mark_info.y_dom); + _this.marks[i] = { + id: e.id, + type: e.type, + per: e.per, + data: mark_info.data, + split: e.split, + text: e.text, + arrange: e.arrange, + order: e.order, + summarizeX: e.summarizeX, + summarizeY: e.summarizeY, + tooltip: e.tooltip, + radius: e.radius, + attributes: e.attributes, + values: e.values + }; + }); + + if (config.x.type === 'ordinal') { + if (config.x.domain) { + this.x_dom = config.x.domain; + } else if (config.x.order) { + this.x_dom = d3.set(d3.merge(all_x)).values().sort(function(a, b) { + return d3.ascending(config.x.order.indexOf(a), config.x.order.indexOf(b)); + }); + } else if (config.x.sort && config.x.sort === 'alphabetical-ascending') { + this.x_dom = d3.set(d3.merge(all_x)).values().sort(naturalSorter); + } else if (config.y.type === 'time' && config.x.sort === 'earliest') { + this.x_dom = d3 .nest() .key(function(d) { - return d[_this.config[axis].column]; + return d[config.x.column]; }) .rollup(function(d) { return d .map(function(m) { - return m[_this.config[otherAxis].column]; + return m[config.y.column]; }) .filter(function(f) { return f instanceof Date; @@ -402,1144 +198,1202 @@ }) .entries(this.raw_data) .sort(function(a, b) { - return min(b.values) - min(a.values); + return d3.min(b.values) - d3.min(a.values); }) .map(function(m) { return m.key; }); - } else if ( - !this.config[axis].sort || - this.config[axis].sort === 'alphabetical-descending' - ) { - //data-driven domain with default/user-defined domain sort algorithm that sorts the - //axis alphanumerically, last to first - this[axis + '_dom'] = d3 - .set( - d3.merge( - this.marks.map(function(mark) { - return mark[axis + '_dom']; - }) - ) - ) - .values() - .sort(naturalSorter) - .reverse(); + } else if (!config.x.sort || config.x.sort === 'alphabetical-descending') { + this.x_dom = d3.set(d3.merge(all_x)).values().sort(naturalSorter); } else { - //data-driven domain with an invalid user-defined sort algorithm that captures a unique - //set of values as they appear in the data - this[axis + '_dom'] = d3 - .set( - d3.merge( - this.marks.map(function(mark) { - return mark[axis + '_dom']; - }) - ) - ) - .values(); + this.x_dom = d3.set(d3.merge(all_x)).values(); } } else if ( - this.config.marks + config.marks .map(function(m) { - return m['summarize' + otherAxis.toUpperCase()] === 'percent'; + return m.summarizeX === 'percent'; }) .indexOf(true) > -1 ) { - //rate domains run from 0 to 1 - this[axis + '_dom'] = [0, 1]; + this.x_dom = [0, 1]; } else { - //continuous domains run from the minimum to the maximum raw value - //TODO: they should really run from the minimum to the maximum summarized value, e.g. a - //TODO: means over time chart should plot over the range of the means, not the range of the - //TODO: raw data - this[axis + '_dom'] = d3.extent( - d3.merge( - this.marks.map(function(mark) { - return mark[axis + '_dom']; - }) - ) - ); + this.x_dom = d3.extent(d3.merge(all_x)); } - //Give the domain a range when the range of the variable is 0. - if ( - this.config[axis].type === 'linear' && - this[axis + '_dom'][0] === this[axis + '_dom'][1] - ) - this[axis + '_dom'] = this[axis + '_dom'][0] !== 0 - ? [ - this[axis + '_dom'][0] - this[axis + '_dom'][0] * 0.01, - this[axis + '_dom'][1] + this[axis + '_dom'][1] * 0.01 - ] - : [-1, 1]; - - return this[axis + '_dom']; - } - - function consolidateData(raw) { - var _this = this; - - this.setDefaults(); - - //Apply filters from associated controls objects to raw data. - this.filtered_data = raw; - if (this.filters.length) { - this.filters.forEach(function(filter) { - _this.filtered_data = _this.filtered_data.filter(function(d) { - return filter.val === 'All' - ? d - : filter.val instanceof Array - ? filter.val.indexOf(d[filter.col]) > -1 - : d[filter.col] === filter.val; + if (config.y.type === 'ordinal') { + if (config.y.domain) { + this.y_dom = config.y.domain; + } else if (config.y.order) { + this.y_dom = d3.set(d3.merge(all_y)).values().sort(function(a, b) { + return d3.ascending(config.y.order.indexOf(a), config.y.order.indexOf(b)); }); - }); + } else if (config.y.sort && config.y.sort === 'alphabetical-ascending') { + this.y_dom = d3.set(d3.merge(all_y)).values().sort(naturalSorter); + } else if (config.x.type === 'time' && config.y.sort === 'earliest') { + this.y_dom = d3 + .nest() + .key(function(d) { + return d[config.y.column]; + }) + .rollup(function(d) { + return d + .map(function(m) { + return m[config.x.column]; + }) + .filter(function(f) { + return f instanceof Date; + }); + }) + .entries(this.raw_data) + .sort(function(a, b) { + return d3.min(b.values) - d3.min(a.values); + }) + .map(function(m) { + return m.key; + }); + } else if (!config.y.sort || config.y.sort === 'alphabetical-descending') { + this.y_dom = d3.set(d3.merge(all_y)).values().sort(naturalSorter).reverse(); + } else { + this.y_dom = d3.set(d3.merge(all_y)).values(); + } + } else if ( + config.marks + .map(function(m) { + return m.summarizeY === 'percent'; + }) + .indexOf(true) > -1 + ) { + this.y_dom = [0, 1]; + } else { + this.y_dom = d3.extent(d3.merge(all_y)); } + } - //Summarize data for each mark. - this.config.marks.forEach(function(mark, i) { - if (mark.type !== 'bar') { - mark.arrange = null; - mark.split = null; - } + function destroy() { + var destroyControls = arguments.length > 0 && arguments[0] !== undefined + ? arguments[0] + : true; - var mark_info = mark.per - ? _this.transformData(raw, mark) - : { - data: [], - x_dom: [], - y_dom: [] - }; + //run onDestroy callback + this.events.onDestroy.call(this); - _this.marks[i] = { - id: mark.id, - type: mark.type, - per: mark.per, - data: mark_info.data, - x_dom: mark_info.x_dom, - y_dom: mark_info.y_dom, - split: mark.split, - text: mark.text, - arrange: mark.arrange, - order: mark.order, - summarizeX: mark.summarizeX, - summarizeY: mark.summarizeY, - tooltip: mark.tooltip, - radius: mark.radius, - attributes: mark.attributes, - values: mark.values - }; - }); + //remove resize event listener + var context = this; + d3.select(window).on('resize.' + context.element + context.id, null); - //Set domains given extents of summarized mark data. - setDomain.call(this, 'x'); - setDomain.call(this, 'y'); - } + //destroy controls + if (destroyControls && this.controls) { + this.controls.destroy(); + } - function setDefaults() { - this.config.x = this.config.x || {}; - this.config.y = this.config.y || {}; + //unmount chart wrapper + this.wrap.remove(); + } - this.config.x.label = this.config.x.label !== undefined - ? this.config.x.label - : this.config.x.column; - this.config.y.label = this.config.y.label !== undefined - ? this.config.y.label - : this.config.y.column; + function draw(raw_data, processed_data) { + var _this = this; - this.config.x.sort = this.config.x.sort || 'alphabetical-ascending'; - this.config.y.sort = this.config.y.sort || 'alphabetical-descending'; + var context = this; + var config = this.config; + var aspect2 = 1 / config.aspect; - this.config.x.type = this.config.x.type || 'linear'; - this.config.y.type = this.config.y.type || 'linear'; + ///////////////////////// + // Data prep pipeline // + ///////////////////////// - this.config.x.range_band = this.config.x.range_band || this.config.range_band; - this.config.y.range_band = this.config.y.range_band || this.config.range_band; + //if pre-processing callback, run it now + this.events.onPreprocess.call(this); - this.config.margin = this.config.margin || {}; - this.config.legend = this.config.legend || {}; - this.config.legend.label = this.config.legend.label !== undefined - ? this.config.legend.label - : this.config.color_by; - this.config.legend.location = this.config.legend.location !== undefined - ? this.config.legend.location - : 'bottom'; - this.config.marks = this.config.marks && this.config.marks.length - ? this.config.marks - : [{}]; - this.config.marks.forEach(function(m, i) { - m.id = m.id ? m.id : 'mark' + (i + 1); - }); + // if user passed raw_data to chart.draw(), use that, otherwise use chart.raw_data + var raw = raw_data ? raw_data : this.raw_data ? this.raw_data : []; - this.config.date_format = this.config.date_format || '%x'; + // warn the user about the perils of "processed_data" + if (processed_data) { + console.warn( + "Drawing the chart using user-defined 'processed_data', this is an experimental, untested feature." + ); + } - this.config.padding = this.config.padding !== undefined ? this.config.padding : 0.3; - this.config.outer_pad = this.config.outer_pad !== undefined ? this.config.outer_pad : 0.1; + //Call consolidateData - this applies filters from controls and prepares data for each set of marks. + var data = processed_data || this.consolidateData(raw); - this.config.resizable = this.config.resizable !== undefined ? this.config.resizable : true; + ///////////////////////////// + // Prepare scales and axes // + ///////////////////////////// - this.config.aspect = this.config.aspect || 1.33; + var div_width = parseInt(this.wrap.style('width')); - this.config.colors = this.config.colors || [ - 'rgb(102,194,165)', - 'rgb(252,141,98)', - 'rgb(141,160,203)', - 'rgb(231,138,195)', - 'rgb(166,216,84)', - 'rgb(255,217,47)', - 'rgb(229,196,148)', - 'rgb(179,179,179)' - ]; + this.setColorScale(); - this.config.scale_text = this.config.scale_text === undefined - ? true - : this.config.scale_text; - this.config.transitions = this.config.transitions === undefined - ? true - : this.config.transitions; - } + var max_width = config.max_width ? config.max_width : div_width; + this.raw_width = config.x.type === 'ordinal' && +config.range_band + ? (+config.range_band + config.range_band * config.padding) * this.x_dom.length + : config.resizable ? max_width : config.width ? config.width : div_width; + this.raw_height = config.y.type === 'ordinal' && +config.range_band + ? (+config.range_band + config.range_band * config.padding) * this.y_dom.length + : config.resizable + ? max_width * aspect2 + : config.height ? config.height : div_width * aspect2; - function cleanData(mark, raw) { - var _this = this; + var pseudo_width = this.svg.select('.overlay').attr('width') + ? this.svg.select('.overlay').attr('width') + : this.raw_width; + var pseudo_height = this.svg.select('.overlay').attr('height') + ? this.svg.select('.overlay').attr('height') + : this.raw_height; - var dateConvert = d3.time.format(this.config.date_format); - var clean = raw; - // only use data for the current mark - clean = mark.per && mark.per.length - ? clean.filter(function(f) { - return f[mark.per[0]] !== undefined; - }) - : clean; + this.svg.select('.x.axis').select('.axis-title').text(function(d) { + return typeof config.x.label === 'string' + ? config.x.label + : typeof config.x.label === 'function' ? config.x.label.call(_this) : null; + }); + this.svg.select('.y.axis').select('.axis-title').text(function(d) { + return typeof config.y.label === 'string' + ? config.y.label + : typeof config.y.label === 'function' ? config.y.label.call(_this) : null; + }); - // Make sure data has x and y values - if (this.config.x.column) { - clean = clean.filter(function(f) { - return [undefined, null].indexOf(f[_this.config.x.column]) < 0; - }); - } - if (this.config.y.column) { - clean = clean.filter(function(f) { - return [undefined, null].indexOf(f[_this.config.y.column]) < 0; - }); - } + this.xScaleAxis(pseudo_width); + this.yScaleAxis(pseudo_height); - //check that x and y have the correct formats - if (this.config.x.type === 'time') { - clean = clean.filter(function(f) { - return f[_this.config.x.column] instanceof Date - ? f[_this.config.x.column] - : dateConvert.parse(f[_this.config.x.column]); - }); - clean.forEach(function(e) { - return (e[_this.config.x.column] = e[_this.config.x.column] instanceof Date - ? e[_this.config.x.column] - : dateConvert.parse(e[_this.config.x.column])); - }); - } - if (this.config.y.type === 'time') { - clean = clean.filter(function(f) { - return f[_this.config.y.column] instanceof Date - ? f[_this.config.y.column] - : dateConvert.parse(f[_this.config.y.column]); - }); - clean.forEach(function(e) { - return (e[_this.config.y.column] = e[_this.config.y.column] instanceof Date - ? e[_this.config.y.column] - : dateConvert.parse(e[_this.config.y.column])); + if (config.resizable && typeof window !== 'undefined') { + d3.select(window).on('resize.' + context.element + context.id, function() { + context.resize(); }); + } else if (typeof window !== 'undefined') { + d3.select(window).on('resize.' + context.element + context.id, null); } - if ( - (this.config.x.type === 'linear' || this.config.x.type === 'log') && - this.config.x.column - ) { - clean = clean.filter(function(f) { - return mark.summarizeX !== 'count' && mark.summarizeX !== 'percent' - ? !(isNaN(f[_this.config.x.column]) || /^\s*$/.test(f[_this.config.x.column])) // is or coerces to a number and is not a string that coerces to 0 - : f; - }); - } - if ( - (this.config.y.type === 'linear' || this.config.y.type === 'log') && - this.config.y.column - ) { - clean = clean.filter(function(f) { - return mark.summarizeY !== 'count' && mark.summarizeY !== 'percent' - ? !(isNaN(f[_this.config.y.column]) || /^\s*$/.test(f[_this.config.y.column])) // is or coerces to a number and is not a string that coerces to 0 - : f; - }); - } + this.events.onDraw.call(this); - return clean; + ////////////////////////////////////////////////////////////////////// + // Call resize - updates marks on the chart (amongst other things) // + ///////////////////////////////////////////////////////////////////// + this.resize(); } - var stats = { - mean: d3.mean, - min: d3.min, - max: d3.max, - median: d3.median, - sum: d3.sum - }; + function drawArea(area_drawer, area_data, datum_accessor) { + var class_match = arguments.length > 3 && arguments[3] !== undefined + ? arguments[3] + : 'chart-area'; - function summarize(vals) { - var operation = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'mean'; + var _this = this; - var nvals = vals - .filter(function(f) { - return +f || +f === 0; + var bind_accessor = arguments[4]; + var attr_accessor = arguments.length > 5 && arguments[5] !== undefined + ? arguments[5] + : function(d) { + return d; + }; + + var area_grps = this.svg.selectAll('.' + class_match).data(area_data, bind_accessor); + area_grps.exit().remove(); + area_grps + .enter() + .append('g') + .attr('class', function(d) { + return class_match + ' ' + d.key; }) - .map(function(m) { - return +m; - }); + .append('path'); - if (operation === 'cumulative') { - return null; - } + var areaPaths = area_grps + .select('path') + .datum(datum_accessor) + .attr('fill', function(d) { + var d_attr = attr_accessor(d); + return d_attr ? _this.colorScale(d_attr[_this.config.color_by]) : null; + }) + .attr( + 'fill-opacity', + this.config.fill_opacity || this.config.fill_opacity === 0 + ? this.config.fill_opacity + : 0.3 + ); - var mathed = operation === 'count' - ? vals.length - : operation === 'percent' ? vals.length : stats[operation](nvals); + //don't transition if config says not to + var areaPathTransitions = this.config.transitions ? areaPaths.transition() : areaPaths; - return mathed; + areaPathTransitions.attr('d', area_drawer); + + return area_grps; } - function makeNest(mark, entries, sublevel) { + function drawBars(marks) { var _this = this; - var dom_xs = []; - var dom_ys = []; - var this_nest = d3.nest(); - var totalOrder = void 0; + var rawData = this.raw_data; + var config = this.config; - if ( - (this.config.x.type === 'linear' && this.config.x.bin) || - (this.config.y.type === 'linear' && this.config.y.bin) - ) { - var xy = this.config.x.type === 'linear' && this.config.x.bin ? 'x' : 'y'; - var quant = d3.scale - .quantile() - .domain( - d3.extent( - entries.map(function(m) { - return +m[_this.config[xy].column]; - }) - ) - ) - .range(d3.range(+this.config[xy].bin)); - - entries.forEach(function(e) { - return (e.wc_bin = quant(e[_this.config[xy].column])); - }); + var bar_supergroups = this.svg.selectAll('.bar-supergroup').data(marks, function(d, i) { + return i + '-' + d.per.join('-'); + }); - this_nest.key(function(d) { - return quant.invertExtent(d.wc_bin); - }); - } else { - this_nest.key(function(d) { - return mark.per - .map(function(m) { - return d[m]; - }) - .join(' '); - }); - } + bar_supergroups.enter().append('g').attr('class', function(d) { + return 'supergroup bar-supergroup ' + d.id; + }); - if (sublevel) { - this_nest.key(function(d) { - return d[sublevel]; - }); - this_nest.sortKeys(function(a, b) { - return _this.config.x.type === 'time' - ? d3.ascending(new Date(a), new Date(b)) - : _this.config.x.order - ? d3.ascending( - _this.config.x.order.indexOf(a), - _this.config.x.order.indexOf(b) - ) - : sublevel === _this.config.color_by && _this.config.legend.order - ? d3.ascending( - _this.config.legend.order.indexOf(a), - _this.config.legend.order.indexOf(b) - ) - : _this.config.x.type === 'ordinal' || _this.config.y.type === 'ordinal' - ? naturalSorter(a, b) - : d3.ascending(+a, +b); - }); - } - this_nest.rollup(function(r) { - var obj = { raw: r }; - var y_vals = r - .map(function(m) { - return m[_this.config.y.column]; - }) - .sort(d3.ascending); - var x_vals = r - .map(function(m) { - return m[_this.config.x.column]; - }) - .sort(d3.ascending); - obj.x = _this.config.x.type === 'ordinal' - ? r[0][_this.config.x.column] - : summarize(x_vals, mark.summarizeX); - obj.y = _this.config.y.type === 'ordinal' - ? r[0][_this.config.y.column] - : summarize(y_vals, mark.summarizeY); - - obj.x_q25 = _this.config.error_bars && _this.config.y.type === 'ordinal' - ? d3.quantile(x_vals, 0.25) - : obj.x; - obj.x_q75 = _this.config.error_bars && _this.config.y.type === 'ordinal' - ? d3.quantile(x_vals, 0.75) - : obj.x; - obj.y_q25 = _this.config.error_bars ? d3.quantile(y_vals, 0.25) : obj.y; - obj.y_q75 = _this.config.error_bars ? d3.quantile(y_vals, 0.75) : obj.y; - dom_xs.push([obj.x_q25, obj.x_q75, obj.x]); - dom_ys.push([obj.y_q25, obj.y_q75, obj.y]); - - if (mark.summarizeY === 'cumulative') { - var interm = entries.filter(function(f) { - return _this.config.x.type === 'time' - ? new Date(f[_this.config.x.column]) <= - new Date(r[0][_this.config.x.column]) - : +f[_this.config.x.column] <= +r[0][_this.config.x.column]; - }); - if (mark.per.length) { - interm = interm.filter(function(f) { - return f[mark.per[0]] === r[0][mark.per[0]]; - }); - } + bar_supergroups.exit().remove(); - var cumul = _this.config.x.type === 'time' - ? interm.length - : d3.sum( - interm.map(function(m) { - return +m[_this.config.y.column] || +m[_this.config.y.column] === 0 - ? +m[_this.config.y.column] - : 1; - }) - ); - dom_ys.push([cumul]); - obj.y = cumul; - } - if (mark.summarizeX === 'cumulative') { - var _interm = entries.filter(function(f) { - return _this.config.y.type === 'time' - ? new Date(f[_this.config.y.column]) <= - new Date(r[0][_this.config.y.column]) - : +f[_this.config.y.column] <= +r[0][_this.config.y.column]; - }); - if (mark.per.length) { - _interm = _interm.filter(function(f) { - return f[mark.per[0]] === r[0][mark.per[0]]; - }); - } - dom_xs.push([_interm.length]); - obj.x = _interm.length; + var bar_groups = bar_supergroups.selectAll('.bar-group').data( + function(d) { + return d.data; + }, + function(d) { + return d.key; } + ); + var old_bar_groups = bar_groups.exit(); - return obj; - }); + var nu_bar_groups = void 0; + var bars = void 0; + + var oldBarsTrans = config.transitions + ? old_bar_groups.selectAll('.bar').transition() + : old_bar_groups.selectAll('.bar'); + var oldBarGroupsTrans = config.transitions ? old_bar_groups.transition() : old_bar_groups; - var test = this_nest.entries(entries); + if (config.x.type === 'ordinal') { + oldBarsTrans.attr('y', this.y(0)).attr('height', 0); - var dom_x = d3.extent(d3.merge(dom_xs)); - var dom_y = d3.extent(d3.merge(dom_ys)); + oldBarGroupsTrans.remove(); - if (sublevel && mark.type === 'bar' && mark.split) { - //calculate percentages in bars - test.forEach(function(e) { - var axis = _this.config.x.type === 'ordinal' || - (_this.config.x.type === 'linear' && _this.config.x.bin) - ? 'y' - : 'x'; - e.total = d3.sum( - e.values.map(function(m) { - return +m.values[axis]; - }) - ); - var counter = 0; - e.values.forEach(function(v, i) { - if ( - _this.config.x.type === 'ordinal' || - (_this.config.x.type === 'linear' && _this.config.x.bin) - ) { - v.values.y = mark.summarizeY === 'percent' - ? v.values.y / e.total - : v.values.y || 0; - counter += +v.values.y; - v.values.start = e.values[i - 1] ? counter : v.values.y; - } else { - v.values.x = mark.summarizeX === 'percent' - ? v.values.x / e.total - : v.values.x || 0; - v.values.start = counter; - counter += +v.values.x; - } - }); + nu_bar_groups = bar_groups.enter().append('g').attr('class', function(d) { + return 'bar-group ' + d.key; }); + nu_bar_groups.append('title'); - if (mark.arrange === 'stacked') { - if ( - this.config.x.type === 'ordinal' || - (this.config.x.type === 'linear' && this.config.x.bin) - ) { - dom_y = d3.extent( - test.map(function(m) { - return m.total; - }) - ); - } - if ( - this.config.y.type === 'ordinal' || - (this.config.y.type === 'linear' && this.config.y.bin) - ) { - dom_x = d3.extent( - test.map(function(m) { - return m.total; - }) - ); + bars = bar_groups.selectAll('rect').data( + function(d) { + return d.values instanceof Array + ? d.values.sort(function(a, b) { + return ( + _this.colorScale.domain().indexOf(b.key) - + _this.colorScale.domain().indexOf(a.key) + ); + }) + : [d]; + }, + function(d) { + return d.key; } - } - } else { - var axis = this.config.x.type === 'ordinal' || - (this.config.x.type === 'linear' && this.config.x.bin) - ? 'y' - : 'x'; - test.forEach(function(e) { - return (e.total = e.values[axis]); - }); - } + ); - if ( - (this.config.x.sort === 'total-ascending' && this.config.x.type == 'ordinal') || - (this.config.y.sort === 'total-descending' && this.config.y.type == 'ordinal') - ) { - totalOrder = test - .sort(function(a, b) { - return d3.ascending(a.total, b.total); + var exitBars = config.transitions ? bars.exit().transition() : bars.exit(); + exitBars.attr('y', this.y(0)).attr('height', 0).remove(); + bars + .enter() + .append('rect') + .attr('class', function(d) { + return 'wc-data-mark bar ' + d.key; }) - .map(function(m) { - return m.key; - }); - } else if ( - (this.config.x.sort === 'total-descending' && this.config.x.type == 'ordinal') || - (this.config.y.sort === 'total-ascending' && this.config.y.type == 'ordinal') - ) { - totalOrder = test - .sort(function(a, b) { - return d3.descending(+a.total, +b.total); + .style('clip-path', 'url(#' + this.id + ')') + .attr('y', this.y(0)) + .attr('height', 0) + .append('title'); + + bars + .attr('shape-rendering', 'crispEdges') + .attr('stroke', function(d) { + return _this.colorScale(d.values.raw[0][config.color_by]); }) - .map(function(m) { - return m.key; + .attr('fill', function(d) { + return _this.colorScale(d.values.raw[0][config.color_by]); }); - } - return { nested: test, dom_x: dom_x, dom_y: dom_y, totalOrder: totalOrder }; - } + bars.each(function(d) { + var mark = d3.select(this.parentNode.parentNode).datum(); + d.tooltip = mark.tooltip; + d.arrange = mark.split ? mark.arrange : null; + d.subcats = config.legend.order + ? config.legend.order.slice().reverse() + : mark.values && mark.values[mark.split] + ? mark.values[mark.split] + : d3 + .set( + rawData.map(function(m) { + return m[mark.split]; + }) + ) + .values(); + d3.select(this).attr(mark.attributes); + }); - ////////////////////////////////////////////////////////// - // transformData(raw, mark) provides specifications and data for - // each set of marks. As such, it is called once for each - // item specified in the config.marks array. - // - // parameters - // raw - the raw data for use in the mark. Filters from controls - // are typically already applied. - // mark - a single mark object from config.marks - //////////////////////////////////////////////////////// + var xformat = config.marks + .map(function(m) { + return m.summarizeX === 'percent'; + }) + .indexOf(true) > -1 + ? d3.format('0%') + : d3.format(config.x.format); + var yformat = config.marks + .map(function(m) { + return m.summarizeY === 'percent'; + }) + .indexOf(true) > -1 + ? d3.format('0%') + : d3.format(config.y.format); + bars.select('title').text(function(d) { + var tt = d.tooltip || ''; + return tt + .replace(/\$x/g, xformat(d.values.x)) + .replace(/\$y/g, yformat(d.values.y)) + .replace(/\[(.+?)\]/g, function(str, orig) { + return d.values.raw[0][orig]; + }); + }); - function transformData(raw, mark) { - var _this = this; + var barsTrans = config.transitions ? bars.transition() : bars; + barsTrans + .attr('x', function(d) { + var position = void 0; + if (!d.arrange || d.arrange === 'stacked') { + return _this.x(d.values.x); + } else if (d.arrange === 'nested') { + var _position = d.subcats.indexOf(d.key); + var offset = _position + ? _this.x.rangeBand() / (d.subcats.length * 0.75) / _position + : _this.x.rangeBand(); + return _this.x(d.values.x) + (_this.x.rangeBand() - offset) / 2; + } else { + position = d.subcats.indexOf(d.key); + return ( + _this.x(d.values.x) + _this.x.rangeBand() / d.subcats.length * position + ); + } + }) + .attr('y', function(d) { + if (d.arrange !== 'stacked') { + return _this.y(d.values.y); + } else { + return _this.y(d.values.start); + } + }) + .attr('width', function(d) { + if (!d.arrange || d.arrange === 'stacked') { + return _this.x.rangeBand(); + } else if (d.arrange === 'nested') { + var position = d.subcats.indexOf(d.key); + return position + ? _this.x.rangeBand() / (d.subcats.length * 0.75) / position + : _this.x.rangeBand(); + } else { + return _this.x.rangeBand() / d.subcats.length; + } + }) + .attr('height', function(d) { + return _this.y(0) - _this.y(d.values.y); + }); + } else if (config.y.type === 'ordinal') { + oldBarsTrans.attr('x', this.x(0)).attr('width', 0); - //convenience mappings - var config = this.config; - var x_behavior = config.x.behavior || 'raw'; - var y_behavior = config.y.behavior || 'raw'; - var sublevel = mark.type === 'line' - ? config.x.column - : mark.type === 'bar' && mark.split ? mark.split : null; + oldBarGroupsTrans.remove(); - ////////////////////////////////////////////////////////////////////////////////// - // DATA PREP - // prepare data based on the properties of the mark - drop missing records, etc - ////////////////////////////////////////////////////////////////////////////////// - var cleaned = cleanData.call(this, mark, raw); + nu_bar_groups = bar_groups.enter().append('g').attr('class', function(d) { + return 'bar-group ' + d.key; + }); + nu_bar_groups.append('title'); - //prepare nested data required for bar charts - var raw_nest = void 0; - if (mark.type === 'bar') { - raw_nest = mark.arrange !== 'stacked' - ? makeNest.call(this, mark, cleaned, sublevel) - : makeNest.call(this, mark, cleaned); - } else if (mark.summarizeX === 'count' || mark.summarizeY === 'count') { - raw_nest = makeNest.call(this, mark, cleaned); - } + bars = bar_groups.selectAll('rect').data( + function(d) { + return d.values instanceof Array + ? d.values.sort(function(a, b) { + return ( + _this.colorScale.domain().indexOf(b.key) - + _this.colorScale.domain().indexOf(a.key) + ); + }) + : [d]; + }, + function(d) { + return d.key; + } + ); - // Get the domain for the mark based on the raw data - var raw_dom_x = mark.summarizeX === 'cumulative' - ? [0, cleaned.length] - : config.x.type === 'ordinal' - ? d3 - .set( - cleaned.map(function(m) { - return m[config.x.column]; - }) - ) - .values() - .filter(function(f) { - return f; - }) - : mark.split && mark.arrange !== 'stacked' - ? d3.extent( - d3.merge( - raw_nest.nested.map(function(m) { - return m.values.map(function(p) { - return p.values.raw.length; - }); - }) - ) - ) - : mark.summarizeX === 'count' - ? d3.extent( - raw_nest.nested.map(function(m) { - return m.values.raw.length; - }) - ) - : d3.extent( - cleaned - .map(function(m) { - return +m[config.x.column]; - }) - .filter(function(f) { - return +f || +f === 0; - }) - ); + var _exitBars = config.transitions ? bars.exit().transition() : bars.exit(); + _exitBars.attr('x', this.x(0)).attr('width', 0).remove(); + bars + .enter() + .append('rect') + .attr('class', function(d) { + return 'wc-data-mark bar ' + d.key; + }) + .style('clip-path', 'url(#' + this.id + ')') + .attr('x', this.x(0)) + .attr('width', 0) + .append('title'); - var raw_dom_y = mark.summarizeY === 'cumulative' - ? [0, cleaned.length] - : config.y.type === 'ordinal' - ? d3 - .set( - cleaned.map(function(m) { - return m[config.y.column]; - }) - ) - .values() - .filter(function(f) { - return f; - }) - : mark.split && mark.arrange !== 'stacked' - ? d3.extent( - d3.merge( - raw_nest.nested.map(function(m) { - return m.values.map(function(p) { - return p.values.raw.length; - }); - }) - ) - ) - : mark.summarizeY === 'count' - ? d3.extent( - raw_nest.nested.map(function(m) { - return m.values.raw.length; - }) - ) - : d3.extent( - cleaned - .map(function(m) { - return +m[config.y.column]; - }) - .filter(function(f) { - return +f || +f === 0; - }) - ); + bars + .attr('shape-rendering', 'crispEdges') + .attr('stroke', function(d) { + return _this.colorScale(d.values.raw[0][config.color_by]); + }) + .attr('fill', function(d) { + return _this.colorScale(d.values.raw[0][config.color_by]); + }); + + bars.each(function(d) { + var mark = d3.select(this.parentNode.parentNode).datum(); + d.arrange = mark.split && mark.arrange + ? mark.arrange + : mark.split ? 'grouped' : null; + d.subcats = config.legend.order + ? config.legend.order.slice().reverse() + : mark.values && mark.values[mark.split] + ? mark.values[mark.split] + : d3 + .set( + rawData.map(function(m) { + return m[mark.split]; + }) + ) + .values(); + d.tooltip = mark.tooltip; + }); + + var _xformat = config.marks + .map(function(m) { + return m.summarizeX === 'percent'; + }) + .indexOf(true) > -1 + ? d3.format('0%') + : d3.format(config.x.format); + var _yformat = config.marks + .map(function(m) { + return m.summarizeY === 'percent'; + }) + .indexOf(true) > -1 + ? d3.format('0%') + : d3.format(config.y.format); + bars.select('title').text(function(d) { + var tt = d.tooltip || ''; + return tt + .replace(/\$x/g, _xformat(d.values.x)) + .replace(/\$y/g, _yformat(d.values.y)) + .replace(/\[(.+?)\]/g, function(str, orig) { + return d.values.raw[0][orig]; + }); + }); + + var _barsTrans = config.transitions ? bars.transition() : bars; + _barsTrans + .attr('x', function(d) { + if (d.arrange === 'stacked' || !d.arrange) { + return d.values.start !== undefined ? _this.x(d.values.start) : _this.x(0); + } else { + return _this.x(0); + } + }) + .attr('y', function(d) { + if (d.arrange === 'nested') { + var position = d.subcats.indexOf(d.key); + var offset = position + ? _this.y.rangeBand() / (d.subcats.length * 0.75) / position + : _this.y.rangeBand(); + return _this.y(d.values.y) + (_this.y.rangeBand() - offset) / 2; + } else if (d.arrange === 'grouped') { + var _position2 = d.subcats.indexOf(d.key); + return ( + _this.y(d.values.y) + + _this.y.rangeBand() / d.subcats.length * _position2 + ); + } else { + return _this.y(d.values.y); + } + }) + .attr('width', function(d) { + return _this.x(d.values.x) - _this.x(0); + }) + .attr('height', function(d) { + if (config.y.type === 'quantile') { + return 20; + } else if (d.arrange === 'nested') { + var position = d.subcats.indexOf(d.key); + return position + ? _this.y.rangeBand() / (d.subcats.length * 0.75) / position + : _this.y.rangeBand(); + } else if (d.arrange === 'grouped') { + return _this.y.rangeBand() / d.subcats.length; + } else { + return _this.y.rangeBand(); + } + }); + } else if (['linear', 'log'].indexOf(config.x.type) > -1 && config.x.bin) { + oldBarsTrans.attr('y', this.y(0)).attr('height', 0); + + oldBarGroupsTrans.remove(); + + nu_bar_groups = bar_groups.enter().append('g').attr('class', function(d) { + return 'bar-group ' + d.key; + }); + nu_bar_groups.append('title'); + + bars = bar_groups.selectAll('rect').data( + function(d) { + return d.values instanceof Array ? d.values : [d]; + }, + function(d) { + return d.key; + } + ); + + var _exitBars2 = config.transitions ? bars.exit().transition() : bars.exit(); + _exitBars2.attr('y', this.y(0)).attr('height', 0).remove(); + bars + .enter() + .append('rect') + .attr('class', function(d) { + return 'wc-data-mark bar ' + d.key; + }) + .style('clip-path', 'url(#' + this.id + ')') + .attr('y', this.y(0)) + .attr('height', 0) + .append('title'); + + bars + .attr('shape-rendering', 'crispEdges') + .attr('stroke', function(d) { + return _this.colorScale(d.values.raw[0][config.color_by]); + }) + .attr('fill', function(d) { + return _this.colorScale(d.values.raw[0][config.color_by]); + }); + + bars.each(function(d) { + var mark = d3.select(this.parentNode.parentNode).datum(); + d.arrange = mark.split ? mark.arrange : null; + d.subcats = config.legend.order + ? config.legend.order.slice().reverse() + : mark.values && mark.values[mark.split] + ? mark.values[mark.split] + : d3 + .set( + rawData.map(function(m) { + return m[mark.split]; + }) + ) + .values(); + d3.select(this).attr(mark.attributes); + var parent = d3.select(this.parentNode).datum(); + var rangeSet = parent.key.split(',').map(function(m) { + return +m; + }); + d.rangeLow = d3.min(rangeSet); + d.rangeHigh = d3.max(rangeSet); + d.tooltip = mark.tooltip; + }); + + var _xformat2 = config.marks + .map(function(m) { + return m.summarizeX === 'percent'; + }) + .indexOf(true) > -1 + ? d3.format('0%') + : d3.format(config.x.format); + var _yformat2 = config.marks + .map(function(m) { + return m.summarizeY === 'percent'; + }) + .indexOf(true) > -1 + ? d3.format('0%') + : d3.format(config.y.format); + bars.select('title').text(function(d) { + var tt = d.tooltip || ''; + return tt + .replace(/\$x/g, _xformat2(d.values.x)) + .replace(/\$y/g, _yformat2(d.values.y)) + .replace(/\[(.+?)\]/g, function(str, orig) { + return d.values.raw[0][orig]; + }); + }); + + var _barsTrans2 = config.transitions ? bars.transition() : bars; + _barsTrans2 + .attr('x', function(d) { + return _this.x(d.rangeLow); + }) + .attr('y', function(d) { + if (d.arrange !== 'stacked') { + return _this.y(d.values.y); + } else { + return _this.y(d.values.start); + } + }) + .attr('width', function(d) { + return _this.x(d.rangeHigh) - _this.x(d.rangeLow); + }) + .attr('height', function(d) { + return _this.y(0) - _this.y(d.values.y); + }); + } else if ( + ['linear', 'log'].indexOf(config.y.type) > -1 && + config.y.type === 'linear' && + config.y.bin + ) { + oldBarsTrans.attr('x', this.x(0)).attr('width', 0); + oldBarGroupsTrans.remove(); + + nu_bar_groups = bar_groups.enter().append('g').attr('class', function(d) { + return 'bar-group ' + d.key; + }); + nu_bar_groups.append('title'); + + bars = bar_groups.selectAll('rect').data( + function(d) { + return d.values instanceof Array ? d.values : [d]; + }, + function(d) { + return d.key; + } + ); + + var _exitBars3 = config.transitions ? bars.exit().transition() : bars.exit(); + _exitBars3.attr('x', this.x(0)).attr('width', 0).remove(); + bars + .enter() + .append('rect') + .attr('class', function(d) { + return 'wc-data-mark bar ' + d.key; + }) + .style('clip-path', 'url(#' + this.id + ')') + .attr('x', this.x(0)) + .attr('width', 0) + .append('title'); - var filtered = cleaned; + bars + .attr('shape-rendering', 'crispEdges') + .attr('stroke', function(d) { + return _this.colorScale(d.values.raw[0][config.color_by]); + }) + .attr('fill', function(d) { + return _this.colorScale(d.values.raw[0][config.color_by]); + }); - var filt1_xs = []; - var filt1_ys = []; - if (this.filters.length) { - this.filters.forEach(function(e) { - filtered = filtered.filter(function(d) { - return e.val === 'All' - ? d - : e.val instanceof Array - ? e.val.indexOf(d[e.col]) > -1 - : d[e.col] === e.val; + bars.each(function(d) { + var mark = d3.select(this.parentNode.parentNode).datum(); + d.arrange = mark.split ? mark.arrange : null; + d.subcats = config.legend.order + ? config.legend.order.slice().reverse() + : mark.values && mark.values[mark.split] + ? mark.values[mark.split] + : d3 + .set( + rawData.map(function(m) { + return m[mark.split]; + }) + ) + .values(); + var parent = d3.select(this.parentNode).datum(); + var rangeSet = parent.key.split(',').map(function(m) { + return +m; }); + d.rangeLow = d3.min(rangeSet); + d.rangeHigh = d3.max(rangeSet); + d.tooltip = mark.tooltip; }); - //get domain for all non-All values of first filter - if (config.x.behavior === 'firstfilter' || config.y.behavior === 'firstfilter') { - this.filters[0].choices - .filter(function(f) { - return f !== 'All'; - }) - .forEach(function(e) { - var perfilter = cleaned.filter(function(f) { - return f[_this.filters[0].col] === e; - }); - var filt_nested = makeNest.call(_this, mark, perfilter, sublevel); - filt1_xs.push(filt_nested.dom_x); - filt1_ys.push(filt_nested.dom_y); + + var _xformat3 = config.marks + .map(function(m) { + return m.summarizeX === 'percent'; + }) + .indexOf(true) > -1 + ? d3.format('0%') + : d3.format(config.x.format); + var _yformat3 = config.marks + .map(function(m) { + return m.summarizeY === 'percent'; + }) + .indexOf(true) > -1 + ? d3.format('0%') + : d3.format(config.y.format); + bars.select('title').text(function(d) { + var tt = d.tooltip || ''; + return tt + .replace(/\$x/g, _xformat3(d.values.x)) + .replace(/\$y/g, _yformat3(d.values.y)) + .replace(/\[(.+?)\]/g, function(str, orig) { + return d.values.raw[0][orig]; }); - } - } + }); - //filter on mark-specific instructions - if (mark.values) { - var _loop = function _loop(a) { - filtered = filtered.filter(function(f) { - return mark.values[a].indexOf(f[a]) > -1; + var _barsTrans3 = config.transitions ? bars.transition() : bars; + _barsTrans3 + .attr('x', function(d) { + if (d.arrange === 'stacked') { + return _this.x(d.values.start); + } else { + return _this.x(0); + } + }) + .attr('y', function(d) { + return _this.y(d.rangeHigh); + }) + .attr('width', function(d) { + return _this.x(d.values.x); + }) + .attr('height', function(d) { + return _this.y(d.rangeLow) - _this.y(d.rangeHigh); }); - }; - - for (var a in mark.values) { - _loop(a); - } + } else { + oldBarsTrans.attr('y', this.y(0)).attr('height', 0); + oldBarGroupsTrans.remove(); + bar_supergroups.remove(); } - var filt1_dom_x = d3.extent(d3.merge(filt1_xs)); - var filt1_dom_y = d3.extent(d3.merge(filt1_ys)); - - var current_nested = makeNest.call(this, mark, filtered, sublevel); - var flex_dom_x = current_nested.dom_x; - var flex_dom_y = current_nested.dom_y; + //Link to the d3.selection from the data + bar_supergroups.each(function(d) { + d.supergroup = d3.select(this); + d.groups = d.supergroup.selectAll('.bar-group'); + }); + } - if (mark.type === 'bar') { - if (config.y.type === 'ordinal' && mark.summarizeX === 'count') { - config.x.domain = config.x.domain ? [0, config.x.domain[1]] : [0, null]; - } else if (config.x.type === 'ordinal' && mark.summarizeY === 'count') { - config.y.domain = config.y.domain ? [0, config.y.domain[1]] : [0, null]; - } + function drawGridLines() { + this.wrap.classed('gridlines', this.config.gridlines); + if (this.config.gridlines) { + this.svg.select('.y.axis').selectAll('.tick line').attr('x1', 0); + this.svg.select('.x.axis').selectAll('.tick line').attr('y1', 0); + if (this.config.gridlines === 'y' || this.config.gridlines === 'xy') + this.svg.select('.y.axis').selectAll('.tick line').attr('x1', this.plot_width); + if (this.config.gridlines === 'x' || this.config.gridlines === 'xy') + this.svg.select('.x.axis').selectAll('.tick line').attr('y1', -this.plot_height); + } else { + this.svg.select('.y.axis').selectAll('.tick line').attr('x1', 0); + this.svg.select('.x.axis').selectAll('.tick line').attr('y1', 0); } + } - //several criteria must be met in order to use the 'firstfilter' domain - var nonall = Boolean( - this.filters.length && - this.filters[0].val !== 'All' && - this.filters.slice(1).filter(function(f) { - return f.val === 'All'; - }).length === - this.filters.length - 1 - ); - - var pre_x_dom = !this.filters.length - ? flex_dom_x - : x_behavior === 'raw' - ? raw_dom_x - : nonall && x_behavior === 'firstfilter' ? filt1_dom_x : flex_dom_x; - var pre_y_dom = !this.filters.length - ? flex_dom_y - : y_behavior === 'raw' - ? raw_dom_y - : nonall && y_behavior === 'firstfilter' ? filt1_dom_y : flex_dom_y; + function drawLines(marks) { + var _this = this; - var x_dom = config.x_dom - ? config.x_dom - : config.x.type === 'ordinal' && config.x.behavior === 'flex' - ? d3 - .set( - filtered.map(function(m) { - return m[config.x.column]; - }) - ) - .values() - : config.x.type === 'ordinal' - ? d3 - .set( - cleaned.map(function(m) { - return m[config.x.column]; - }) - ) - .values() - : pre_x_dom; + var config = this.config; + var line = d3.svg + .line() + .interpolate(config.interpolate) + .x(function(d) { + return config.x.type === 'linear' || config.x.type == 'log' + ? _this.x(+d.values.x) + : config.x.type === 'time' + ? _this.x(new Date(d.values.x)) + : _this.x(d.values.x) + _this.x.rangeBand() / 2; + }) + .y(function(d) { + return config.y.type === 'linear' || config.y.type == 'log' + ? _this.y(+d.values.y) + : config.y.type === 'time' + ? _this.y(new Date(d.values.y)) + : _this.y(d.values.y) + _this.y.rangeBand() / 2; + }); - var y_dom = config.y_dom - ? config.y_dom - : config.y.type === 'ordinal' && config.y.behavior === 'flex' - ? d3 - .set( - filtered.map(function(m) { - return m[config.y.column]; - }) - ) - .values() - : config.y.type === 'ordinal' - ? d3 - .set( - cleaned.map(function(m) { - return m[config.y.column]; - }) - ) - .values() - : pre_y_dom; + var line_supergroups = this.svg.selectAll('.line-supergroup').data(marks, function(d, i) { + return i + '-' + d.per.join('-'); + }); - //set lower limit of linear domain to 0 when other axis is ordinal and mark type is set to 'bar', provided no values are negative - if (mark.type === 'bar') { - if ( - config.x.behavior !== 'flex' && - config.x.type === 'linear' && - config.y.type === 'ordinal' && - raw_dom_x[0] >= 0 - ) - x_dom[0] = 0; + line_supergroups.enter().append('g').attr('class', function(d) { + return 'supergroup line-supergroup ' + d.id; + }); - if ( - config.y.behavior !== 'flex' && - config.x.type === 'ordinal' && - config.y.type === 'linear' && - raw_dom_y[0] >= 0 - ) - y_dom[0] = 0; - } + line_supergroups.exit().remove(); - //update domains with those specified in the config - if (config.x.domain && (config.x.domain[0] || config.x.domain[0] === 0)) { - x_dom[0] = config.x.domain[0]; - } - if (config.x.domain && (config.x.domain[1] || config.x.domain[1] === 0)) { - x_dom[1] = config.x.domain[1]; - } - if (config.y.domain && (config.y.domain[0] || config.y.domain[0] === 0)) { - y_dom[0] = config.y.domain[0]; - } - if (config.y.domain && (config.y.domain[1] || config.y.domain[1] === 0)) { - y_dom[1] = config.y.domain[1]; - } + var line_grps = line_supergroups.selectAll('.line').data( + function(d) { + return d.data; + }, + function(d) { + return d.key; + } + ); + line_grps.exit().remove(); + var nu_line_grps = line_grps.enter().append('g').attr('class', function(d) { + return d.key + ' line'; + }); + nu_line_grps.append('path'); + nu_line_grps.append('title'); - if (config.x.type === 'ordinal' && !config.x.order) { - config.x.order = current_nested.totalOrder; - } - if (config.y.type === 'ordinal' && !config.y.order) { - config.y.order = current_nested.totalOrder; - } + var linePaths = line_grps + .select('path') + .attr('class', 'wc-data-mark') + .datum(function(d) { + return d.values; + }) + .attr('stroke', function(d) { + return _this.colorScale(d[0].values.raw[0][config.color_by]); + }) + .attr( + 'stroke-width', + config.stroke_width ? config.stroke_width : config.flex_stroke_width + ) + .attr('stroke-linecap', 'round') + .attr('fill', 'none'); + var linePathsTrans = config.transitions ? linePaths.transition() : linePaths; + linePathsTrans.attr('d', line); - this.current_data = current_nested.nested; + line_grps.each(function(d) { + var mark = d3.select(this.parentNode).datum(); + d.tooltip = mark.tooltip; + d3.select(this).select('path').attr(mark.attributes); + }); - this.events.onDatatransform.call(this); + line_grps.select('title').text(function(d) { + var tt = d.tooltip || ''; + var xformat = config.x.summary === 'percent' + ? d3.format('0%') + : d3.format(config.x.format); + var yformat = config.y.summary === 'percent' + ? d3.format('0%') + : d3.format(config.y.format); + return tt + .replace(/\$x/g, xformat(d.values.x)) + .replace(/\$y/g, yformat(d.values.y)) + .replace(/\[(.+?)\]/g, function(str, orig) { + return d.values[0].values.raw[0][orig]; + }); + }); - return { config: mark, data: current_nested.nested, x_dom: x_dom, y_dom: y_dom }; + //Link to the d3.selection from the data + line_supergroups.each(function(d) { + d.supergroup = d3.select(this); + d.groups = d.supergroup.selectAll('g.line'); + d.paths = d.groups.select('path'); + }); + return line_grps; } - function setColorScale() { - var config = this.config; - var data = config.legend.behavior === 'flex' ? this.filtered_data : this.raw_data; - var colordom = Array.isArray(config.color_dom) && config.color_dom.length - ? config.color_dom.slice() - : d3 - .set( - data.map(function(m) { - return m[config.color_by]; - }) - ) - .values() - .filter(function(f) { - return f && f !== 'undefined'; - }); - - if (config.legend.order) - colordom.sort(function(a, b) { - return d3.ascending(config.legend.order.indexOf(a), config.legend.order.indexOf(b)); - }); - else colordom.sort(naturalSorter); - - this.colorScale = d3.scale.ordinal().domain(colordom).range(config.colors); - } + function drawPoints(marks) { + var _this = this; - function xScaleAxis(max_range, domain, type) { - if (max_range === undefined) { - max_range = this.plot_width; - } - if (domain === undefined) { - domain = this.x_dom; - } - if (type === undefined) { - type = this.config.x.type; - } var config = this.config; - var x = void 0; - if (type === 'log') { - x = d3.scale.log(); - } else if (type === 'ordinal') { - x = d3.scale.ordinal(); - } else if (type === 'time') { - x = d3.time.scale(); - } else { - x = d3.scale.linear(); - } - - x.domain(domain); - - if (type === 'ordinal') { - x.rangeBands([0, +max_range], config.padding, config.outer_pad); - } else { - x.range([0, +max_range]).clamp(Boolean(config.x.clamp)); - } + var point_supergroups = this.svg.selectAll('.point-supergroup').data(marks, function(d, i) { + return i + '-' + d.per.join('-'); + }); - var xFormat = config.x.format - ? config.x.format - : config.marks - .map(function(m) { - return m.summarizeX === 'percent'; - }) - .indexOf(true) > -1 - ? '0%' - : type === 'time' ? '%x' : '.0f'; - var tick_count = Math.max(2, Math.min(max_range / 80, 8)); - var xAxis = d3.svg - .axis() - .scale(x) - .orient(config.x.location) - .ticks(tick_count) - .tickFormat( - type === 'ordinal' - ? null - : type === 'time' ? d3.time.format(xFormat) : d3.format(xFormat) - ) - .tickValues(config.x.ticks ? config.x.ticks : null) - .innerTickSize(6) - .outerTickSize(3); + point_supergroups.enter().append('g').attr('class', function(d) { + return 'supergroup point-supergroup ' + d.id; + }); - this.svg.select('g.x.axis').attr('class', 'x axis ' + type); - this.x = x; - this.xAxis = xAxis; - } + point_supergroups.exit().remove(); - function yScaleAxis(max_range, domain, type) { - if (max_range === undefined) { - max_range = this.plot_height; - } - if (domain === undefined) { - domain = this.y_dom; - } - if (type === undefined) { - type = this.config.y.type; - } - var config = this.config; - var y = void 0; - if (type === 'log') { - y = d3.scale.log(); - } else if (type === 'ordinal') { - y = d3.scale.ordinal(); - } else if (type === 'time') { - y = d3.time.scale(); - } else { - y = d3.scale.linear(); - } + var points = point_supergroups.selectAll('.point').data( + function(d) { + return d.data; + }, + function(d) { + return d.key; + } + ); + var oldPoints = points.exit(); - y.domain(domain); + var oldPointsTrans = config.transitions + ? oldPoints.selectAll('circle').transition() + : oldPoints.selectAll('circle'); + oldPointsTrans.attr('r', 0); - if (type === 'ordinal') { - y.rangeBands([+max_range, 0], config.padding, config.outer_pad); - } else { - y.range([+max_range, 0]).clamp(Boolean(config.y_clamp)); - } + var oldPointGroupTrans = config.transitions ? oldPoints.transition() : oldPoints; + oldPointGroupTrans.remove(); - var yFormat = config.y.format - ? config.y.format - : config.marks - .map(function(m) { - return m.summarizeY === 'percent'; - }) - .indexOf(true) > -1 - ? '0%' - : '.0f'; - var tick_count = Math.max(2, Math.min(max_range / 80, 8)); - var yAxis = d3.svg - .axis() - .scale(y) - .orient('left') - .ticks(tick_count) - .tickFormat( - type === 'ordinal' - ? null - : type === 'time' ? d3.time.format(yFormat) : d3.format(yFormat) + var nupoints = points.enter().append('g').attr('class', function(d) { + return d.key + ' point'; + }); + nupoints.append('circle').attr('class', 'wc-data-mark').attr('r', 0); + nupoints.append('title'); + //static attributes + points + .select('circle') + .attr( + 'fill-opacity', + config.fill_opacity || config.fill_opacity === 0 ? config.fill_opacity : 0.6 ) - .tickValues(config.y.ticks ? config.y.ticks : null) - .innerTickSize(6) - .outerTickSize(3); + .attr('fill', function(d) { + return _this.colorScale(d.values.raw[0][config.color_by]); + }) + .attr('stroke', function(d) { + return _this.colorScale(d.values.raw[0][config.color_by]); + }); + //attach mark info + points.each(function(d) { + var mark = d3.select(this.parentNode).datum(); + d.mark = mark; + d3.select(this).select('circle').attr(mark.attributes); + }); + //animated attributes + var pointsTrans = config.transitions + ? points.select('circle').transition() + : points.select('circle'); + pointsTrans + .attr('r', function(d) { + return d.mark.radius || config.flex_point_size; + }) + .attr('cx', function(d) { + var x_pos = _this.x(d.values.x) || 0; + return config.x.type === 'ordinal' ? x_pos + _this.x.rangeBand() / 2 : x_pos; + }) + .attr('cy', function(d) { + var y_pos = _this.y(d.values.y) || 0; + return config.y.type === 'ordinal' ? y_pos + _this.y.rangeBand() / 2 : y_pos; + }); + + points.select('title').text(function(d) { + var tt = d.mark.tooltip || ''; + var xformat = config.x.summary === 'percent' + ? d3.format('0%') + : config.x.type === 'time' + ? d3.time.format(config.x.format) + : d3.format(config.x.format); + var yformat = config.y.summary === 'percent' + ? d3.format('0%') + : config.y.type === 'time' + ? d3.time.format(config.y.format) + : d3.format(config.y.format); + return tt + .replace( + /\$x/g, + config.x.type === 'time' ? xformat(new Date(d.values.x)) : xformat(d.values.x) + ) + .replace( + /\$y/g, + config.y.type === 'time' ? yformat(new Date(d.values.y)) : yformat(d.values.y) + ) + .replace(/\[(.+?)\]/g, function(str, orig) { + return d.values.raw[0][orig]; + }); + }); - this.svg.select('g.y.axis').attr('class', 'y axis ' + type); + //Link to the d3.selection from the data + point_supergroups.each(function(d) { + d.supergroup = d3.select(this); + d.groups = d.supergroup.selectAll('g.point'); + d.circles = d.groups.select('circle'); + }); - this.y = y; - this.yAxis = yAxis; + return points; } - function resize() { - var config = this.config; - - var aspect2 = 1 / config.aspect; - var div_width = parseInt(this.wrap.style('width')); - var max_width = config.max_width ? config.max_width : div_width; - var preWidth = !config.resizable - ? config.width - : !max_width || div_width < max_width ? div_width : this.raw_width; + function drawText(marks) { + var _this = this; - this.textSize(preWidth); + var config = this.config; - this.margin = this.setMargins(); + var textSupergroups = this.svg.selectAll('.text-supergroup').data(marks, function(d, i) { + return i + '-' + d.per.join('-'); + }); - var svg_width = config.x.type === 'ordinal' && +config.x.range_band - ? this.raw_width + this.margin.left + this.margin.right - : !config.resizable - ? this.raw_width - : !config.max_width || div_width < config.max_width ? div_width : this.raw_width; - this.plot_width = svg_width - this.margin.left - this.margin.right; - var svg_height = config.y.type === 'ordinal' && +config.y.range_band - ? this.raw_height + this.margin.top + this.margin.bottom - : !config.resizable && config.height - ? config.height - : !config.resizable ? svg_width * aspect2 : this.plot_width * aspect2; - this.plot_height = svg_height - this.margin.top - this.margin.bottom; + textSupergroups.enter().append('g').attr('class', function(d) { + return 'supergroup text-supergroup ' + d.id; + }); - d3 - .select(this.svg.node().parentNode) - .attr('width', svg_width) - .attr('height', svg_height) - .select('g') - .attr('transform', 'translate(' + this.margin.left + ',' + this.margin.top + ')'); + textSupergroups.exit().remove(); - this.svg - .select('.overlay') - .attr('width', this.plot_width) - .attr('height', this.plot_height) - .classed('zoomable', config.zoomable); + var texts = textSupergroups.selectAll('.text').data( + function(d) { + return d.data; + }, + function(d) { + return d.key; + } + ); + var oldTexts = texts.exit(); - this.svg - .select('.plotting-area') - .attr('width', this.plot_width) - .attr('height', this.plot_height + 1) - .attr('transform', 'translate(0, -1)'); + // don't need to transition position of outgoing text + // const oldTextsTrans = config.transitions ? oldTexts.selectAll('text').transition() : oldTexts.selectAll('text'); - this.xScaleAxis(); - this.yScaleAxis(); + var oldTextGroupTrans = config.transitions ? oldTexts.transition() : oldTexts; + oldTextGroupTrans.remove(); - var g_x_axis = this.svg.select('.x.axis'); - var g_y_axis = this.svg.select('.y.axis'); - var x_axis_label = g_x_axis.select('.axis-title'); - var y_axis_label = g_y_axis.select('.axis-title'); + var nutexts = texts.enter().append('g').attr('class', function(d) { + return d.key + ' text'; + }); + nutexts.append('text').attr('class', 'wc-data-mark'); + // don't need to set initial location for incoming text - if (config.x_location !== 'top') { - g_x_axis.attr('transform', 'translate(0,' + this.plot_height + ')'); + // attach mark info + function attachMarks(d) { + d.mark = d3.select(this.parentNode).datum(); + d3.select(this).select('text').attr(d.mark.attributes); } - var gXAxisTrans = config.transitions ? g_x_axis.transition() : g_x_axis; - gXAxisTrans.call(this.xAxis); - var gYAxisTrans = config.transitions ? g_y_axis.transition() : g_y_axis; - gYAxisTrans.call(this.yAxis); - - x_axis_label.attr( - 'transform', - 'translate(' + this.plot_width / 2 + ',' + (this.margin.bottom - 2) + ')' - ); - y_axis_label.attr('x', -1 * this.plot_height / 2).attr('y', -1 * this.margin.left); + texts.each(attachMarks); - this.svg - .selectAll('.axis .domain') - .attr({ - fill: 'none', - stroke: '#ccc', - 'stroke-width': 1, - 'shape-rendering': 'crispEdges' + // parse text like tooltips + texts.select('text').text(function(d) { + var tt = d.mark.text || ''; + var xformat = config.x.summary === 'percent' + ? d3.format('0%') + : config.x.type === 'time' + ? d3.time.format(config.x.format) + : d3.format(config.x.format); + var yformat = config.y.summary === 'percent' + ? d3.format('0%') + : config.y.type === 'time' + ? d3.time.format(config.y.format) + : d3.format(config.y.format); + return tt + .replace( + /\$x/g, + config.x.type === 'time' ? xformat(new Date(d.values.x)) : xformat(d.values.x) + ) + .replace( + /\$y/g, + config.y.type === 'time' ? yformat(new Date(d.values.y)) : yformat(d.values.y) + ) + .replace(/\[(.+?)\]/g, function(str, orig) { + return d.values.raw[0][orig]; + }); + }); + // animated attributes + var textsTrans = config.transitions + ? texts.select('text').transition() + : texts.select('text'); + textsTrans + .attr('x', function(d) { + var xPos = _this.x(d.values.x) || 0; + return config.x.type === 'ordinal' ? xPos + _this.x.rangeBand() / 2 : xPos; + }) + .attr('y', function(d) { + var yPos = _this.y(d.values.y) || 0; + return config.y.type === 'ordinal' ? yPos + _this.y.rangeBand() / 2 : yPos; }); - this.svg - .selectAll('.axis .tick line') - .attr({ stroke: '#eee', 'stroke-width': 1, 'shape-rendering': 'crispEdges' }); + //add a reference to the selection from it's data + textSupergroups.each(function(d) { + d.supergroup = d3.select(this); + d.groups = d.supergroup.selectAll('g.text'); + d.texts = d.groups.select('text'); + }); + return texts; + } - this.drawGridlines(); + function init(data) { + var _this = this; - //update legend - margins need to be set first - this.makeLegend(); + var test = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; - //update the chart's specific marks - this.updateDataMarks(); + if (d3.select(this.div).select('.loader').empty()) { + d3 + .select(this.div) + .insert('div', ':first-child') + .attr('class', 'loader') + .selectAll('.blockG') + .data(d3.range(8)) + .enter() + .append('div') + .attr('class', function(d) { + return 'blockG rotate' + (d + 1); + }); + } - //call .on("resize") function, if any - this.events.onResize.call(this); - } + this.wrap.attr('class', 'wc-chart'); - function textSize(width) { - var font_size = '14px'; - var point_size = 4; - var stroke_width = 2; + this.setDefaults(); - if (!this.config.scale_text) { - font_size = this.config.font_size; - point_size = this.config.point_size || 4; - stroke_width = this.config.stroke_width || 2; - } else if (width >= 600) { - font_size = '14px'; - point_size = 4; - stroke_width = 2; - } else if (width > 450 && width < 600) { - font_size = '12px'; - point_size = 3; - stroke_width = 2; - } else if (width > 300 && width < 450) { - font_size = '10px'; - point_size = 2; - stroke_width = 2; - } else if (width <= 300) { - font_size = '10px'; - point_size = 2; - stroke_width = 1; - } + this.raw_data = data; + this.initial_data = data; - this.wrap.style('font-size', font_size); - this.config.flex_point_size = point_size; - this.config.flex_stroke_width = stroke_width; - } + var startup = function startup(data) { + //connect this chart and its controls, if any + if (_this.controls) { + _this.controls.targets.push(_this); + if (!_this.controls.ready) { + _this.controls.init(_this.raw_data); + } else { + _this.controls.layout(); + } + } - function setMargins() { - var _this = this; + //make sure container is visible (has height and width) before trying to initialize + var visible = d3.select(_this.div).property('offsetWidth') > 0 || test; + if (!visible) { + console.warn( + 'The chart cannot be initialized inside an element with 0 width. The chart will be initialized as soon as the container element is given a width > 0.' + ); + var onVisible = setInterval(function(i) { + var visible_now = d3.select(_this.div).property('offsetWidth') > 0; + if (visible_now) { + _this.layout(); + _this.draw(); + clearInterval(onVisible); + } + }, 500); + } else { + _this.layout(); + _this.draw(); + } + }; - var y_ticks = this.yAxis.tickFormat() - ? this.y.domain().map(function(m) { - return _this.yAxis.tickFormat()(m); - }) - : this.y.domain(); + this.events.onInit.call(this); + if (this.raw_data.length) { + this.checkRequired(this.raw_data); + } + startup(data); - var max_y_text_length = d3.max( - y_ticks.map(function(m) { - return String(m).length; + return this; + } + + function layout() { + this.svg = this.wrap + .append('svg') + .datum(function() { + return null; + }) // prevent data inheritance + .attr({ + class: 'wc-svg', + xmlns: 'http://www.w3.org/2000/svg', + version: '1.1', + xlink: 'http://www.w3.org/1999/xlink' }) - ); - if (this.config.y_format && this.config.y_format.indexOf('%') > -1) { - max_y_text_length += 1; - } - max_y_text_length = Math.max(2, max_y_text_length); - var x_label_on = this.config.x.label ? 1.5 : 0; - var y_label_on = this.config.y.label ? 1.5 : 0.25; - var font_size = parseInt(this.wrap.style('font-size')); - var x_second = this.config.x2_interval ? 1 : 0; - var y_margin = max_y_text_length * font_size * 0.5 + font_size * y_label_on * 1.5 || 8; - var x_margin = - font_size + font_size / 1.5 + font_size * x_label_on + font_size * x_second || 8; + .append('g') + .style('display', 'inline-block'); - y_margin += 6; - x_margin += 3; + var defs = this.svg.append('defs'); + defs + .append('pattern') + .attr({ + id: 'diagonal-stripes', + x: 0, + y: 0, + width: 3, + height: 8, + patternUnits: 'userSpaceOnUse', + patternTransform: 'rotate(30)' + }) + .append('rect') + .attr({ x: '0', y: '0', width: '2', height: '8', style: 'stroke:none; fill:black' }); - return { - top: this.config.margin && this.config.margin.top ? this.config.margin.top : 8, - right: this.config.margin && this.config.margin.right ? this.config.margin.right : 16, - bottom: this.config.margin && this.config.margin.bottom - ? this.config.margin.bottom - : x_margin, - left: this.config.margin && this.config.margin.left ? this.config.margin.left : y_margin - }; - } + defs.append('clipPath').attr('id', this.id).append('rect').attr('class', 'plotting-area'); - function drawGridLines() { - this.wrap.classed('gridlines', this.config.gridlines); - if (this.config.gridlines) { - this.svg.select('.y.axis').selectAll('.tick line').attr('x1', 0); - this.svg.select('.x.axis').selectAll('.tick line').attr('y1', 0); - if (this.config.gridlines === 'y' || this.config.gridlines === 'xy') - this.svg.select('.y.axis').selectAll('.tick line').attr('x1', this.plot_width); - if (this.config.gridlines === 'x' || this.config.gridlines === 'xy') - this.svg.select('.x.axis').selectAll('.tick line').attr('y1', -this.plot_height); - } else { - this.svg.select('.y.axis').selectAll('.tick line').attr('x1', 0); - this.svg.select('.x.axis').selectAll('.tick line').attr('y1', 0); - } + //y axis + this.svg + .append('g') + .attr('class', 'y axis') + .append('text') + .attr('class', 'axis-title') + .attr('transform', 'rotate(-90)') + .attr('dy', '.75em') + .attr('text-anchor', 'middle'); + //x axis + this.svg + .append('g') + .attr('class', 'x axis') + .append('text') + .attr('class', 'axis-title') + .attr('dy', '-.35em') + .attr('text-anchor', 'middle'); + //overlay + this.svg + .append('rect') + .attr('class', 'overlay') + .attr('opacity', 0) + .attr('fill', 'none') + .style('pointer-events', 'all'); + //add legend + var legend = this.wrap.append('ul').datum(function() { + return null; + }); // prevent data inheritance + legend + .attr('class', 'legend') + .style('vertical-align', 'top') + .append('span') + .attr('class', 'legend-title'); + + d3.select(this.div).select('.loader').remove(); + + this.events.onLayout.call(this); } function makeLegend() { @@ -1564,27 +1418,11 @@ var legendOriginal = this.legend || this.wrap.select('.legend'); var legend = legendOriginal; - if (!this.parent) { - //singular chart - if (this.config.legend.location === 'top' || this.config.legend.location === 'left') { - this.wrap.node().insertBefore(legendOriginal.node(), this.svg.node().parentNode); - } else { - this.wrap.node().appendChild(legendOriginal.node()); - } + if (this.config.legend.location === 'top' || this.config.legend.location === 'left') { + this.wrap.node().insertBefore(legendOriginal.node(), this.svg.node().parentNode); } else { - //multiples - keep legend outside of individual charts' wraps - if (this.config.legend.location === 'top' || this.config.legend.location === 'left') { - this.parent.wrap - .node() - .insertBefore( - legendOriginal.node(), - this.parent.wrap.select('.wc-chart').node() - ); - } else { - this.parent.wrap.node().appendChild(legendOriginal.node()); - } + this.wrap.node().appendChild(legendOriginal.node()); } - legend.style('padding', 0); var legend_data = @@ -1650,7 +1488,7 @@ if (e.mark === 'circle') { svg$$1 .append('circle') - .attr({ cx: '.5em', cy: '.5em', r: '.45em', class: 'legend-mark' }); + .attr({ cx: '.5em', cy: '.45em', r: '.45em', class: 'legend-mark' }); } else if (e.mark === 'line') { svg$$1.append('line').attr({ x1: 0, @@ -1692,9 +1530,8 @@ }); if (scale$$1.domain().length > 0) { - var legendDisplay = (this.config.legend.location === 'bottom' || - this.config.legend.location === 'top') && - !this.parent + var legendDisplay = this.config.legend.location === 'bottom' || + this.config.legend.location === 'top' ? 'block' : 'inline-block'; legend.style('display', legendDisplay); @@ -1705,925 +1542,968 @@ this.legend = legend; } - function updateDataMarks() { - this.drawBars( - this.marks.filter(function(f) { - return f.type === 'bar'; - }) - ); - this.drawLines( - this.marks.filter(function(f) { - return f.type === 'line'; - }) - ); - this.drawPoints( - this.marks.filter(function(f) { - return f.type === 'circle'; - }) - ); - this.drawText( - this.marks.filter(function(f) { - return f.type === 'text'; - }) - ); + function resize() { + var config = this.config; - this.marks.supergroups = this.svg.selectAll('g.supergroup'); - } + var aspect2 = 1 / config.aspect; + var div_width = parseInt(this.wrap.style('width')); + var max_width = config.max_width ? config.max_width : div_width; + var preWidth = !config.resizable + ? config.width + : !max_width || div_width < max_width ? div_width : this.raw_width; - function drawArea(area_drawer, area_data, datum_accessor) { - var class_match = arguments.length > 3 && arguments[3] !== undefined - ? arguments[3] - : 'chart-area'; + this.textSize(preWidth); - var _this = this; + this.margin = this.setMargins(); - var bind_accessor = arguments[4]; - var attr_accessor = arguments.length > 5 && arguments[5] !== undefined - ? arguments[5] - : function(d) { - return d; - }; + var svg_width = config.x.type === 'ordinal' && +config.range_band + ? this.raw_width + this.margin.left + this.margin.right + : !config.resizable + ? this.raw_width + : !config.max_width || div_width < config.max_width ? div_width : this.raw_width; + this.plot_width = svg_width - this.margin.left - this.margin.right; + var svg_height = config.y.type === 'ordinal' && +config.range_band + ? this.raw_height + this.margin.top + this.margin.bottom + : !config.resizable && config.height + ? config.height + : !config.resizable ? svg_width * aspect2 : this.plot_width * aspect2; + this.plot_height = svg_height - this.margin.top - this.margin.bottom; - var area_grps = this.svg.selectAll('.' + class_match).data(area_data, bind_accessor); - area_grps.exit().remove(); - area_grps - .enter() - .append('g') - .attr('class', function(d) { - return class_match + ' ' + d.key; - }) - .append('path'); + d3 + .select(this.svg.node().parentNode) + .attr('width', svg_width) + .attr('height', svg_height) + .select('g') + .attr('transform', 'translate(' + this.margin.left + ',' + this.margin.top + ')'); - var areaPaths = area_grps - .select('path') - .datum(datum_accessor) - .attr('fill', function(d) { - var d_attr = attr_accessor(d); - return d_attr ? _this.colorScale(d_attr[_this.config.color_by]) : null; - }) - .attr( - 'fill-opacity', - this.config.fill_opacity || this.config.fill_opacity === 0 - ? this.config.fill_opacity - : 0.3 - ); + this.svg + .select('.overlay') + .attr('width', this.plot_width) + .attr('height', this.plot_height) + .classed('zoomable', config.zoomable); - //don't transition if config says not to - var areaPathTransitions = this.config.transitions ? areaPaths.transition() : areaPaths; + this.svg + .select('.plotting-area') + .attr('width', this.plot_width) + .attr('height', this.plot_height + 1) + .attr('transform', 'translate(0, -1)'); + + this.xScaleAxis(); + this.yScaleAxis(); + + var g_x_axis = this.svg.select('.x.axis'); + var g_y_axis = this.svg.select('.y.axis'); + var x_axis_label = g_x_axis.select('.axis-title'); + var y_axis_label = g_y_axis.select('.axis-title'); + + if (config.x_location !== 'top') { + g_x_axis.attr('transform', 'translate(0,' + this.plot_height + ')'); + } + var gXAxisTrans = config.transitions ? g_x_axis.transition() : g_x_axis; + gXAxisTrans.call(this.xAxis); + var gYAxisTrans = config.transitions ? g_y_axis.transition() : g_y_axis; + gYAxisTrans.call(this.yAxis); + + x_axis_label.attr( + 'transform', + 'translate(' + this.plot_width / 2 + ',' + (this.margin.bottom - 2) + ')' + ); + y_axis_label.attr('x', -1 * this.plot_height / 2).attr('y', -1 * this.margin.left); + + this.svg + .selectAll('.axis .domain') + .attr({ + fill: 'none', + stroke: '#ccc', + 'stroke-width': 1, + 'shape-rendering': 'crispEdges' + }); + this.svg + .selectAll('.axis .tick line') + .attr({ stroke: '#eee', 'stroke-width': 1, 'shape-rendering': 'crispEdges' }); + + this.drawGridlines(); + //update legend - margins need to be set first + this.makeLegend(); + + //update the chart's specific marks + this.updateDataMarks(); + + //call .on("resize") function, if any + this.events.onResize.call(this); + } + + function setColorScale() { + var config = this.config; + var data = config.legend.behavior === 'flex' ? this.filtered_data : this.raw_data; + var colordom = Array.isArray(config.color_dom) && config.color_dom.length + ? config.color_dom.slice() + : d3 + .set( + data.map(function(m) { + return m[config.color_by]; + }) + ) + .values() + .filter(function(f) { + return f && f !== 'undefined'; + }); - areaPathTransitions.attr('d', area_drawer); + if (config.legend.order) + colordom.sort(function(a, b) { + return d3.ascending(config.legend.order.indexOf(a), config.legend.order.indexOf(b)); + }); + else colordom.sort(naturalSorter); - return area_grps; + this.colorScale = d3.scale.ordinal().domain(colordom).range(config.colors); } - function drawBars(marks) { - var _this = this; + function setDefaults() { + this.config.x = this.config.x || {}; + this.config.y = this.config.y || {}; - var rawData = this.raw_data; - var config = this.config; + this.config.x.label = this.config.x.label !== undefined + ? this.config.x.label + : this.config.x.column; + this.config.y.label = this.config.y.label !== undefined + ? this.config.y.label + : this.config.y.column; - var bar_supergroups = this.svg.selectAll('.bar-supergroup').data(marks, function(d, i) { - return i + '-' + d.per.join('-'); - }); + this.config.x.sort = this.config.x.sort || 'alphabetical-ascending'; + this.config.y.sort = this.config.y.sort || 'alphabetical-descending'; - bar_supergroups.enter().append('g').attr('class', function(d) { - return 'supergroup bar-supergroup ' + d.id; + this.config.x.type = this.config.x.type || 'linear'; + this.config.y.type = this.config.y.type || 'linear'; + + this.config.margin = this.config.margin || {}; + this.config.legend = this.config.legend || {}; + this.config.legend.label = this.config.legend.label !== undefined + ? this.config.legend.label + : this.config.color_by; + this.config.legend.location = this.config.legend.location !== undefined + ? this.config.legend.location + : 'bottom'; + this.config.marks = this.config.marks && this.config.marks.length + ? this.config.marks + : [{}]; + this.config.marks.forEach(function(m, i) { + m.id = m.id ? m.id : 'mark' + (i + 1); }); - bar_supergroups.exit().remove(); + this.config.date_format = this.config.date_format || '%x'; - var bar_groups = bar_supergroups.selectAll('.bar-group').data( - function(d) { - return d.data; - }, - function(d) { - return d.key; - } - ); - var old_bar_groups = bar_groups.exit(); + this.config.padding = this.config.padding !== undefined ? this.config.padding : 0.3; + this.config.outer_pad = this.config.outer_pad !== undefined ? this.config.outer_pad : 0.1; - var nu_bar_groups = void 0; - var bars = void 0; + this.config.resizable = this.config.resizable !== undefined ? this.config.resizable : true; - var oldBarsTrans = config.transitions - ? old_bar_groups.selectAll('.bar').transition() - : old_bar_groups.selectAll('.bar'); - var oldBarGroupsTrans = config.transitions ? old_bar_groups.transition() : old_bar_groups; + this.config.aspect = this.config.aspect || 1.33; - if (config.x.type === 'ordinal') { - oldBarsTrans.attr('y', this.y(0)).attr('height', 0); + this.config.colors = this.config.colors || [ + 'rgb(102,194,165)', + 'rgb(252,141,98)', + 'rgb(141,160,203)', + 'rgb(231,138,195)', + 'rgb(166,216,84)', + 'rgb(255,217,47)', + 'rgb(229,196,148)', + 'rgb(179,179,179)' + ]; - oldBarGroupsTrans.remove(); + this.config.scale_text = this.config.scale_text === undefined + ? true + : this.config.scale_text; + this.config.transitions = this.config.transitions === undefined + ? true + : this.config.transitions; + } - nu_bar_groups = bar_groups.enter().append('g').attr('class', function(d) { - return 'bar-group ' + d.key; - }); - nu_bar_groups.append('title'); + function setMargins() { + var _this = this; - bars = bar_groups.selectAll('rect').data( - function(d) { - return d.values instanceof Array - ? d.values.sort(function(a, b) { - return ( - _this.colorScale.domain().indexOf(b.key) - - _this.colorScale.domain().indexOf(a.key) - ); - }) - : [d]; - }, - function(d) { - return d.key; - } - ); + var y_ticks = this.yAxis.tickFormat() + ? this.y.domain().map(function(m) { + return _this.yAxis.tickFormat()(m); + }) + : this.y.domain(); - var exitBars = config.transitions ? bars.exit().transition() : bars.exit(); - exitBars.attr('y', this.y(0)).attr('height', 0).remove(); - bars - .enter() - .append('rect') - .attr('class', function(d) { - return 'wc-data-mark bar ' + d.key; - }) - .style('clip-path', 'url(#' + this.id + ')') - .attr('y', this.y(0)) - .attr('height', 0) - .append('title'); + var max_y_text_length = d3.max( + y_ticks.map(function(m) { + return String(m).length; + }) + ); + if (this.config.y_format && this.config.y_format.indexOf('%') > -1) { + max_y_text_length += 1; + } + max_y_text_length = Math.max(2, max_y_text_length); + var x_label_on = this.config.x.label ? 1.5 : 0; + var y_label_on = this.config.y.label ? 1.5 : 0.25; + var font_size = parseInt(this.wrap.style('font-size')); + var x_second = this.config.x2_interval ? 1 : 0; + var y_margin = max_y_text_length * font_size * 0.5 + font_size * y_label_on * 1.5 || 8; + var x_margin = + font_size + font_size / 1.5 + font_size * x_label_on + font_size * x_second || 8; - bars - .attr('shape-rendering', 'crispEdges') - .attr('stroke', function(d) { - return _this.colorScale(d.values.raw[0][config.color_by]); - }) - .attr('fill', function(d) { - return _this.colorScale(d.values.raw[0][config.color_by]); - }); + y_margin += 6; + x_margin += 3; - bars.each(function(d) { - var mark = d3.select(this.parentNode.parentNode).datum(); - d.tooltip = mark.tooltip; - d.arrange = mark.split && mark.arrange - ? mark.arrange - : mark.split ? 'grouped' : null; - d.subcats = config.legend.order - ? config.legend.order.slice().reverse() - : mark.values && mark.values[mark.split] - ? mark.values[mark.split] - : d3 - .set( - rawData.map(function(m) { - return m[mark.split]; - }) - ) - .values(); - d3.select(this).attr(mark.attributes); - }); + return { + top: this.config.margin && this.config.margin.top ? this.config.margin.top : 8, + right: this.config.margin && this.config.margin.right ? this.config.margin.right : 16, + bottom: this.config.margin && this.config.margin.bottom + ? this.config.margin.bottom + : x_margin, + left: this.config.margin && this.config.margin.left ? this.config.margin.left : y_margin + }; + } - var xformat = config.marks - .map(function(m) { - return m.summarizeX === 'percent'; - }) - .indexOf(true) > -1 - ? d3.format('0%') - : d3.format(config.x.format); - var yformat = config.marks - .map(function(m) { - return m.summarizeY === 'percent'; - }) - .indexOf(true) > -1 - ? d3.format('0%') - : d3.format(config.y.format); - bars.select('title').text(function(d) { - var tt = d.tooltip || ''; - return tt - .replace(/\$x/g, xformat(d.values.x)) - .replace(/\$y/g, yformat(d.values.y)) - .replace(/\[(.+?)\]/g, function(str, orig) { - return d.values.raw[0][orig]; - }); - }); + function textSize(width) { + var font_size = '14px'; + var point_size = 4; + var stroke_width = 2; - var barsTrans = config.transitions ? bars.transition() : bars; - barsTrans - .attr('x', function(d) { - var position = void 0; - if (!d.arrange || d.arrange === 'stacked') { - return _this.x(d.values.x); - } else if (d.arrange === 'nested') { - var _position = d.subcats.indexOf(d.key); - var offset = _position - ? _this.x.rangeBand() / (d.subcats.length * 0.75) / _position - : _this.x.rangeBand(); - return _this.x(d.values.x) + (_this.x.rangeBand() - offset) / 2; - } else { - position = d.subcats.indexOf(d.key); - return ( - _this.x(d.values.x) + _this.x.rangeBand() / d.subcats.length * position - ); - } - }) - .attr('y', function(d) { - if (d.arrange !== 'stacked') { - return _this.y(d.values.y); - } else { - return _this.y(d.values.start); - } - }) - .attr('width', function(d) { - if (!d.arrange || d.arrange === 'stacked') { - return _this.x.rangeBand(); - } else if (d.arrange === 'nested') { - var position = d.subcats.indexOf(d.key); - return position - ? _this.x.rangeBand() / (d.subcats.length * 0.75) / position - : _this.x.rangeBand(); - } else { - return _this.x.rangeBand() / d.subcats.length; - } - }) - .attr('height', function(d) { - return _this.y(0) - _this.y(d.values.y); - }); - } else if (config.y.type === 'ordinal') { - oldBarsTrans.attr('x', this.x(0)).attr('width', 0); + if (!this.config.scale_text) { + font_size = this.config.font_size; + point_size = this.config.point_size || 4; + stroke_width = this.config.stroke_width || 2; + } else if (width >= 600) { + font_size = '14px'; + point_size = 4; + stroke_width = 2; + } else if (width > 450 && width < 600) { + font_size = '12px'; + point_size = 3; + stroke_width = 2; + } else if (width > 300 && width < 450) { + font_size = '10px'; + point_size = 2; + stroke_width = 2; + } else if (width <= 300) { + font_size = '10px'; + point_size = 2; + stroke_width = 1; + } - oldBarGroupsTrans.remove(); + this.wrap.style('font-size', font_size); + this.config.flex_point_size = point_size; + this.config.flex_stroke_width = stroke_width; + } - nu_bar_groups = bar_groups.enter().append('g').attr('class', function(d) { - return 'bar-group ' + d.key; - }); - nu_bar_groups.append('title'); + var stats = { + mean: d3.mean, + min: d3.min, + max: d3.max, + median: d3.median, + sum: d3.sum + }; - bars = bar_groups.selectAll('rect').data( - function(d) { - return d.values instanceof Array - ? d.values.sort(function(a, b) { - return ( - _this.colorScale.domain().indexOf(b.key) - - _this.colorScale.domain().indexOf(a.key) - ); - }) - : [d]; - }, - function(d) { - return d.key; - } - ); + function summarize(vals) { + var operation = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'mean'; - var _exitBars = config.transitions ? bars.exit().transition() : bars.exit(); - _exitBars.attr('x', this.x(0)).attr('width', 0).remove(); - bars - .enter() - .append('rect') - .attr('class', function(d) { - return 'wc-data-mark bar ' + d.key; - }) - .style('clip-path', 'url(#' + this.id + ')') - .attr('x', this.x(0)) - .attr('width', 0) - .append('title'); + var nvals = vals + .filter(function(f) { + return +f || +f === 0; + }) + .map(function(m) { + return +m; + }); - bars - .attr('shape-rendering', 'crispEdges') - .attr('stroke', function(d) { - return _this.colorScale(d.values.raw[0][config.color_by]); - }) - .attr('fill', function(d) { - return _this.colorScale(d.values.raw[0][config.color_by]); - }); + if (operation === 'cumulative') { + return null; + } - bars.each(function(d) { - var mark = d3.select(this.parentNode.parentNode).datum(); - d.arrange = mark.split && mark.arrange - ? mark.arrange - : mark.split ? 'grouped' : null; - d.subcats = config.legend.order - ? config.legend.order.slice().reverse() - : mark.values && mark.values[mark.split] - ? mark.values[mark.split] - : d3 - .set( - rawData.map(function(m) { - return m[mark.split]; - }) - ) - .values(); - d.tooltip = mark.tooltip; - d3.select(this).attr(mark.attributes); - }); + var mathed = operation === 'count' + ? vals.length + : operation === 'percent' ? vals.length : stats[operation](nvals); - var _xformat = config.marks - .map(function(m) { - return m.summarizeX === 'percent'; - }) - .indexOf(true) > -1 - ? d3.format('0%') - : d3.format(config.x.format); - var _yformat = config.marks - .map(function(m) { - return m.summarizeY === 'percent'; - }) - .indexOf(true) > -1 - ? d3.format('0%') - : d3.format(config.y.format); - bars.select('title').text(function(d) { - var tt = d.tooltip || ''; - return tt - .replace(/\$x/g, _xformat(d.values.x)) - .replace(/\$y/g, _yformat(d.values.y)) - .replace(/\[(.+?)\]/g, function(str, orig) { - return d.values.raw[0][orig]; - }); - }); + return mathed; + } - var _barsTrans = config.transitions ? bars.transition() : bars; - _barsTrans - .attr('x', function(d) { - if (d.arrange === 'stacked' || !d.arrange) { - return d.values.start !== undefined ? _this.x(d.values.start) : _this.x(0); - } else { - return _this.x(0); - } - }) - .attr('y', function(d) { - if (d.arrange === 'nested') { - var position = d.subcats.indexOf(d.key); - var offset = position - ? _this.y.rangeBand() / (d.subcats.length * 0.75) / position - : _this.y.rangeBand(); - return _this.y(d.values.y) + (_this.y.rangeBand() - offset) / 2; - } else if (d.arrange === 'grouped') { - var _position2 = d.subcats.indexOf(d.key); - return ( - _this.y(d.values.y) + - _this.y.rangeBand() / d.subcats.length * _position2 - ); - } else { - return _this.y(d.values.y); - } - }) - .attr('width', function(d) { - return _this.x(d.values.x) - _this.x(0); - }) - .attr('height', function(d) { - if (config.y.type === 'quantile') { - return 20; - } else if (d.arrange === 'nested') { - var position = d.subcats.indexOf(d.key); - return position - ? _this.y.rangeBand() / (d.subcats.length * 0.75) / position - : _this.y.rangeBand(); - } else if (d.arrange === 'grouped') { - return _this.y.rangeBand() / d.subcats.length; - } else { - return _this.y.rangeBand(); - } - }); - } else if (['linear', 'log'].indexOf(config.x.type) > -1 && config.x.bin) { - oldBarsTrans.attr('y', this.y(0)).attr('height', 0); + ////////////////////////////////////////////////////////// + // transformData(raw, mark) provides specifications and data for + // each set of marks. As such, it is called once for each + // item specified in the config.marks array. + // + // parameters + // raw - the raw data for use in the mark. Filters from controls + // are typically already applied. + // mark - a single mark object from config.marks + //////////////////////////////////////////////////////// - oldBarGroupsTrans.remove(); + function transformData(raw, mark) { + var _this = this; - nu_bar_groups = bar_groups.enter().append('g').attr('class', function(d) { - return 'bar-group ' + d.key; - }); - nu_bar_groups.append('title'); + //convenience mappings + var config = this.config; + var x_behavior = config.x.behavior || 'raw'; + var y_behavior = config.y.behavior || 'raw'; + var sublevel = mark.type === 'line' + ? config.x.column + : mark.type === 'bar' && mark.split ? mark.split : null; + var dateConvert = d3.time.format(config.date_format); + var totalOrder = void 0; - bars = bar_groups.selectAll('rect').data( - function(d) { - return d.values instanceof Array ? d.values : [d]; - }, - function(d) { - return d.key; - } + /////////////////////////////////////////////// + // calcStartTotal() - method to calculate percentages in bars + ////////////////////////////////////////////// + function calcStartTotal(e) { + var axis = config.x.type === 'ordinal' || (config.x.type === 'linear' && config.x.bin) + ? 'y' + : 'x'; + e.total = d3.sum( + e.values.map(function(m) { + return +m.values[axis]; + }) ); + var counter = 0; + e.values.forEach(function(v, i) { + if (config.x.type === 'ordinal' || (config.x.type === 'linear' && config.x.bin)) { + v.values.y = mark.summarizeY === 'percent' + ? v.values.y / e.total + : v.values.y || 0; + counter += +v.values.y; + v.values.start = e.values[i - 1] ? counter : v.values.y; + } else { + v.values.x = mark.summarizeX === 'percent' + ? v.values.x / e.total + : v.values.x || 0; + v.values.start = counter; + counter += +v.values.x; + } + }); + } - var _exitBars2 = config.transitions ? bars.exit().transition() : bars.exit(); - _exitBars2.attr('y', this.y(0)).attr('height', 0).remove(); - bars - .enter() - .append('rect') - .attr('class', function(d) { - return 'wc-data-mark bar ' + d.key; - }) - .style('clip-path', 'url(#' + this.id + ')') - .attr('y', this.y(0)) - .attr('height', 0) - .append('title'); + function makeNest(entries, sublevel) { + var dom_xs = []; + var dom_ys = []; + var this_nest = d3.nest(); - bars - .attr('shape-rendering', 'crispEdges') - .attr('stroke', function(d) { - return _this.colorScale(d.values.raw[0][config.color_by]); - }) - .attr('fill', function(d) { - return _this.colorScale(d.values.raw[0][config.color_by]); + if ( + (config.x.type === 'linear' && config.x.bin) || + (config.y.type === 'linear' && config.y.bin) + ) { + var xy = config.x.type === 'linear' && config.x.bin ? 'x' : 'y'; + var quant = d3.scale + .quantile() + .domain( + d3.extent( + entries.map(function(m) { + return +m[config[xy].column]; + }) + ) + ) + .range(d3.range(+config[xy].bin)); + + entries.forEach(function(e) { + return (e.wc_bin = quant(e[config[xy].column])); }); - bars.each(function(d) { - var mark = d3.select(this.parentNode.parentNode).datum(); - d.arrange = mark.split ? mark.arrange : null; - d.subcats = config.legend.order - ? config.legend.order.slice().reverse() - : mark.values && mark.values[mark.split] - ? mark.values[mark.split] - : d3 - .set( - rawData.map(function(m) { - return m[mark.split]; - }) - ) - .values(); - d3.select(this).attr(mark.attributes); - var parent = d3.select(this.parentNode).datum(); - var rangeSet = parent.key.split(',').map(function(m) { - return +m; + this_nest.key(function(d) { + return quant.invertExtent(d.wc_bin); }); - d.rangeLow = d3.min(rangeSet); - d.rangeHigh = d3.max(rangeSet); - d.tooltip = mark.tooltip; - }); + } else { + this_nest.key(function(d) { + return mark.per + .map(function(m) { + return d[m]; + }) + .join(' '); + }); + } - var _xformat2 = config.marks - .map(function(m) { - return m.summarizeX === 'percent'; - }) - .indexOf(true) > -1 - ? d3.format('0%') - : d3.format(config.x.format); - var _yformat2 = config.marks - .map(function(m) { - return m.summarizeY === 'percent'; - }) - .indexOf(true) > -1 - ? d3.format('0%') - : d3.format(config.y.format); - bars.select('title').text(function(d) { - var tt = d.tooltip || ''; - return tt - .replace(/\$x/g, _xformat2(d.values.x)) - .replace(/\$y/g, _yformat2(d.values.y)) - .replace(/\[(.+?)\]/g, function(str, orig) { - return d.values.raw[0][orig]; + if (sublevel) { + this_nest.key(function(d) { + return d[sublevel]; + }); + this_nest.sortKeys(function(a, b) { + return config.x.type === 'time' + ? d3.ascending(new Date(a), new Date(b)) + : config.x.order + ? d3.ascending(config.x.order.indexOf(a), config.x.order.indexOf(b)) + : sublevel === config.color_by && config.legend.order + ? d3.ascending( + config.legend.order.indexOf(a), + config.legend.order.indexOf(b) + ) + : config.x.type === 'ordinal' || config.y.type === 'ordinal' + ? naturalSorter(a, b) + : d3.ascending(+a, +b); + }); + } + this_nest.rollup(function(r) { + var obj = { raw: r }; + var y_vals = r + .map(function(m) { + return m[config.y.column]; + }) + .sort(d3.ascending); + var x_vals = r + .map(function(m) { + return m[config.x.column]; + }) + .sort(d3.ascending); + obj.x = config.x.type === 'ordinal' + ? r[0][config.x.column] + : summarize(x_vals, mark.summarizeX); + obj.y = config.y.type === 'ordinal' + ? r[0][config.y.column] + : summarize(y_vals, mark.summarizeY); + + obj.x_q25 = config.error_bars && config.y.type === 'ordinal' + ? d3.quantile(x_vals, 0.25) + : obj.x; + obj.x_q75 = config.error_bars && config.y.type === 'ordinal' + ? d3.quantile(x_vals, 0.75) + : obj.x; + obj.y_q25 = config.error_bars ? d3.quantile(y_vals, 0.25) : obj.y; + obj.y_q75 = config.error_bars ? d3.quantile(y_vals, 0.75) : obj.y; + dom_xs.push([obj.x_q25, obj.x_q75, obj.x]); + dom_ys.push([obj.y_q25, obj.y_q75, obj.y]); + + if (mark.summarizeY === 'cumulative') { + var interm = entries.filter(function(f) { + return config.x.type === 'time' + ? new Date(f[config.x.column]) <= new Date(r[0][config.x.column]) + : +f[config.x.column] <= +r[0][config.x.column]; }); - }); + if (mark.per.length) { + interm = interm.filter(function(f) { + return f[mark.per[0]] === r[0][mark.per[0]]; + }); + } - var _barsTrans2 = config.transitions ? bars.transition() : bars; - _barsTrans2 - .attr('x', function(d) { - return _this.x(d.rangeLow); - }) - .attr('y', function(d) { - if (d.arrange !== 'stacked') { - return _this.y(d.values.y); - } else { - return _this.y(d.values.start); + var cumul = config.x.type === 'time' + ? interm.length + : d3.sum( + interm.map(function(m) { + return +m[config.y.column] || +m[config.y.column] === 0 + ? +m[config.y.column] + : 1; + }) + ); + dom_ys.push([cumul]); + obj.y = cumul; + } + if (mark.summarizeX === 'cumulative') { + var _interm = entries.filter(function(f) { + return config.y.type === 'time' + ? new Date(f[config.y.column]) <= new Date(r[0][config.y.column]) + : +f[config.y.column] <= +r[0][config.y.column]; + }); + if (mark.per.length) { + _interm = _interm.filter(function(f) { + return f[mark.per[0]] === r[0][mark.per[0]]; + }); } - }) - .attr('width', function(d) { - return _this.x(d.rangeHigh) - _this.x(d.rangeLow); - }) - .attr('height', function(d) { - return _this.y(0) - _this.y(d.values.y); - }); - } else if ( - ['linear', 'log'].indexOf(config.y.type) > -1 && - config.y.type === 'linear' && - config.y.bin - ) { - oldBarsTrans.attr('x', this.x(0)).attr('width', 0); - oldBarGroupsTrans.remove(); + dom_xs.push([_interm.length]); + obj.x = _interm.length; + } - nu_bar_groups = bar_groups.enter().append('g').attr('class', function(d) { - return 'bar-group ' + d.key; + return obj; }); - nu_bar_groups.append('title'); - bars = bar_groups.selectAll('rect').data( - function(d) { - return d.values instanceof Array ? d.values : [d]; - }, - function(d) { - return d.key; - } - ); + var test = this_nest.entries(entries); - var _exitBars3 = config.transitions ? bars.exit().transition() : bars.exit(); - _exitBars3.attr('x', this.x(0)).attr('width', 0).remove(); - bars - .enter() - .append('rect') - .attr('class', function(d) { - return 'wc-data-mark bar ' + d.key; - }) - .style('clip-path', 'url(#' + this.id + ')') - .attr('x', this.x(0)) - .attr('width', 0) - .append('title'); + var dom_x = d3.extent(d3.merge(dom_xs)); + var dom_y = d3.extent(d3.merge(dom_ys)); - bars - .attr('shape-rendering', 'crispEdges') - .attr('stroke', function(d) { - return _this.colorScale(d.values.raw[0][config.color_by]); - }) - .attr('fill', function(d) { - return _this.colorScale(d.values.raw[0][config.color_by]); + if (sublevel && mark.type === 'bar' && mark.arrange === 'stacked') { + test.forEach(calcStartTotal); + if (config.x.type === 'ordinal' || (config.x.type === 'linear' && config.x.bin)) { + dom_y = d3.extent( + test.map(function(m) { + return m.total; + }) + ); + } + if (config.y.type === 'ordinal' || (config.y.type === 'linear' && config.y.bin)) { + dom_x = d3.extent( + test.map(function(m) { + return m.total; + }) + ); + } + } else if (sublevel && mark.type === 'bar' && mark.split) { + test.forEach(calcStartTotal); + } else { + var axis = config.x.type === 'ordinal' || + (config.x.type === 'linear' && config.x.bin) + ? 'y' + : 'x'; + test.forEach(function(e) { + return (e.total = e.values[axis]); }); + } - bars.each(function(d) { - var mark = d3.select(this.parentNode.parentNode).datum(); - d.arrange = mark.split ? mark.arrange : null; - d.subcats = config.legend.order - ? config.legend.order.slice().reverse() - : mark.values && mark.values[mark.split] - ? mark.values[mark.split] - : d3 - .set( - rawData.map(function(m) { - return m[mark.split]; - }) - ) - .values(); - var parent = d3.select(this.parentNode).datum(); - var rangeSet = parent.key.split(',').map(function(m) { - return +m; - }); - d.rangeLow = d3.min(rangeSet); - d.rangeHigh = d3.max(rangeSet); - d.tooltip = mark.tooltip; + if ( + (config.x.sort === 'total-ascending' && config.x.type == 'ordinal') || + (config.y.sort === 'total-descending' && config.y.type == 'ordinal') + ) { + totalOrder = test + .sort(function(a, b) { + return d3.ascending(a.total, b.total); + }) + .map(function(m) { + return m.key; + }); + } else if ( + (config.x.sort === 'total-descending' && config.x.type == 'ordinal') || + (config.y.sort === 'total-ascending' && config.y.type == 'ordinal') + ) { + totalOrder = test + .sort(function(a, b) { + return d3.descending(+a.total, +b.total); + }) + .map(function(m) { + return m.key; + }); + } + + return { nested: test, dom_x: dom_x, dom_y: dom_y }; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DATA PREP + // prepare data based on the properties of the mark - drop missing records, etc + ////////////////////////////////////////////////////////////////////////////////// + + // only use data for the current mark + raw = mark.per && mark.per.length + ? raw.filter(function(f) { + return f[mark.per[0]]; + }) + : raw; + + // Make sure data has x and y values + if (config.x.column) { + raw = raw.filter(function(f) { + return f[config.x.column] !== undefined; }); + } + if (config.y.column) { + raw = raw.filter(function(f) { + return f[config.y.column] !== undefined; + }); + } - var _xformat3 = config.marks - .map(function(m) { - return m.summarizeX === 'percent'; - }) - .indexOf(true) > -1 - ? d3.format('0%') - : d3.format(config.x.format); - var _yformat3 = config.marks - .map(function(m) { - return m.summarizeY === 'percent'; - }) - .indexOf(true) > -1 - ? d3.format('0%') - : d3.format(config.y.format); - bars.select('title').text(function(d) { - var tt = d.tooltip || ''; - return tt - .replace(/\$x/g, _xformat3(d.values.x)) - .replace(/\$y/g, _yformat3(d.values.y)) - .replace(/\[(.+?)\]/g, function(str, orig) { - return d.values.raw[0][orig]; - }); + //check that x and y have the correct formats + if (config.x.type === 'time') { + raw = raw.filter(function(f) { + return f[config.x.column] instanceof Date + ? f[config.x.column] + : dateConvert.parse(f[config.x.column]); + }); + raw.forEach(function(e) { + return (e[config.x.column] = e[config.x.column] instanceof Date + ? e[config.x.column] + : dateConvert.parse(e[config.x.column])); + }); + } + if (config.y.type === 'time') { + raw = raw.filter(function(f) { + return f[config.y.column] instanceof Date + ? f[config.y.column] + : dateConvert.parse(f[config.y.column]); + }); + raw.forEach(function(e) { + return (e[config.y.column] = e[config.y.column] instanceof Date + ? e[config.y.column] + : dateConvert.parse(e[config.y.column])); }); + } - var _barsTrans3 = config.transitions ? bars.transition() : bars; - _barsTrans3 - .attr('x', function(d) { - if (d.arrange === 'stacked') { - return _this.x(d.values.start); - } else { - return _this.x(0); - } - }) - .attr('y', function(d) { - return _this.y(d.rangeHigh); - }) - .attr('width', function(d) { - return _this.x(d.values.x); - }) - .attr('height', function(d) { - return _this.y(d.rangeLow) - _this.y(d.rangeHigh); - }); - } else { - oldBarsTrans.attr('y', this.y(0)).attr('height', 0); - oldBarGroupsTrans.remove(); - bar_supergroups.remove(); + if ((config.x.type === 'linear' || config.x.type === 'log') && config.x.column) { + raw = raw.filter(function(f) { + return mark.summarizeX !== 'count' && mark.summarizeX !== 'percent' + ? +f[config.x.column] || +f[config.x.column] === 0 + : f; + }); + } + if ((config.y.type === 'linear' || config.y.type === 'log') && config.y.column) { + raw = raw.filter(function(f) { + return mark.summarizeY !== 'count' && mark.summarizeY !== 'percent' + ? +f[config.y.column] || +f[config.y.column] === 0 + : f; + }); } - //Link to the d3.selection from the data - bar_supergroups.each(function(d) { - d.supergroup = d3.select(this); - d.groups = d.supergroup.selectAll('.bar-group'); - }); - } + //prepare nested data required for bar charts + var raw_nest = void 0; + if (mark.type === 'bar') { + raw_nest = mark.arrange !== 'stacked' ? makeNest(raw, sublevel) : makeNest(raw); + } else if (mark.summarizeX === 'count' || mark.summarizeY === 'count') { + raw_nest = makeNest(raw); + } + + // Get the domain for the mark based on the raw data + var raw_dom_x = mark.summarizeX === 'cumulative' + ? [0, raw.length] + : config.x.type === 'ordinal' + ? d3 + .set( + raw.map(function(m) { + return m[config.x.column]; + }) + ) + .values() + .filter(function(f) { + return f; + }) + : mark.split && mark.arrange !== 'stacked' + ? d3.extent( + d3.merge( + raw_nest.nested.map(function(m) { + return m.values.map(function(p) { + return p.values.raw.length; + }); + }) + ) + ) + : mark.summarizeX === 'count' + ? d3.extent( + raw_nest.nested.map(function(m) { + return m.values.raw.length; + }) + ) + : d3.extent( + raw + .map(function(m) { + return +m[config.x.column]; + }) + .filter(function(f) { + return +f || +f === 0; + }) + ); + + var raw_dom_y = mark.summarizeY === 'cumulative' + ? [0, raw.length] + : config.y.type === 'ordinal' + ? d3 + .set( + raw.map(function(m) { + return m[config.y.column]; + }) + ) + .values() + .filter(function(f) { + return f; + }) + : mark.split && mark.arrange !== 'stacked' + ? d3.extent( + d3.merge( + raw_nest.nested.map(function(m) { + return m.values.map(function(p) { + return p.values.raw.length; + }); + }) + ) + ) + : mark.summarizeY === 'count' + ? d3.extent( + raw_nest.nested.map(function(m) { + return m.values.raw.length; + }) + ) + : d3.extent( + raw + .map(function(m) { + return +m[config.y.column]; + }) + .filter(function(f) { + return +f || +f === 0; + }) + ); - function drawLines(marks) { - var _this = this; + var filtered = raw; - var config = this.config; - var line = d3.svg - .line() - .interpolate(config.interpolate) - .x(function(d) { - return config.x.type === 'linear' || config.x.type == 'log' - ? _this.x(+d.values.x) - : config.x.type === 'time' - ? _this.x(new Date(d.values.x)) - : _this.x(d.values.x) + _this.x.rangeBand() / 2; - }) - .y(function(d) { - return config.y.type === 'linear' || config.y.type == 'log' - ? _this.y(+d.values.y) - : config.y.type === 'time' - ? _this.y(new Date(d.values.y)) - : _this.y(d.values.y) + _this.y.rangeBand() / 2; + var filt1_xs = []; + var filt1_ys = []; + if (this.filters.length) { + this.filters.forEach(function(e) { + filtered = filtered.filter(function(d) { + return e.val === 'All' + ? d + : e.val instanceof Array + ? e.val.indexOf(d[e.col]) > -1 + : d[e.col] === e.val; + }); }); + //get domain for all non-All values of first filter + if (config.x.behavior === 'firstfilter' || config.y.behavior === 'firstfilter') { + this.filters[0].choices + .filter(function(f) { + return f !== 'All'; + }) + .forEach(function(e) { + var perfilter = raw.filter(function(f) { + return f[_this.filters[0].col] === e; + }); + var filt_nested = makeNest(perfilter, sublevel); + filt1_xs.push(filt_nested.dom_x); + filt1_ys.push(filt_nested.dom_y); + }); + } + } - var line_supergroups = this.svg.selectAll('.line-supergroup').data(marks, function(d, i) { - return i + '-' + d.per.join('-'); - }); - - line_supergroups.enter().append('g').attr('class', function(d) { - return 'supergroup line-supergroup ' + d.id; - }); - - line_supergroups.exit().remove(); + //filter on mark-specific instructions + if (mark.values) { + var _loop = function _loop(a) { + filtered = filtered.filter(function(f) { + return mark.values[a].indexOf(f[a]) > -1; + }); + }; - var line_grps = line_supergroups.selectAll('.line').data( - function(d) { - return d.data; - }, - function(d) { - return d.key; + for (var a in mark.values) { + _loop(a); } - ); - line_grps.exit().remove(); - var nu_line_grps = line_grps.enter().append('g').attr('class', function(d) { - return d.key + ' line'; - }); - nu_line_grps.append('path'); - nu_line_grps.append('title'); + } + var filt1_dom_x = d3.extent(d3.merge(filt1_xs)); + var filt1_dom_y = d3.extent(d3.merge(filt1_ys)); - var linePaths = line_grps - .select('path') - .attr('class', 'wc-data-mark') - .datum(function(d) { - return d.values; - }) - .attr('stroke', function(d) { - return _this.colorScale(d[0].values.raw[0][config.color_by]); - }) - .attr( - 'stroke-width', - config.stroke_width ? config.stroke_width : config.flex_stroke_width - ) - .attr('stroke-linecap', 'round') - .attr('fill', 'none'); - var linePathsTrans = config.transitions ? linePaths.transition() : linePaths; - linePathsTrans.attr('d', line); + var current_nested = makeNest(filtered, sublevel); - line_grps.each(function(d) { - var mark = d3.select(this.parentNode).datum(); - d.tooltip = mark.tooltip; - d3.select(this).select('path').attr(mark.attributes); - }); + var flex_dom_x = current_nested.dom_x; + var flex_dom_y = current_nested.dom_y; - line_grps.select('title').text(function(d) { - var tt = d.tooltip || ''; - var xformat = config.x.summary === 'percent' - ? d3.format('0%') - : d3.format(config.x.format); - var yformat = config.y.summary === 'percent' - ? d3.format('0%') - : d3.format(config.y.format); - return tt - .replace(/\$x/g, xformat(d.values.x)) - .replace(/\$y/g, yformat(d.values.y)) - .replace(/\[(.+?)\]/g, function(str, orig) { - return d.values[0].values.raw[0][orig]; - }); - }); + if (mark.type === 'bar') { + if (config.y.type === 'ordinal' && mark.summarizeX === 'count') { + config.x.domain = config.x.domain ? [0, config.x.domain[1]] : [0, null]; + } else if (config.x.type === 'ordinal' && mark.summarizeY === 'count') { + config.y.domain = config.y.domain ? [0, config.y.domain[1]] : [0, null]; + } + } - //Link to the d3.selection from the data - line_supergroups.each(function(d) { - d.supergroup = d3.select(this); - d.groups = d.supergroup.selectAll('g.line'); - d.paths = d.groups.select('path'); - }); - return line_grps; - } + //several criteria must be met in order to use the 'firstfilter' domain + var nonall = Boolean( + this.filters.length && + this.filters[0].val !== 'All' && + this.filters.slice(1).filter(function(f) { + return f.val === 'All'; + }).length === + this.filters.length - 1 + ); - function drawPoints(marks) { - var _this = this; + var pre_x_dom = !this.filters.length + ? flex_dom_x + : x_behavior === 'raw' + ? raw_dom_x + : nonall && x_behavior === 'firstfilter' ? filt1_dom_x : flex_dom_x; + var pre_y_dom = !this.filters.length + ? flex_dom_y + : y_behavior === 'raw' + ? raw_dom_y + : nonall && y_behavior === 'firstfilter' ? filt1_dom_y : flex_dom_y; - var config = this.config; + var x_dom = config.x_dom + ? config.x_dom + : config.x.type === 'ordinal' && config.x.behavior === 'flex' + ? d3 + .set( + filtered.map(function(m) { + return m[config.x.column]; + }) + ) + .values() + : config.x.type === 'ordinal' + ? d3 + .set( + raw.map(function(m) { + return m[config.x.column]; + }) + ) + .values() + : config.x_from0 ? [0, d3.max(pre_x_dom)] : pre_x_dom; - var point_supergroups = this.svg.selectAll('.point-supergroup').data(marks, function(d, i) { - return i + '-' + d.per.join('-'); - }); + var y_dom = config.y_dom + ? config.y_dom + : config.y.type === 'ordinal' && config.y.behavior === 'flex' + ? d3 + .set( + filtered.map(function(m) { + return m[config.y.column]; + }) + ) + .values() + : config.y.type === 'ordinal' + ? d3 + .set( + raw.map(function(m) { + return m[config.y.column]; + }) + ) + .values() + : config.y_from0 ? [0, d3.max(pre_y_dom)] : pre_y_dom; - point_supergroups.enter().append('g').attr('class', function(d) { - return 'supergroup point-supergroup ' + d.id; - }); + if (config.x.domain && (config.x.domain[0] || config.x.domain[0] === 0)) { + x_dom[0] = config.x.domain[0]; + } + if (config.x.domain && (config.x.domain[1] || config.x.domain[1] === 0)) { + x_dom[1] = config.x.domain[1]; + } + if (config.y.domain && (config.y.domain[0] || config.y.domain[0] === 0)) { + y_dom[0] = config.y.domain[0]; + } + if (config.y.domain && (config.y.domain[1] || config.y.domain[1] === 0)) { + y_dom[1] = config.y.domain[1]; + } - point_supergroups.exit().remove(); + if (config.x.type === 'ordinal' && !config.x.order) { + config.x.order = totalOrder; + } + if (config.y.type === 'ordinal' && !config.y.order) { + config.y.order = totalOrder; + } - var points = point_supergroups.selectAll('.point').data( - function(d) { - return d.data; - }, - function(d) { - return d.key; - } - ); - var oldPoints = points.exit(); + this.current_data = current_nested.nested; - var oldPointsTrans = config.transitions - ? oldPoints.selectAll('circle').transition() - : oldPoints.selectAll('circle'); - oldPointsTrans.attr('r', 0); + this.events.onDatatransform.call(this); - var oldPointGroupTrans = config.transitions ? oldPoints.transition() : oldPoints; - oldPointGroupTrans.remove(); + return { config: mark, data: current_nested.nested, x_dom: x_dom, y_dom: y_dom }; + } - var nupoints = points.enter().append('g').attr('class', function(d) { - return d.key + ' point'; - }); - nupoints.append('circle').attr('class', 'wc-data-mark').attr('r', 0); - nupoints.append('title'); - //static attributes - points - .select('circle') - .attr( - 'fill-opacity', - config.fill_opacity || config.fill_opacity === 0 ? config.fill_opacity : 0.6 - ) - .attr('fill', function(d) { - return _this.colorScale(d.values.raw[0][config.color_by]); + function updateDataMarks() { + this.drawBars( + this.marks.filter(function(f) { + return f.type === 'bar'; }) - .attr('stroke', function(d) { - return _this.colorScale(d.values.raw[0][config.color_by]); - }); - //attach mark info - points.each(function(d) { - var mark = d3.select(this.parentNode).datum(); - d.mark = mark; - d3.select(this).select('circle').attr(mark.attributes); - }); - //animated attributes - var pointsTrans = config.transitions - ? points.select('circle').transition() - : points.select('circle'); - pointsTrans - .attr('r', function(d) { - return d.mark.radius || config.flex_point_size; + ); + this.drawLines( + this.marks.filter(function(f) { + return f.type === 'line'; }) - .attr('cx', function(d) { - var x_pos = _this.x(d.values.x) || 0; - return config.x.type === 'ordinal' ? x_pos + _this.x.rangeBand() / 2 : x_pos; + ); + this.drawPoints( + this.marks.filter(function(f) { + return f.type === 'circle'; }) - .attr('cy', function(d) { - var y_pos = _this.y(d.values.y) || 0; - return config.y.type === 'ordinal' ? y_pos + _this.y.rangeBand() / 2 : y_pos; - }); - - points.select('title').text(function(d) { - var tt = d.mark.tooltip || ''; - var xformat = config.x.summary === 'percent' - ? d3.format('0%') - : config.x.type === 'time' - ? d3.time.format(config.x.format) - : d3.format(config.x.format); - var yformat = config.y.summary === 'percent' - ? d3.format('0%') - : config.y.type === 'time' - ? d3.time.format(config.y.format) - : d3.format(config.y.format); - return tt - .replace( - /\$x/g, - config.x.type === 'time' ? xformat(new Date(d.values.x)) : xformat(d.values.x) - ) - .replace( - /\$y/g, - config.y.type === 'time' ? yformat(new Date(d.values.y)) : yformat(d.values.y) - ) - .replace(/\[(.+?)\]/g, function(str, orig) { - return d.values.raw[0][orig]; - }); - }); - - //Link to the d3.selection from the data - point_supergroups.each(function(d) { - d.supergroup = d3.select(this); - d.groups = d.supergroup.selectAll('g.point'); - d.circles = d.groups.select('circle'); - }); + ); + this.drawText( + this.marks.filter(function(f) { + return f.type === 'text'; + }) + ); - return points; + this.marks.supergroups = this.svg.selectAll('g.supergroup'); } - function drawText(marks) { - var _this = this; - + function xScaleAxis(max_range, domain, type) { + if (max_range === undefined) { + max_range = this.plot_width; + } + if (domain === undefined) { + domain = this.x_dom; + } + if (type === undefined) { + type = this.config.x.type; + } var config = this.config; + var x = void 0; - var textSupergroups = this.svg.selectAll('.text-supergroup').data(marks, function(d, i) { - return i + '-' + d.per.join('-'); - }); - - textSupergroups.enter().append('g').attr('class', function(d) { - return 'supergroup text-supergroup ' + d.id; - }); - - textSupergroups.exit().remove(); + if (type === 'log') { + x = d3.scale.log(); + } else if (type === 'ordinal') { + x = d3.scale.ordinal(); + } else if (type === 'time') { + x = d3.time.scale(); + } else { + x = d3.scale.linear(); + } - var texts = textSupergroups.selectAll('.text').data( - function(d) { - return d.data; - }, - function(d) { - return d.key; - } - ); - var oldTexts = texts.exit(); + x.domain(domain); - // don't need to transition position of outgoing text - // const oldTextsTrans = config.transitions ? oldTexts.selectAll('text').transition() : oldTexts.selectAll('text'); + if (type === 'ordinal') { + x.rangeBands([0, +max_range], config.padding, config.outer_pad); + } else { + x.range([0, +max_range]).clamp(Boolean(config.x.clamp)); + } - var oldTextGroupTrans = config.transitions ? oldTexts.transition() : oldTexts; - oldTextGroupTrans.remove(); + var xFormat = config.x.format + ? config.x.format + : config.marks + .map(function(m) { + return m.summarizeX === 'percent'; + }) + .indexOf(true) > -1 + ? '0%' + : type === 'time' ? '%x' : '.0f'; + var tick_count = Math.max(2, Math.min(max_range / 80, 8)); + var xAxis = d3.svg + .axis() + .scale(x) + .orient(config.x.location) + .ticks(tick_count) + .tickFormat( + type === 'ordinal' + ? null + : type === 'time' ? d3.time.format(xFormat) : d3.format(xFormat) + ) + .tickValues(config.x.ticks ? config.x.ticks : null) + .innerTickSize(6) + .outerTickSize(3); - var nutexts = texts.enter().append('g').attr('class', function(d) { - return d.key + ' text'; - }); - nutexts.append('text').attr('class', 'wc-data-mark'); - // don't need to set initial location for incoming text + this.svg.select('g.x.axis').attr('class', 'x axis ' + type); + this.x = x; + this.xAxis = xAxis; + } - // attach mark info - function attachMarks(d) { - d.mark = d3.select(this.parentNode).datum(); - d3.select(this).select('text').attr(d.mark.attributes); + function yScaleAxis(max_range, domain, type) { + if (max_range === undefined) { + max_range = this.plot_height; + } + if (domain === undefined) { + domain = this.y_dom; + } + if (type === undefined) { + type = this.config.y.type; + } + var config = this.config; + var y = void 0; + if (type === 'log') { + y = d3.scale.log(); + } else if (type === 'ordinal') { + y = d3.scale.ordinal(); + } else if (type === 'time') { + y = d3.time.scale(); + } else { + y = d3.scale.linear(); } - texts.each(attachMarks); - - // parse text like tooltips - texts.select('text').text(function(d) { - var tt = d.mark.text || ''; - var xformat = config.x.summary === 'percent' - ? d3.format('0%') - : config.x.type === 'time' - ? d3.time.format(config.x.format) - : d3.format(config.x.format); - var yformat = config.y.summary === 'percent' - ? d3.format('0%') - : config.y.type === 'time' - ? d3.time.format(config.y.format) - : d3.format(config.y.format); - return tt - .replace( - /\$x/g, - config.x.type === 'time' ? xformat(new Date(d.values.x)) : xformat(d.values.x) - ) - .replace( - /\$y/g, - config.y.type === 'time' ? yformat(new Date(d.values.y)) : yformat(d.values.y) - ) - .replace(/\[(.+?)\]/g, function(str, orig) { - return d.values.raw[0][orig]; - }); - }); - // animated attributes - var textsTrans = config.transitions - ? texts.select('text').transition() - : texts.select('text'); - textsTrans - .attr('x', function(d) { - var xPos = _this.x(d.values.x) || 0; - return config.x.type === 'ordinal' ? xPos + _this.x.rangeBand() / 2 : xPos; - }) - .attr('y', function(d) { - var yPos = _this.y(d.values.y) || 0; - return config.y.type === 'ordinal' ? yPos + _this.y.rangeBand() / 2 : yPos; - }); - //add a reference to the selection from it's data - textSupergroups.each(function(d) { - d.supergroup = d3.select(this); - d.groups = d.supergroup.selectAll('g.text'); - d.texts = d.groups.select('text'); - }); - return texts; - } - function destroy() { - var destroyControls = arguments.length > 0 && arguments[0] !== undefined - ? arguments[0] - : true; + y.domain(domain); - //run onDestroy callback - this.events.onDestroy.call(this); + if (type === 'ordinal') { + y.rangeBands([+max_range, 0], config.padding, config.outer_pad); + } else { + y.range([+max_range, 0]).clamp(Boolean(config.y_clamp)); + } - //remove resize event listener - var context = this; - d3.select(window).on('resize.' + context.element + context.id, null); + var yFormat = config.y.format + ? config.y.format + : config.marks + .map(function(m) { + return m.summarizeY === 'percent'; + }) + .indexOf(true) > -1 + ? '0%' + : '.0f'; + var tick_count = Math.max(2, Math.min(max_range / 80, 8)); + var yAxis = d3.svg + .axis() + .scale(y) + .orient('left') + .ticks(tick_count) + .tickFormat( + type === 'ordinal' + ? null + : type === 'time' ? d3.time.format(yFormat) : d3.format(yFormat) + ) + .tickValues(config.y.ticks ? config.y.ticks : null) + .innerTickSize(6) + .outerTickSize(3); - //destroy controls - if (destroyControls && this.controls) { - this.controls.destroy(); - } + this.svg.select('g.y.axis').attr('class', 'y axis ' + type); - //unmount chart wrapper - this.wrap.remove(); + this.y = y; + this.yAxis = yAxis; } var chartProto = { @@ -3277,42 +3157,26 @@ : clone(this.data.raw); } - function updateDataObject() { - this.data.raw = this.data.passed; - this.data.filtered = this.data.passed; - this.config.activePage = 0; - this.config.startIndex = this.config.activePage * this.config.nRowsPerPage; // first row shown - this.config.endIndex = this.config.startIndex + this.config.nRowsPerPage; // last row shown - } - - function applySearchTerm(data) { + function applySearchTerm() { var _this = this; - if (this.searchable.searchTerm) { - //Determine which rows contain input text. - this.data.searched = this.data.filtered.filter(function(d) { - var match = false; + //Determine which rows contain input text. + this.data.searched = this.data.filtered.filter(function(d) { + var match = false; - Object.keys(d) - .filter(function(key) { - return _this.config.cols.indexOf(key) > -1; - }) - .forEach(function(var_name) { - if (match === false) { - var cellText = '' + d[var_name]; - match = - cellText.toLowerCase().indexOf(_this.searchable.searchTerm) > -1; - } - }); + Object.keys(d) + .filter(function(key) { + return _this.config.cols.indexOf(key) > -1; + }) + .forEach(function(var_name) { + if (match === false) { + var cellText = '' + d[var_name]; + match = cellText.toLowerCase().indexOf(_this.searchable.searchTerm) > -1; + } + }); - return match; - }); - this.data.processing = this.data.searched; - } else { - //Otherwise delete previously searched data and set data to filtered data. - delete this.data.searched; - this.data.processing = this.data.filtered; - } + return match; + }); } /*------------------------------------------------------------------------------------------------\ @@ -3347,7 +3211,26 @@ // Hide method from for-in loops Object.defineProperty(Array.prototype, 'equals', { enumerable: false }); - function checkFilters() { + function draw$1(passed_data) { + var _this = this; + + var context = this, + config = this.config, + table = this.table; + + //Apply filters if data is not passed to table.draw(). + if (!passed_data) { + applyFilters.call(this); + } else { + //Otherwise update data object. + this.data.raw = passed_data; + this.data.filtered = passed_data; + this.config.activePage = 0; + this.config.startIndex = this.config.activePage * this.config.nRowsPerPage; // first row shown + this.config.endIndex = this.config.startIndex + this.config.nRowsPerPage; // last row shown + } + + //Compare current filter settings to previous filter settings, if any. if (this.filters) { this.currentFilters = this.filters.map(function(filter) { return filter.val; @@ -3362,11 +3245,28 @@ this.previousFilters = this.currentFilters; } - } - function updateTableHeaders() { - var _this = this; + var data = void 0; + + //Filter data on search term if it exists and set data to searched data. + if (this.searchable.searchTerm) { + applySearchTerm.call(this); + data = this.data.searched; + } else { + //Otherwise delete previously searched data and set data to filtered data. + delete this.data.searched; + data = this.data.filtered; + } + + this.searchable.wrap + .select('.nNrecords') + .text( + data.length === this.data.raw.length + ? this.data.raw.length + ' records displayed' + : data.length + '/' + this.data.raw.length + ' records displayed' + ); + //update table header this.thead_cells = this.thead .select('tr') .selectAll('th') @@ -3375,6 +3275,7 @@ }); this.thead_cells.exit().remove(); this.thead_cells.enter().append('th'); + this.thead_cells .sort(function(a, b) { return _this.config.headers.indexOf(a) - _this.config.headers.indexOf(b); @@ -3385,44 +3286,87 @@ .text(function(d) { return d; }); - } - function drawTableBody() { - var _this = this; + //Clear table body rows. + this.tbody.selectAll('tr').remove(); - var table = this; + //Print a note that no data was selected for empty tables. + if (data.length === 0) { + this.tbody + .append('tr') + .classed('no-data', true) + .append('td') + .attr('colspan', this.config.cols.length) + .text('No data selected.'); - //Define table body rows. - var rows = this.tbody.selectAll('tr').data(this.data.processing).enter().append('tr'); + //Add export. + if (this.config.exportable) + this.config.exports.forEach(function(fmt) { + _this.exportable.exports[fmt].call(_this, data); + }); - //Define table body cells. - var cells = rows.selectAll('td').data(function(d) { - return _this.config.cols.map(function(key) { - return { col: key, text: d[key] }; - }); - }); - cells.exit().remove(); - cells.enter().append('td'); - cells - .sort(function(a, b) { - return _this.config.cols.indexOf(a.col) - _this.config.cols.indexOf(b.col); - }) - .attr('class', function(d) { - return d.col; - }) - .each(function(d) { - var cell = d3.select(this); + //Add pagination. + if (this.config.pagination) this.pagination.addPagination.call(this, data); + } else { + //Sort data. + if (this.config.sortable) { + this.thead.selectAll('th').on('click', function(header) { + context.sortable.onClick.call(context, this, header); + }); - //Apply text in data as html or as plain text. - if (table.config.as_html) { - cell.html(d.text); - } else { - cell.text(d.text); - } + if (this.sortable.order.length) this.sortable.sortData.call(this, data); + } + + //Bind table filtered/searched data to table container. + this.wrap.datum(clone(data)); + + //Add export. + if (this.config.exportable) + this.config.exports.forEach(function(fmt) { + _this.exportable.exports[fmt].call(_this, data); + }); + + //Add pagination. + if (this.config.pagination) { + this.pagination.addPagination.call(this, data); + + //Apply pagination. + data = data.filter(function(d, i) { + return _this.config.startIndex <= i && i < _this.config.endIndex; + }); + } + + //Define table body rows. + var rows = this.tbody.selectAll('tr').data(data).enter().append('tr'); + + //Define table body cells. + var cells = rows.selectAll('td').data(function(d) { + return _this.config.cols.map(function(key) { + return { col: key, text: d[key] }; + }); }); - } + cells.exit().remove(); + cells.enter().append('td'); + cells + .sort(function(a, b) { + return _this.config.cols.indexOf(a.col) - _this.config.cols.indexOf(b.col); + }) + .attr('class', function(d) { + return d.col; + }) + .each(function(d) { + var cell = d3.select(this); + + //Apply text in data as html or as plain text. + if (config.as_html) { + cell.html(d.text); + } else { + cell.text(d.text); + } + }); + } - function dynamicLayout() { + //Alter table layout if table is narrower than table top or bottom. var widths = { table: this.table.select('thead').node().offsetWidth, top: @@ -3460,114 +3404,14 @@ .style({ display: 'inline-block', float: function float() { - return select(this).classed('searchable-container') || - select(this).classed('pagination-container') + return d3.select(this).classed('searchable-container') || + d3.select(this).classed('pagination-container') ? 'right' : null; }, clear: null }); } - } - - function draw$1(passed_data) { - var _this = this; - - var table = this; - var config = this.config; - - this.data.passed = passed_data; // make passed data available on preprocess - this.events.onPreprocess.call(this); - - if (!passed_data) - //Apply filters if data is not passed to table.draw(). - applyFilters.call(this); - else - //Otherwise update data object. - updateDataObject.call(this); - - //Compare current filter settings to previous filter settings, if any. - checkFilters.call(this); - - //Filter data on search term if it exists and set data to searched data. - applySearchTerm.call(this); - - this.searchable.wrap - .select('.nNrecords') - .text( - this.data.processing.length === this.data.raw.length - ? this.data.raw.length + ' records displayed' - : this.data.processing.length + - '/' + - this.data.raw.length + - ' records displayed' - ); - - //Update table headers. - updateTableHeaders.call(this); - - //Clear table body rows. - this.tbody.selectAll('tr').remove(); - - //Print a note that no data was selected for empty tables. - if (this.data.processing.length === 0) { - this.tbody - .append('tr') - .classed('no-data', true) - .append('td') - .attr('colspan', this.config.cols.length) - .text('No data selected.'); - - //Bind table filtered/searched data to table container. - this.data.current = clone(this.data.processing); - this.table.datum(this.table.current); - - //Add export. - if (this.config.exportable) - this.config.exports.forEach(function(fmt) { - _this.exportable.exports[fmt].call(_this, _this.data.processing); - }); - - //Add pagination. - if (this.config.pagination) - this.pagination.addPagination.call(this, this.data.processing); - } else { - //Sort data. - if (this.config.sortable) { - this.thead.selectAll('th').on('click', function(header) { - table.sortable.onClick.call(table, this, header); - }); - - if (this.sortable.order.length) - this.sortable.sortData.call(this, this.data.processing); - } - - //Bind table filtered/searched data to table container. - this.data.current = clone(this.data.processing); - this.table.datum(this.data.current); - - //Add export. - if (this.config.exportable) - this.config.exports.forEach(function(fmt) { - _this.exportable.exports[fmt].call(_this, _this.data.processing); - }); - - //Add pagination. - if (this.config.pagination) { - this.pagination.addPagination.call(this, this.data.processing); - - //Apply pagination. - this.data.processing = this.data.processing.filter(function(d, i) { - return _this.config.startIndex <= i && i < _this.config.endIndex; - }); - } - - //Define table body rows. - drawTableBody.call(this); - } - - //Alter table layout if table is narrower than table top or bottom. - dynamicLayout.call(this); this.events.onDraw.call(this); } @@ -3630,14 +3474,16 @@ var CSVarray = []; - //add headers to CSV array - var headers = this.config.headers.map(function(header) { - return '"' + header.replace(/"/g, '""') + '"'; - }); - CSVarray.push(headers); - - //add rows to CSV array data.forEach(function(d, i) { + //add headers to CSV array + if (i === 0) { + var headers = _this.config.headers.map(function(header) { + return '"' + header.replace(/"/g, '""') + '"'; + }); + CSVarray.push(headers); + } + + //add rows to CSV array var row = _this.config.cols.map(function(col) { var value = d[col]; @@ -4388,18 +4234,28 @@ thisTable.required_cols = []; - thisTable.wrap = d3.select(thisTable.div).append('div').datum(thisTable); + thisTable.wrap = d3.select(thisTable.div).append('div'); thisTable.events = { onInit: function onInit() {}, onLayout: function onLayout() {}, onPreprocess: function onPreprocess() {}, + onDatatransform: function onDatatransform() {}, onDraw: function onDraw() {}, + onResize: function onResize() {}, onDestroy: function onDestroy() {} }; thisTable.on = function(event, callback) { - var possible_events = ['init', 'layout', 'preprocess', 'draw', 'destroy']; + var possible_events = [ + 'init', + 'layout', + 'preprocess', + 'datatransform', + 'draw', + 'resize', + 'destroy' + ]; if (possible_events.indexOf(event) < 0) { return; } @@ -4414,13 +4270,11 @@ function multiply(chart, data, split_by, order) { var test = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false; - chart.wrap.classed('wc-layout wc-small-multiples', true).classed('wc-chart', false); - - //Define container for legend that overrides multiples' legends. - chart.master_legend = chart.wrap.append('ul').attr('class', 'legend'); - chart.master_legend.append('span').classed('legend-title', true); - - //Instantiate multiples array. + var config = chart.config; + var wrap = chart.wrap + .classed('wc-layout wc-small-multiples', true) + .classed('wc-chart', false); + var master_legend = wrap.append('ul').attr('class', 'legend'); chart.multiples = []; function goAhead(data) { @@ -4440,17 +4294,16 @@ }); } split_vals.forEach(function(e) { - var mchart = createChart(chart.wrap.node(), chart.config, chart.controls); + var mchart = createChart(chart.wrap.node(), config, chart.controls); chart.multiples.push(mchart); mchart.parent = chart; mchart.events = chart.events; - mchart.legend = chart.master_legend; + mchart.legend = master_legend; mchart.filters.unshift({ col: split_by, val: e, choices: split_vals }); mchart.wrap.insert('span', 'svg').attr('class', 'wc-chart-title').text(e); mchart.init(data, test); }); } - goAhead(data); } diff --git a/build/webcharts.min.js b/build/webcharts.min.js index 8653464..dbeb366 100644 --- a/build/webcharts.min.js +++ b/build/webcharts.min.js @@ -1,3 +1,3 @@ -(function(global,factory){typeof exports==="object"&&typeof module!=="undefined"?module.exports=factory(require("d3")):typeof define==="function"&&define.amd?define(["d3"],factory):global.webCharts=factory(global.d3)})(this,function(d3){"use strict";var version="1.11.0";function init(data){var _this=this;var test=arguments.length>1&&arguments[1]!==undefined?arguments[1]:false;if(d3.select(this.div).select(".loader").empty()){d3.select(this.div).insert("div",":first-child").attr("class","loader").selectAll(".blockG").data(d3.range(8)).enter().append("div").attr("class",function(d){return"blockG rotate"+(d+1)})}this.wrap.attr("class","wc-chart");this.setDefaults();this.raw_data=data;this.initial_data=data;var startup=function startup(data){if(_this.controls){_this.controls.targets.push(_this);if(!_this.controls.ready){_this.controls.init(_this.raw_data)}else{_this.controls.layout()}}var visible=d3.select(_this.div).property("offsetWidth")>0||test;if(!visible){console.warn("The chart cannot be initialized inside an element with 0 width. The chart will be initialized as soon as the container element is given a width > 0.");var onVisible=setInterval(function(i){var visible_now=d3.select(_this.div).property("offsetWidth")>0;if(visible_now){_this.layout();_this.draw();clearInterval(onVisible)}},500)}else{_this.layout();_this.draw()}};this.events.onInit.call(this);if(this.raw_data.length){this.checkRequired(this.raw_data)}startup(data);return this}function checkRequired(data){var _this=this;var colnames=Object.keys(data[0]);var requiredVars=[];var requiredCols=[];if(this.config.x&&this.config.x.column){requiredVars.push("this.config.x.column");requiredCols.push(this.config.x.column)}if(this.config.y&&this.config.y.column){requiredVars.push("this.config.y.column");requiredCols.push(this.config.y.column)}if(this.config.color_by){requiredVars.push("this.config.color_by");requiredCols.push(this.config.color_by)}if(this.config.marks)this.config.marks.forEach(function(e,i){if(e.per&&e.per.length){e.per.forEach(function(p,j){requiredVars.push("this.config.marks["+i+"].per["+j+"]");requiredCols.push(p)})}if(e.split){requiredVars.push("this.config.marks["+i+"].split");requiredCols.push(e.split)}if(e.values){for(var value in e.values){requiredVars.push("this.config.marks["+i+"].values['"+value+"']");requiredCols.push(value)}}});var missingDataField=false;requiredCols.forEach(function(e,i){if(colnames.indexOf(e)<0){missingDataField=true;d3.select(_this.div).select(".loader").remove();_this.wrap.append("div").style("color","red").html('The value "'+e+'" for the '+requiredVars[i]+" setting does not match any column in the provided dataset.");throw new Error('Error in settings object: The value "'+e+'" for the '+requiredVars[i]+" setting does not match any column in the provided dataset.")}});return{missingDataField:missingDataField,dataFieldArguments:requiredVars,requiredDataFields:requiredCols}}function layout(){this.svg=this.wrap.append("svg").datum(function(){return null}).attr({class:"wc-svg",xmlns:"http://www.w3.org/2000/svg",version:"1.1",xlink:"http://www.w3.org/1999/xlink"}).append("g").style("display","inline-block");var defs=this.svg.append("defs");defs.append("pattern").attr({id:"diagonal-stripes",x:0,y:0,width:3,height:8,patternUnits:"userSpaceOnUse",patternTransform:"rotate(30)"}).append("rect").attr({x:"0",y:"0",width:"2",height:"8",style:"stroke:none; fill:black"});defs.append("clipPath").attr("id",this.id).append("rect").attr("class","plotting-area");this.svg.append("g").attr("class","y axis").append("text").attr("class","axis-title").attr("transform","rotate(-90)").attr("dy",".75em").attr("text-anchor","middle");this.svg.append("g").attr("class","x axis").append("text").attr("class","axis-title").attr("dy","-.35em").attr("text-anchor","middle");this.svg.append("rect").attr("class","overlay").attr("opacity",0).attr("fill","none").style("pointer-events","all");if(!this.parent)this.wrap.append("ul").datum(function(){return null}).attr("class","legend").style("vertical-align","top").append("span").attr("class","legend-title");d3.select(this.div).select(".loader").remove();this.events.onLayout.call(this)}function draw(raw_data,processed_data){var _this=this;var chart=this;var config=this.config;this.events.onPreprocess.call(this);var raw=raw_data?raw_data:this.raw_data?this.raw_data:[];if(processed_data){console.warn("Drawing the chart using user-defined 'processed_data', this is an experimental, untested feature.")}this.consolidateData(raw);var div_width=parseInt(this.wrap.style("width"));this.setColorScale();var max_width=config.max_width?config.max_width:div_width;this.raw_width=config.x.type==="ordinal"&&+config.x.range_band?(+config.x.range_band+config.x.range_band*config.padding)*this.x_dom.length:config.resizable?max_width:config.width?config.width:div_width;this.raw_height=config.y.type==="ordinal"&&+config.y.range_band?(+config.y.range_band+config.y.range_band*config.padding)*this.y_dom.length:config.resizable?max_width*(1/config.aspect):config.height?config.height:div_width*(1/config.aspect);var pseudo_width=this.svg.select(".overlay").attr("width")?this.svg.select(".overlay").attr("width"):this.raw_width;var pseudo_height=this.svg.select(".overlay").attr("height")?this.svg.select(".overlay").attr("height"):this.raw_height;this.svg.select(".x.axis").select(".axis-title").text(function(d){return typeof config.x.label==="string"?config.x.label:typeof config.x.label==="function"?config.x.label.call(_this):null});this.svg.select(".y.axis").select(".axis-title").text(function(d){return typeof config.y.label==="string"?config.y.label:typeof config.y.label==="function"?config.y.label.call(_this):null});this.xScaleAxis(pseudo_width);this.yScaleAxis(pseudo_height);if(config.resizable&&typeof window!=="undefined"){d3.select(window).on("resize."+this.element+this.id,function(){chart.resize()})}else if(typeof window!=="undefined"){d3.select(window).on("resize."+this.element+this.id,null)}this.events.onDraw.call(this);this.resize()}function naturalSorter(a,b){function chunkify(t){var tz=[];var x=0,y=-1,n=0,i=void 0,j=void 0;while(i=(j=t.charAt(x++)).charCodeAt(0)){var m=i==46||i>=48&&i<=57;if(m!==n){tz[++y]="";n=m}tz[y]+=j}return tz}var aa=chunkify(a.toLowerCase());var bb=chunkify(b.toLowerCase());for(var x=0;aa[x]&&bb[x];x++){if(aa[x]!==bb[x]){var c=Number(aa[x]),d=Number(bb[x]);if(c==aa[x]&&d==bb[x]){return c-d}else{return aa[x]>bb[x]?1:-1}}}return aa.length-bb.length}function setDomain(axis){var _this=this;var otherAxis=axis==="x"?"y":"x";if(this.config[axis].type==="ordinal"){if(this.config[axis].domain){this[axis+"_dom"]=this.config[axis].domain}else if(this.config[axis].order){this[axis+"_dom"]=d3.set(d3.merge(this.marks.map(function(mark){return mark[axis+"_dom"]}))).values().sort(function(a,b){return d3.ascending(_this.config[axis].order.indexOf(a),_this.config[axis].order.indexOf(b))})}else if(this.config[axis].sort&&this.config[axis].sort==="alphabetical-ascending"){this[axis+"_dom"]=d3.set(d3.merge(this.marks.map(function(mark){return mark[axis+"_dom"]}))).values().sort(naturalSorter)}else if(["time","linear"].indexOf(this.config[otherAxis].type)>-1&&this.config[axis].sort==="earliest"){this[axis+"_dom"]=d3.nest().key(function(d){return d[_this.config[axis].column]}).rollup(function(d){return d.map(function(m){return m[_this.config[otherAxis].column]}).filter(function(f){return f instanceof Date})}).entries(this.raw_data).sort(function(a,b){return min(b.values)-min(a.values)}).map(function(m){return m.key})}else if(!this.config[axis].sort||this.config[axis].sort==="alphabetical-descending"){this[axis+"_dom"]=d3.set(d3.merge(this.marks.map(function(mark){return mark[axis+"_dom"]}))).values().sort(naturalSorter).reverse()}else{this[axis+"_dom"]=d3.set(d3.merge(this.marks.map(function(mark){return mark[axis+"_dom"]}))).values()}}else if(this.config.marks.map(function(m){return m["summarize"+otherAxis.toUpperCase()]==="percent"}).indexOf(true)>-1){this[axis+"_dom"]=[0,1]}else{this[axis+"_dom"]=d3.extent(d3.merge(this.marks.map(function(mark){return mark[axis+"_dom"]})))}if(this.config[axis].type==="linear"&&this[axis+"_dom"][0]===this[axis+"_dom"][1])this[axis+"_dom"]=this[axis+"_dom"][0]!==0?[this[axis+"_dom"][0]-this[axis+"_dom"][0]*.01,this[axis+"_dom"][1]+this[axis+"_dom"][1]*.01]:[-1,1];return this[axis+"_dom"]}function consolidateData(raw){var _this=this;this.setDefaults();this.filtered_data=raw;if(this.filters.length){this.filters.forEach(function(filter){_this.filtered_data=_this.filtered_data.filter(function(d){return filter.val==="All"?d:filter.val instanceof Array?filter.val.indexOf(d[filter.col])>-1:d[filter.col]===filter.val})})}this.config.marks.forEach(function(mark,i){if(mark.type!=="bar"){mark.arrange=null;mark.split=null}var mark_info=mark.per?_this.transformData(raw,mark):{data:[],x_dom:[],y_dom:[]};_this.marks[i]={id:mark.id,type:mark.type,per:mark.per,data:mark_info.data,x_dom:mark_info.x_dom,y_dom:mark_info.y_dom,split:mark.split,text:mark.text,arrange:mark.arrange,order:mark.order,summarizeX:mark.summarizeX,summarizeY:mark.summarizeY,tooltip:mark.tooltip,radius:mark.radius,attributes:mark.attributes,values:mark.values}});setDomain.call(this,"x");setDomain.call(this,"y")}function setDefaults(){this.config.x=this.config.x||{};this.config.y=this.config.y||{};this.config.x.label=this.config.x.label!==undefined?this.config.x.label:this.config.x.column;this.config.y.label=this.config.y.label!==undefined?this.config.y.label:this.config.y.column;this.config.x.sort=this.config.x.sort||"alphabetical-ascending";this.config.y.sort=this.config.y.sort||"alphabetical-descending";this.config.x.type=this.config.x.type||"linear";this.config.y.type=this.config.y.type||"linear";this.config.x.range_band=this.config.x.range_band||this.config.range_band;this.config.y.range_band=this.config.y.range_band||this.config.range_band;this.config.margin=this.config.margin||{};this.config.legend=this.config.legend||{};this.config.legend.label=this.config.legend.label!==undefined?this.config.legend.label:this.config.color_by;this.config.legend.location=this.config.legend.location!==undefined?this.config.legend.location:"bottom";this.config.marks=this.config.marks&&this.config.marks.length?this.config.marks:[{}];this.config.marks.forEach(function(m,i){m.id=m.id?m.id:"mark"+(i+1)});this.config.date_format=this.config.date_format||"%x";this.config.padding=this.config.padding!==undefined?this.config.padding:.3;this.config.outer_pad=this.config.outer_pad!==undefined?this.config.outer_pad:.1;this.config.resizable=this.config.resizable!==undefined?this.config.resizable:true;this.config.aspect=this.config.aspect||1.33;this.config.colors=this.config.colors||["rgb(102,194,165)","rgb(252,141,98)","rgb(141,160,203)","rgb(231,138,195)","rgb(166,216,84)","rgb(255,217,47)","rgb(229,196,148)","rgb(179,179,179)"];this.config.scale_text=this.config.scale_text===undefined?true:this.config.scale_text;this.config.transitions=this.config.transitions===undefined?true:this.config.transitions}function cleanData(mark,raw){var _this=this;var dateConvert=d3.time.format(this.config.date_format);var clean=raw;clean=mark.per&&mark.per.length?clean.filter(function(f){return f[mark.per[0]]!==undefined}):clean;if(this.config.x.column){clean=clean.filter(function(f){return[undefined,null].indexOf(f[_this.config.x.column])<0})}if(this.config.y.column){clean=clean.filter(function(f){return[undefined,null].indexOf(f[_this.config.y.column])<0})}if(this.config.x.type==="time"){clean=clean.filter(function(f){return f[_this.config.x.column]instanceof Date?f[_this.config.x.column]:dateConvert.parse(f[_this.config.x.column])});clean.forEach(function(e){return e[_this.config.x.column]=e[_this.config.x.column]instanceof Date?e[_this.config.x.column]:dateConvert.parse(e[_this.config.x.column])})}if(this.config.y.type==="time"){clean=clean.filter(function(f){return f[_this.config.y.column]instanceof Date?f[_this.config.y.column]:dateConvert.parse(f[_this.config.y.column])});clean.forEach(function(e){return e[_this.config.y.column]=e[_this.config.y.column]instanceof Date?e[_this.config.y.column]:dateConvert.parse(e[_this.config.y.column])})}if((this.config.x.type==="linear"||this.config.x.type==="log")&&this.config.x.column){clean=clean.filter(function(f){return mark.summarizeX!=="count"&&mark.summarizeX!=="percent"?!(isNaN(f[_this.config.x.column])||/^\s*$/.test(f[_this.config.x.column])):f})}if((this.config.y.type==="linear"||this.config.y.type==="log")&&this.config.y.column){clean=clean.filter(function(f){return mark.summarizeY!=="count"&&mark.summarizeY!=="percent"?!(isNaN(f[_this.config.y.column])||/^\s*$/.test(f[_this.config.y.column])):f})}return clean}var stats={mean:d3.mean,min:d3.min,max:d3.max,median:d3.median,sum:d3.sum};function summarize(vals){var operation=arguments.length>1&&arguments[1]!==undefined?arguments[1]:"mean";var nvals=vals.filter(function(f){return+f||+f===0}).map(function(m){return+m});if(operation==="cumulative"){return null}var mathed=operation==="count"?vals.length:operation==="percent"?vals.length:stats[operation](nvals);return mathed}function makeNest(mark,entries,sublevel){var _this=this;var dom_xs=[];var dom_ys=[];var this_nest=d3.nest();var totalOrder=void 0;if(this.config.x.type==="linear"&&this.config.x.bin||this.config.y.type==="linear"&&this.config.y.bin){var xy=this.config.x.type==="linear"&&this.config.x.bin?"x":"y";var quant=d3.scale.quantile().domain(d3.extent(entries.map(function(m){return+m[_this.config[xy].column]}))).range(d3.range(+this.config[xy].bin));entries.forEach(function(e){return e.wc_bin=quant(e[_this.config[xy].column])});this_nest.key(function(d){return quant.invertExtent(d.wc_bin)})}else{this_nest.key(function(d){return mark.per.map(function(m){return d[m]}).join(" ")})}if(sublevel){this_nest.key(function(d){return d[sublevel]});this_nest.sortKeys(function(a,b){return _this.config.x.type==="time"?d3.ascending(new Date(a),new Date(b)):_this.config.x.order?d3.ascending(_this.config.x.order.indexOf(a),_this.config.x.order.indexOf(b)):sublevel===_this.config.color_by&&_this.config.legend.order?d3.ascending(_this.config.legend.order.indexOf(a),_this.config.legend.order.indexOf(b)):_this.config.x.type==="ordinal"||_this.config.y.type==="ordinal"?naturalSorter(a,b):d3.ascending(+a,+b)})}this_nest.rollup(function(r){var obj={raw:r};var y_vals=r.map(function(m){return m[_this.config.y.column]}).sort(d3.ascending);var x_vals=r.map(function(m){return m[_this.config.x.column]}).sort(d3.ascending);obj.x=_this.config.x.type==="ordinal"?r[0][_this.config.x.column]:summarize(x_vals,mark.summarizeX);obj.y=_this.config.y.type==="ordinal"?r[0][_this.config.y.column]:summarize(y_vals,mark.summarizeY);obj.x_q25=_this.config.error_bars&&_this.config.y.type==="ordinal"?d3.quantile(x_vals,.25):obj.x;obj.x_q75=_this.config.error_bars&&_this.config.y.type==="ordinal"?d3.quantile(x_vals,.75):obj.x;obj.y_q25=_this.config.error_bars?d3.quantile(y_vals,.25):obj.y;obj.y_q75=_this.config.error_bars?d3.quantile(y_vals,.75):obj.y;dom_xs.push([obj.x_q25,obj.x_q75,obj.x]);dom_ys.push([obj.y_q25,obj.y_q75,obj.y]);if(mark.summarizeY==="cumulative"){var interm=entries.filter(function(f){return _this.config.x.type==="time"?new Date(f[_this.config.x.column])<=new Date(r[0][_this.config.x.column]):+f[_this.config.x.column]<=+r[0][_this.config.x.column]});if(mark.per.length){interm=interm.filter(function(f){return f[mark.per[0]]===r[0][mark.per[0]]})}var cumul=_this.config.x.type==="time"?interm.length:d3.sum(interm.map(function(m){return+m[_this.config.y.column]||+m[_this.config.y.column]===0?+m[_this.config.y.column]:1}));dom_ys.push([cumul]);obj.y=cumul}if(mark.summarizeX==="cumulative"){var _interm=entries.filter(function(f){return _this.config.y.type==="time"?new Date(f[_this.config.y.column])<=new Date(r[0][_this.config.y.column]):+f[_this.config.y.column]<=+r[0][_this.config.y.column]});if(mark.per.length){_interm=_interm.filter(function(f){return f[mark.per[0]]===r[0][mark.per[0]]})}dom_xs.push([_interm.length]);obj.x=_interm.length}return obj});var test=this_nest.entries(entries);var dom_x=d3.extent(d3.merge(dom_xs));var dom_y=d3.extent(d3.merge(dom_ys));if(sublevel&&mark.type==="bar"&&mark.split){test.forEach(function(e){var axis=_this.config.x.type==="ordinal"||_this.config.x.type==="linear"&&_this.config.x.bin?"y":"x";e.total=d3.sum(e.values.map(function(m){return+m.values[axis]}));var counter=0;e.values.forEach(function(v,i){if(_this.config.x.type==="ordinal"||_this.config.x.type==="linear"&&_this.config.x.bin){v.values.y=mark.summarizeY==="percent"?v.values.y/e.total:v.values.y||0;counter+=+v.values.y;v.values.start=e.values[i-1]?counter:v.values.y}else{v.values.x=mark.summarizeX==="percent"?v.values.x/e.total:v.values.x||0;v.values.start=counter;counter+=+v.values.x}})});if(mark.arrange==="stacked"){if(this.config.x.type==="ordinal"||this.config.x.type==="linear"&&this.config.x.bin){dom_y=d3.extent(test.map(function(m){return m.total}))}if(this.config.y.type==="ordinal"||this.config.y.type==="linear"&&this.config.y.bin){dom_x=d3.extent(test.map(function(m){return m.total}))}}}else{var axis=this.config.x.type==="ordinal"||this.config.x.type==="linear"&&this.config.x.bin?"y":"x";test.forEach(function(e){return e.total=e.values[axis]})}if(this.config.x.sort==="total-ascending"&&this.config.x.type=="ordinal"||this.config.y.sort==="total-descending"&&this.config.y.type=="ordinal"){totalOrder=test.sort(function(a,b){return d3.ascending(a.total,b.total)}).map(function(m){return m.key})}else if(this.config.x.sort==="total-descending"&&this.config.x.type=="ordinal"||this.config.y.sort==="total-ascending"&&this.config.y.type=="ordinal"){totalOrder=test.sort(function(a,b){return d3.descending(+a.total,+b.total)}).map(function(m){return m.key})}return{nested:test,dom_x:dom_x,dom_y:dom_y,totalOrder:totalOrder}}function transformData(raw,mark){var _this=this;var config=this.config;var x_behavior=config.x.behavior||"raw";var y_behavior=config.y.behavior||"raw";var sublevel=mark.type==="line"?config.x.column:mark.type==="bar"&&mark.split?mark.split:null;var cleaned=cleanData.call(this,mark,raw);var raw_nest=void 0;if(mark.type==="bar"){raw_nest=mark.arrange!=="stacked"?makeNest.call(this,mark,cleaned,sublevel):makeNest.call(this,mark,cleaned)}else if(mark.summarizeX==="count"||mark.summarizeY==="count"){raw_nest=makeNest.call(this,mark,cleaned)}var raw_dom_x=mark.summarizeX==="cumulative"?[0,cleaned.length]:config.x.type==="ordinal"?d3.set(cleaned.map(function(m){return m[config.x.column]})).values().filter(function(f){return f}):mark.split&&mark.arrange!=="stacked"?d3.extent(d3.merge(raw_nest.nested.map(function(m){return m.values.map(function(p){return p.values.raw.length})}))):mark.summarizeX==="count"?d3.extent(raw_nest.nested.map(function(m){return m.values.raw.length})):d3.extent(cleaned.map(function(m){return+m[config.x.column]}).filter(function(f){return+f||+f===0}));var raw_dom_y=mark.summarizeY==="cumulative"?[0,cleaned.length]:config.y.type==="ordinal"?d3.set(cleaned.map(function(m){return m[config.y.column]})).values().filter(function(f){return f}):mark.split&&mark.arrange!=="stacked"?d3.extent(d3.merge(raw_nest.nested.map(function(m){return m.values.map(function(p){return p.values.raw.length})}))):mark.summarizeY==="count"?d3.extent(raw_nest.nested.map(function(m){return m.values.raw.length})):d3.extent(cleaned.map(function(m){return+m[config.y.column]}).filter(function(f){return+f||+f===0}));var filtered=cleaned;var filt1_xs=[];var filt1_ys=[];if(this.filters.length){this.filters.forEach(function(e){filtered=filtered.filter(function(d){return e.val==="All"?d:e.val instanceof Array?e.val.indexOf(d[e.col])>-1:d[e.col]===e.val})});if(config.x.behavior==="firstfilter"||config.y.behavior==="firstfilter"){this.filters[0].choices.filter(function(f){return f!=="All"}).forEach(function(e){var perfilter=cleaned.filter(function(f){return f[_this.filters[0].col]===e});var filt_nested=makeNest.call(_this,mark,perfilter,sublevel);filt1_xs.push(filt_nested.dom_x);filt1_ys.push(filt_nested.dom_y)})}}if(mark.values){var _loop=function _loop(a){filtered=filtered.filter(function(f){return mark.values[a].indexOf(f[a])>-1})};for(var a in mark.values){_loop(a)}}var filt1_dom_x=d3.extent(d3.merge(filt1_xs));var filt1_dom_y=d3.extent(d3.merge(filt1_ys));var current_nested=makeNest.call(this,mark,filtered,sublevel);var flex_dom_x=current_nested.dom_x;var flex_dom_y=current_nested.dom_y;if(mark.type==="bar"){if(config.y.type==="ordinal"&&mark.summarizeX==="count"){config.x.domain=config.x.domain?[0,config.x.domain[1]]:[0,null]}else if(config.x.type==="ordinal"&&mark.summarizeY==="count"){config.y.domain=config.y.domain?[0,config.y.domain[1]]:[0,null]}}var nonall=Boolean(this.filters.length&&this.filters[0].val!=="All"&&this.filters.slice(1).filter(function(f){return f.val==="All"}).length===this.filters.length-1);var pre_x_dom=!this.filters.length?flex_dom_x:x_behavior==="raw"?raw_dom_x:nonall&&x_behavior==="firstfilter"?filt1_dom_x:flex_dom_x;var pre_y_dom=!this.filters.length?flex_dom_y:y_behavior==="raw"?raw_dom_y:nonall&&y_behavior==="firstfilter"?filt1_dom_y:flex_dom_y;var x_dom=config.x_dom?config.x_dom:config.x.type==="ordinal"&&config.x.behavior==="flex"?d3.set(filtered.map(function(m){return m[config.x.column]})).values():config.x.type==="ordinal"?d3.set(cleaned.map(function(m){return m[config.x.column]})).values():pre_x_dom;var y_dom=config.y_dom?config.y_dom:config.y.type==="ordinal"&&config.y.behavior==="flex"?d3.set(filtered.map(function(m){return m[config.y.column]})).values():config.y.type==="ordinal"?d3.set(cleaned.map(function(m){return m[config.y.column]})).values():pre_y_dom;if(mark.type==="bar"){if(config.x.behavior!=="flex"&&config.x.type==="linear"&&config.y.type==="ordinal"&&raw_dom_x[0]>=0)x_dom[0]=0;if(config.y.behavior!=="flex"&&config.x.type==="ordinal"&&config.y.type==="linear"&&raw_dom_y[0]>=0)y_dom[0]=0}if(config.x.domain&&(config.x.domain[0]||config.x.domain[0]===0)){x_dom[0]=config.x.domain[0]}if(config.x.domain&&(config.x.domain[1]||config.x.domain[1]===0)){x_dom[1]=config.x.domain[1]}if(config.y.domain&&(config.y.domain[0]||config.y.domain[0]===0)){y_dom[0]=config.y.domain[0]}if(config.y.domain&&(config.y.domain[1]||config.y.domain[1]===0)){y_dom[1]=config.y.domain[1]}if(config.x.type==="ordinal"&&!config.x.order){config.x.order=current_nested.totalOrder}if(config.y.type==="ordinal"&&!config.y.order){config.y.order=current_nested.totalOrder}this.current_data=current_nested.nested;this.events.onDatatransform.call(this);return{config:mark,data:current_nested.nested,x_dom:x_dom,y_dom:y_dom}}function setColorScale(){var config=this.config;var data=config.legend.behavior==="flex"?this.filtered_data:this.raw_data;var colordom=Array.isArray(config.color_dom)&&config.color_dom.length?config.color_dom.slice():d3.set(data.map(function(m){return m[config.color_by]})).values().filter(function(f){return f&&f!=="undefined"});if(config.legend.order)colordom.sort(function(a,b){return d3.ascending(config.legend.order.indexOf(a),config.legend.order.indexOf(b))});else colordom.sort(naturalSorter);this.colorScale=d3.scale.ordinal().domain(colordom).range(config.colors)}function xScaleAxis(max_range,domain,type){if(max_range===undefined){max_range=this.plot_width}if(domain===undefined){domain=this.x_dom}if(type===undefined){type=this.config.x.type}var config=this.config;var x=void 0;if(type==="log"){x=d3.scale.log()}else if(type==="ordinal"){x=d3.scale.ordinal()}else if(type==="time"){x=d3.time.scale()}else{x=d3.scale.linear()}x.domain(domain);if(type==="ordinal"){x.rangeBands([0,+max_range],config.padding,config.outer_pad)}else{x.range([0,+max_range]).clamp(Boolean(config.x.clamp))}var xFormat=config.x.format?config.x.format:config.marks.map(function(m){return m.summarizeX==="percent"}).indexOf(true)>-1?"0%":type==="time"?"%x":".0f";var tick_count=Math.max(2,Math.min(max_range/80,8));var xAxis=d3.svg.axis().scale(x).orient(config.x.location).ticks(tick_count).tickFormat(type==="ordinal"?null:type==="time"?d3.time.format(xFormat):d3.format(xFormat)).tickValues(config.x.ticks?config.x.ticks:null).innerTickSize(6).outerTickSize(3);this.svg.select("g.x.axis").attr("class","x axis "+type);this.x=x;this.xAxis=xAxis}function yScaleAxis(max_range,domain,type){if(max_range===undefined){max_range=this.plot_height}if(domain===undefined){domain=this.y_dom}if(type===undefined){type=this.config.y.type}var config=this.config;var y=void 0;if(type==="log"){y=d3.scale.log()}else if(type==="ordinal"){y=d3.scale.ordinal()}else if(type==="time"){y=d3.time.scale()}else{y=d3.scale.linear()}y.domain(domain);if(type==="ordinal"){y.rangeBands([+max_range,0],config.padding,config.outer_pad)}else{y.range([+max_range,0]).clamp(Boolean(config.y_clamp))}var yFormat=config.y.format?config.y.format:config.marks.map(function(m){return m.summarizeY==="percent"}).indexOf(true)>-1?"0%":".0f";var tick_count=Math.max(2,Math.min(max_range/80,8));var yAxis=d3.svg.axis().scale(y).orient("left").ticks(tick_count).tickFormat(type==="ordinal"?null:type==="time"?d3.time.format(yFormat):d3.format(yFormat)).tickValues(config.y.ticks?config.y.ticks:null).innerTickSize(6).outerTickSize(3);this.svg.select("g.y.axis").attr("class","y axis "+type);this.y=y;this.yAxis=yAxis}function resize(){var config=this.config;var aspect2=1/config.aspect;var div_width=parseInt(this.wrap.style("width"));var max_width=config.max_width?config.max_width:div_width;var preWidth=!config.resizable?config.width:!max_width||div_width=600){font_size="14px";point_size=4;stroke_width=2}else if(width>450&&width<600){font_size="12px";point_size=3;stroke_width=2}else if(width>300&&width<450){font_size="10px";point_size=2;stroke_width=2}else if(width<=300){font_size="10px";point_size=2;stroke_width=1}this.wrap.style("font-size",font_size);this.config.flex_point_size=point_size;this.config.flex_stroke_width=stroke_width}function setMargins(){var _this=this;var y_ticks=this.yAxis.tickFormat()?this.y.domain().map(function(m){return _this.yAxis.tickFormat()(m)}):this.y.domain();var max_y_text_length=d3.max(y_ticks.map(function(m){return String(m).length}));if(this.config.y_format&&this.config.y_format.indexOf("%")>-1){max_y_text_length+=1}max_y_text_length=Math.max(2,max_y_text_length);var x_label_on=this.config.x.label?1.5:0;var y_label_on=this.config.y.label?1.5:.25;var font_size=parseInt(this.wrap.style("font-size"));var x_second=this.config.x2_interval?1:0;var y_margin=max_y_text_length*font_size*.5+font_size*y_label_on*1.5||8;var x_margin=font_size+font_size/1.5+font_size*x_label_on+font_size*x_second||8;y_margin+=6;x_margin+=3;return{top:this.config.margin&&this.config.margin.top?this.config.margin.top:8,right:this.config.margin&&this.config.margin.right?this.config.margin.right:16,bottom:this.config.margin&&this.config.margin.bottom?this.config.margin.bottom:x_margin,left:this.config.margin&&this.config.margin.left?this.config.margin.left:y_margin}}function drawGridLines(){this.wrap.classed("gridlines",this.config.gridlines);if(this.config.gridlines){this.svg.select(".y.axis").selectAll(".tick line").attr("x1",0);this.svg.select(".x.axis").selectAll(".tick line").attr("y1",0);if(this.config.gridlines==="y"||this.config.gridlines==="xy")this.svg.select(".y.axis").selectAll(".tick line").attr("x1",this.plot_width);if(this.config.gridlines==="x"||this.config.gridlines==="xy")this.svg.select(".x.axis").selectAll(".tick line").attr("y1",-this.plot_height)}else{this.svg.select(".y.axis").selectAll(".tick line").attr("x1",0);this.svg.select(".x.axis").selectAll(".tick line").attr("y1",0)}}function makeLegend(){var scale$$1=arguments.length>0&&arguments[0]!==undefined?arguments[0]:this.colorScale;var label=arguments.length>1&&arguments[1]!==undefined?arguments[1]:"";var custom_data=arguments.length>2&&arguments[2]!==undefined?arguments[2]:null;var config=this.config;config.legend.mark=config.legend.mark?config.legend.mark:config.marks.length&&config.marks[0].type==="bar"?"square":config.marks.length?config.marks[0].type:"square";var legend_label=label?label:typeof config.legend.label==="string"?config.legend.label:"";var legendOriginal=this.legend||this.wrap.select(".legend");var legend=legendOriginal;if(!this.parent){if(this.config.legend.location==="top"||this.config.legend.location==="left"){this.wrap.node().insertBefore(legendOriginal.node(),this.svg.node().parentNode)}else{this.wrap.node().appendChild(legendOriginal.node())}}else{if(this.config.legend.location==="top"||this.config.legend.location==="left"){this.parent.wrap.node().insertBefore(legendOriginal.node(),this.parent.wrap.select(".wc-chart").node())}else{this.parent.wrap.node().appendChild(legendOriginal.node())}}legend.style("padding",0);var legend_data=custom_data||scale$$1.domain().slice(0).filter(function(f){return f!==undefined&&f!==null}).map(function(m){return{label:m,mark:config.legend.mark}});legend.select(".legend-title").text(legend_label).style("display",legend_label?"inline":"none").style("margin-right","1em");var leg_parts=legend.selectAll(".legend-item").data(legend_data,function(d){return d.label+d.mark});leg_parts.exit().remove();var legendPartDisplay=this.config.legend.location==="bottom"||this.config.legend.location==="top"?"inline-block":"block";var new_parts=leg_parts.enter().append("li").attr("class","legend-item").style({"list-style-type":"none","margin-right":"1em"});new_parts.append("span").attr("class","legend-mark-text").style("color",function(d){return scale$$1(d.label)}) -;new_parts.append("svg").attr("class","legend-color-block").attr("width","1.1em").attr("height","1.1em").style({position:"relative",top:"0.2em"});leg_parts.style("display",legendPartDisplay);if(config.legend.order){leg_parts.sort(function(a,b){return d3.ascending(config.legend.order.indexOf(a.label),config.legend.order.indexOf(b.label))})}leg_parts.selectAll(".legend-color-block").select(".legend-mark").remove();leg_parts.selectAll(".legend-color-block").each(function(e){var svg$$1=d3.select(this);if(e.mark==="circle"){svg$$1.append("circle").attr({cx:".5em",cy:".5em",r:".45em",class:"legend-mark"})}else if(e.mark==="line"){svg$$1.append("line").attr({x1:0,y1:".5em",x2:"1em",y2:".5em","stroke-width":2,"shape-rendering":"crispEdges",class:"legend-mark"})}else if(e.mark==="square"){svg$$1.append("rect").attr({height:"1em",width:"1em",class:"legend-mark","shape-rendering":"crispEdges"})}});leg_parts.selectAll(".legend-color-block").select(".legend-mark").attr("fill",function(d){return d.color||scale$$1(d.label)}).attr("stroke",function(d){return d.color||scale$$1(d.label)}).each(function(e){d3.select(this).attr(e.attributes)});new_parts.append("span").attr("class","legend-label").style("margin-left","0.25em").text(function(d){return d.label});if(scale$$1.domain().length>0){var legendDisplay=this.config.legend.location==="bottom"||this.config.legend.location==="top"?"block":"inline-block";legend.style("display",legendDisplay)}else{legend.style("display","none")}this.legend=legend}function updateDataMarks(){this.drawBars(this.marks.filter(function(f){return f.type==="bar"}));this.drawLines(this.marks.filter(function(f){return f.type==="line"}));this.drawPoints(this.marks.filter(function(f){return f.type==="circle"}));this.drawText(this.marks.filter(function(f){return f.type==="text"}));this.marks.supergroups=this.svg.selectAll("g.supergroup")}function drawArea(area_drawer,area_data,datum_accessor){var class_match=arguments.length>3&&arguments[3]!==undefined?arguments[3]:"chart-area";var _this=this;var bind_accessor=arguments[4];var attr_accessor=arguments.length>5&&arguments[5]!==undefined?arguments[5]:function(d){return d};var area_grps=this.svg.selectAll("."+class_match).data(area_data,bind_accessor);area_grps.exit().remove();area_grps.enter().append("g").attr("class",function(d){return class_match+" "+d.key}).append("path");var areaPaths=area_grps.select("path").datum(datum_accessor).attr("fill",function(d){var d_attr=attr_accessor(d);return d_attr?_this.colorScale(d_attr[_this.config.color_by]):null}).attr("fill-opacity",this.config.fill_opacity||this.config.fill_opacity===0?this.config.fill_opacity:.3);var areaPathTransitions=this.config.transitions?areaPaths.transition():areaPaths;areaPathTransitions.attr("d",area_drawer);return area_grps}function drawBars(marks){var _this=this;var rawData=this.raw_data;var config=this.config;var bar_supergroups=this.svg.selectAll(".bar-supergroup").data(marks,function(d,i){return i+"-"+d.per.join("-")});bar_supergroups.enter().append("g").attr("class",function(d){return"supergroup bar-supergroup "+d.id});bar_supergroups.exit().remove();var bar_groups=bar_supergroups.selectAll(".bar-group").data(function(d){return d.data},function(d){return d.key});var old_bar_groups=bar_groups.exit();var nu_bar_groups=void 0;var bars=void 0;var oldBarsTrans=config.transitions?old_bar_groups.selectAll(".bar").transition():old_bar_groups.selectAll(".bar");var oldBarGroupsTrans=config.transitions?old_bar_groups.transition():old_bar_groups;if(config.x.type==="ordinal"){oldBarsTrans.attr("y",this.y(0)).attr("height",0);oldBarGroupsTrans.remove();nu_bar_groups=bar_groups.enter().append("g").attr("class",function(d){return"bar-group "+d.key});nu_bar_groups.append("title");bars=bar_groups.selectAll("rect").data(function(d){return d.values instanceof Array?d.values.sort(function(a,b){return _this.colorScale.domain().indexOf(b.key)-_this.colorScale.domain().indexOf(a.key)}):[d]},function(d){return d.key});var exitBars=config.transitions?bars.exit().transition():bars.exit();exitBars.attr("y",this.y(0)).attr("height",0).remove();bars.enter().append("rect").attr("class",function(d){return"wc-data-mark bar "+d.key}).style("clip-path","url(#"+this.id+")").attr("y",this.y(0)).attr("height",0).append("title");bars.attr("shape-rendering","crispEdges").attr("stroke",function(d){return _this.colorScale(d.values.raw[0][config.color_by])}).attr("fill",function(d){return _this.colorScale(d.values.raw[0][config.color_by])});bars.each(function(d){var mark=d3.select(this.parentNode.parentNode).datum();d.tooltip=mark.tooltip;d.arrange=mark.split&&mark.arrange?mark.arrange:mark.split?"grouped":null;d.subcats=config.legend.order?config.legend.order.slice().reverse():mark.values&&mark.values[mark.split]?mark.values[mark.split]:d3.set(rawData.map(function(m){return m[mark.split]})).values();d3.select(this).attr(mark.attributes)});var xformat=config.marks.map(function(m){return m.summarizeX==="percent"}).indexOf(true)>-1?d3.format("0%"):d3.format(config.x.format);var yformat=config.marks.map(function(m){return m.summarizeY==="percent"}).indexOf(true)>-1?d3.format("0%"):d3.format(config.y.format);bars.select("title").text(function(d){var tt=d.tooltip||"";return tt.replace(/\$x/g,xformat(d.values.x)).replace(/\$y/g,yformat(d.values.y)).replace(/\[(.+?)\]/g,function(str,orig){return d.values.raw[0][orig]})});var barsTrans=config.transitions?bars.transition():bars;barsTrans.attr("x",function(d){var position=void 0;if(!d.arrange||d.arrange==="stacked"){return _this.x(d.values.x)}else if(d.arrange==="nested"){var _position=d.subcats.indexOf(d.key);var offset=_position?_this.x.rangeBand()/(d.subcats.length*.75)/_position:_this.x.rangeBand();return _this.x(d.values.x)+(_this.x.rangeBand()-offset)/2}else{position=d.subcats.indexOf(d.key);return _this.x(d.values.x)+_this.x.rangeBand()/d.subcats.length*position}}).attr("y",function(d){if(d.arrange!=="stacked"){return _this.y(d.values.y)}else{return _this.y(d.values.start)}}).attr("width",function(d){if(!d.arrange||d.arrange==="stacked"){return _this.x.rangeBand()}else if(d.arrange==="nested"){var position=d.subcats.indexOf(d.key);return position?_this.x.rangeBand()/(d.subcats.length*.75)/position:_this.x.rangeBand()}else{return _this.x.rangeBand()/d.subcats.length}}).attr("height",function(d){return _this.y(0)-_this.y(d.values.y)})}else if(config.y.type==="ordinal"){oldBarsTrans.attr("x",this.x(0)).attr("width",0);oldBarGroupsTrans.remove();nu_bar_groups=bar_groups.enter().append("g").attr("class",function(d){return"bar-group "+d.key});nu_bar_groups.append("title");bars=bar_groups.selectAll("rect").data(function(d){return d.values instanceof Array?d.values.sort(function(a,b){return _this.colorScale.domain().indexOf(b.key)-_this.colorScale.domain().indexOf(a.key)}):[d]},function(d){return d.key});var _exitBars=config.transitions?bars.exit().transition():bars.exit();_exitBars.attr("x",this.x(0)).attr("width",0).remove();bars.enter().append("rect").attr("class",function(d){return"wc-data-mark bar "+d.key}).style("clip-path","url(#"+this.id+")").attr("x",this.x(0)).attr("width",0).append("title");bars.attr("shape-rendering","crispEdges").attr("stroke",function(d){return _this.colorScale(d.values.raw[0][config.color_by])}).attr("fill",function(d){return _this.colorScale(d.values.raw[0][config.color_by])});bars.each(function(d){var mark=d3.select(this.parentNode.parentNode).datum();d.arrange=mark.split&&mark.arrange?mark.arrange:mark.split?"grouped":null;d.subcats=config.legend.order?config.legend.order.slice().reverse():mark.values&&mark.values[mark.split]?mark.values[mark.split]:d3.set(rawData.map(function(m){return m[mark.split]})).values();d.tooltip=mark.tooltip;d3.select(this).attr(mark.attributes)});var _xformat=config.marks.map(function(m){return m.summarizeX==="percent"}).indexOf(true)>-1?d3.format("0%"):d3.format(config.x.format);var _yformat=config.marks.map(function(m){return m.summarizeY==="percent"}).indexOf(true)>-1?d3.format("0%"):d3.format(config.y.format);bars.select("title").text(function(d){var tt=d.tooltip||"";return tt.replace(/\$x/g,_xformat(d.values.x)).replace(/\$y/g,_yformat(d.values.y)).replace(/\[(.+?)\]/g,function(str,orig){return d.values.raw[0][orig]})});var _barsTrans=config.transitions?bars.transition():bars;_barsTrans.attr("x",function(d){if(d.arrange==="stacked"||!d.arrange){return d.values.start!==undefined?_this.x(d.values.start):_this.x(0)}else{return _this.x(0)}}).attr("y",function(d){if(d.arrange==="nested"){var position=d.subcats.indexOf(d.key);var offset=position?_this.y.rangeBand()/(d.subcats.length*.75)/position:_this.y.rangeBand();return _this.y(d.values.y)+(_this.y.rangeBand()-offset)/2}else if(d.arrange==="grouped"){var _position2=d.subcats.indexOf(d.key);return _this.y(d.values.y)+_this.y.rangeBand()/d.subcats.length*_position2}else{return _this.y(d.values.y)}}).attr("width",function(d){return _this.x(d.values.x)-_this.x(0)}).attr("height",function(d){if(config.y.type==="quantile"){return 20}else if(d.arrange==="nested"){var position=d.subcats.indexOf(d.key);return position?_this.y.rangeBand()/(d.subcats.length*.75)/position:_this.y.rangeBand()}else if(d.arrange==="grouped"){return _this.y.rangeBand()/d.subcats.length}else{return _this.y.rangeBand()}})}else if(["linear","log"].indexOf(config.x.type)>-1&&config.x.bin){oldBarsTrans.attr("y",this.y(0)).attr("height",0);oldBarGroupsTrans.remove();nu_bar_groups=bar_groups.enter().append("g").attr("class",function(d){return"bar-group "+d.key});nu_bar_groups.append("title");bars=bar_groups.selectAll("rect").data(function(d){return d.values instanceof Array?d.values:[d]},function(d){return d.key});var _exitBars2=config.transitions?bars.exit().transition():bars.exit();_exitBars2.attr("y",this.y(0)).attr("height",0).remove();bars.enter().append("rect").attr("class",function(d){return"wc-data-mark bar "+d.key}).style("clip-path","url(#"+this.id+")").attr("y",this.y(0)).attr("height",0).append("title");bars.attr("shape-rendering","crispEdges").attr("stroke",function(d){return _this.colorScale(d.values.raw[0][config.color_by])}).attr("fill",function(d){return _this.colorScale(d.values.raw[0][config.color_by])});bars.each(function(d){var mark=d3.select(this.parentNode.parentNode).datum();d.arrange=mark.split?mark.arrange:null;d.subcats=config.legend.order?config.legend.order.slice().reverse():mark.values&&mark.values[mark.split]?mark.values[mark.split]:d3.set(rawData.map(function(m){return m[mark.split]})).values();d3.select(this).attr(mark.attributes);var parent=d3.select(this.parentNode).datum();var rangeSet=parent.key.split(",").map(function(m){return+m});d.rangeLow=d3.min(rangeSet);d.rangeHigh=d3.max(rangeSet);d.tooltip=mark.tooltip});var _xformat2=config.marks.map(function(m){return m.summarizeX==="percent"}).indexOf(true)>-1?d3.format("0%"):d3.format(config.x.format);var _yformat2=config.marks.map(function(m){return m.summarizeY==="percent"}).indexOf(true)>-1?d3.format("0%"):d3.format(config.y.format);bars.select("title").text(function(d){var tt=d.tooltip||"";return tt.replace(/\$x/g,_xformat2(d.values.x)).replace(/\$y/g,_yformat2(d.values.y)).replace(/\[(.+?)\]/g,function(str,orig){return d.values.raw[0][orig]})});var _barsTrans2=config.transitions?bars.transition():bars;_barsTrans2.attr("x",function(d){return _this.x(d.rangeLow)}).attr("y",function(d){if(d.arrange!=="stacked"){return _this.y(d.values.y)}else{return _this.y(d.values.start)}}).attr("width",function(d){return _this.x(d.rangeHigh)-_this.x(d.rangeLow)}).attr("height",function(d){return _this.y(0)-_this.y(d.values.y)})}else if(["linear","log"].indexOf(config.y.type)>-1&&config.y.type==="linear"&&config.y.bin){oldBarsTrans.attr("x",this.x(0)).attr("width",0);oldBarGroupsTrans.remove();nu_bar_groups=bar_groups.enter().append("g").attr("class",function(d){return"bar-group "+d.key});nu_bar_groups.append("title");bars=bar_groups.selectAll("rect").data(function(d){return d.values instanceof Array?d.values:[d]},function(d){return d.key});var _exitBars3=config.transitions?bars.exit().transition():bars.exit();_exitBars3.attr("x",this.x(0)).attr("width",0).remove();bars.enter().append("rect").attr("class",function(d){return"wc-data-mark bar "+d.key}).style("clip-path","url(#"+this.id+")").attr("x",this.x(0)).attr("width",0).append("title");bars.attr("shape-rendering","crispEdges").attr("stroke",function(d){return _this.colorScale(d.values.raw[0][config.color_by])}).attr("fill",function(d){return _this.colorScale(d.values.raw[0][config.color_by])});bars.each(function(d){var mark=d3.select(this.parentNode.parentNode).datum();d.arrange=mark.split?mark.arrange:null;d.subcats=config.legend.order?config.legend.order.slice().reverse():mark.values&&mark.values[mark.split]?mark.values[mark.split]:d3.set(rawData.map(function(m){return m[mark.split]})).values();var parent=d3.select(this.parentNode).datum();var rangeSet=parent.key.split(",").map(function(m){return+m});d.rangeLow=d3.min(rangeSet);d.rangeHigh=d3.max(rangeSet);d.tooltip=mark.tooltip});var _xformat3=config.marks.map(function(m){return m.summarizeX==="percent"}).indexOf(true)>-1?d3.format("0%"):d3.format(config.x.format);var _yformat3=config.marks.map(function(m){return m.summarizeY==="percent"}).indexOf(true)>-1?d3.format("0%"):d3.format(config.y.format);bars.select("title").text(function(d){var tt=d.tooltip||"";return tt.replace(/\$x/g,_xformat3(d.values.x)).replace(/\$y/g,_yformat3(d.values.y)).replace(/\[(.+?)\]/g,function(str,orig){return d.values.raw[0][orig]})});var _barsTrans3=config.transitions?bars.transition():bars;_barsTrans3.attr("x",function(d){if(d.arrange==="stacked"){return _this.x(d.values.start)}else{return _this.x(0)}}).attr("y",function(d){return _this.y(d.rangeHigh)}).attr("width",function(d){return _this.x(d.values.x)}).attr("height",function(d){return _this.y(d.rangeLow)-_this.y(d.rangeHigh)})}else{oldBarsTrans.attr("y",this.y(0)).attr("height",0);oldBarGroupsTrans.remove();bar_supergroups.remove()}bar_supergroups.each(function(d){d.supergroup=d3.select(this);d.groups=d.supergroup.selectAll(".bar-group")})}function drawLines(marks){var _this=this;var config=this.config;var line=d3.svg.line().interpolate(config.interpolate).x(function(d){return config.x.type==="linear"||config.x.type=="log"?_this.x(+d.values.x):config.x.type==="time"?_this.x(new Date(d.values.x)):_this.x(d.values.x)+_this.x.rangeBand()/2}).y(function(d){return config.y.type==="linear"||config.y.type=="log"?_this.y(+d.values.y):config.y.type==="time"?_this.y(new Date(d.values.y)):_this.y(d.values.y)+_this.y.rangeBand()/2});var line_supergroups=this.svg.selectAll(".line-supergroup").data(marks,function(d,i){return i+"-"+d.per.join("-")});line_supergroups.enter().append("g").attr("class",function(d){return"supergroup line-supergroup "+d.id});line_supergroups.exit().remove();var line_grps=line_supergroups.selectAll(".line").data(function(d){return d.data},function(d){return d.key});line_grps.exit().remove();var nu_line_grps=line_grps.enter().append("g").attr("class",function(d){return d.key+" line"});nu_line_grps.append("path");nu_line_grps.append("title");var linePaths=line_grps.select("path").attr("class","wc-data-mark").datum(function(d){return d.values}).attr("stroke",function(d){return _this.colorScale(d[0].values.raw[0][config.color_by])}).attr("stroke-width",config.stroke_width?config.stroke_width:config.flex_stroke_width).attr("stroke-linecap","round").attr("fill","none");var linePathsTrans=config.transitions?linePaths.transition():linePaths;linePathsTrans.attr("d",line);line_grps.each(function(d){var mark=d3.select(this.parentNode).datum();d.tooltip=mark.tooltip;d3.select(this).select("path").attr(mark.attributes)});line_grps.select("title").text(function(d){var tt=d.tooltip||"";var xformat=config.x.summary==="percent"?d3.format("0%"):d3.format(config.x.format);var yformat=config.y.summary==="percent"?d3.format("0%"):d3.format(config.y.format);return tt.replace(/\$x/g,xformat(d.values.x)).replace(/\$y/g,yformat(d.values.y)).replace(/\[(.+?)\]/g,function(str,orig){return d.values[0].values.raw[0][orig]})});line_supergroups.each(function(d){d.supergroup=d3.select(this);d.groups=d.supergroup.selectAll("g.line");d.paths=d.groups.select("path")});return line_grps}function drawPoints(marks){var _this=this;var config=this.config;var point_supergroups=this.svg.selectAll(".point-supergroup").data(marks,function(d,i){return i+"-"+d.per.join("-")});point_supergroups.enter().append("g").attr("class",function(d){return"supergroup point-supergroup "+d.id});point_supergroups.exit().remove();var points=point_supergroups.selectAll(".point").data(function(d){return d.data},function(d){return d.key});var oldPoints=points.exit();var oldPointsTrans=config.transitions?oldPoints.selectAll("circle").transition():oldPoints.selectAll("circle");oldPointsTrans.attr("r",0);var oldPointGroupTrans=config.transitions?oldPoints.transition():oldPoints;oldPointGroupTrans.remove();var nupoints=points.enter().append("g").attr("class",function(d){return d.key+" point"});nupoints.append("circle").attr("class","wc-data-mark").attr("r",0);nupoints.append("title");points.select("circle").attr("fill-opacity",config.fill_opacity||config.fill_opacity===0?config.fill_opacity:.6).attr("fill",function(d){return _this.colorScale(d.values.raw[0][config.color_by])}).attr("stroke",function(d){return _this.colorScale(d.values.raw[0][config.color_by])});points.each(function(d){var mark=d3.select(this.parentNode).datum();d.mark=mark;d3.select(this).select("circle").attr(mark.attributes)});var pointsTrans=config.transitions?points.select("circle").transition():points.select("circle");pointsTrans.attr("r",function(d){return d.mark.radius||config.flex_point_size}).attr("cx",function(d){var x_pos=_this.x(d.values.x)||0;return config.x.type==="ordinal"?x_pos+_this.x.rangeBand()/2:x_pos}).attr("cy",function(d){var y_pos=_this.y(d.values.y)||0;return config.y.type==="ordinal"?y_pos+_this.y.rangeBand()/2:y_pos});points.select("title").text(function(d){var tt=d.mark.tooltip||"";var xformat=config.x.summary==="percent"?d3.format("0%"):config.x.type==="time"?d3.time.format(config.x.format):d3.format(config.x.format);var yformat=config.y.summary==="percent"?d3.format("0%"):config.y.type==="time"?d3.time.format(config.y.format):d3.format(config.y.format);return tt.replace(/\$x/g,config.x.type==="time"?xformat(new Date(d.values.x)):xformat(d.values.x)).replace(/\$y/g,config.y.type==="time"?yformat(new Date(d.values.y)):yformat(d.values.y)).replace(/\[(.+?)\]/g,function(str,orig){return d.values.raw[0][orig]})});point_supergroups.each(function(d){d.supergroup=d3.select(this);d.groups=d.supergroup.selectAll("g.point");d.circles=d.groups.select("circle")});return points}function drawText(marks){var _this=this;var config=this.config;var textSupergroups=this.svg.selectAll(".text-supergroup").data(marks,function(d,i){return i+"-"+d.per.join("-")});textSupergroups.enter().append("g").attr("class",function(d){return"supergroup text-supergroup "+d.id});textSupergroups.exit().remove();var texts=textSupergroups.selectAll(".text").data(function(d){return d.data},function(d){return d.key});var oldTexts=texts.exit();var oldTextGroupTrans=config.transitions?oldTexts.transition():oldTexts;oldTextGroupTrans.remove();var nutexts=texts.enter().append("g").attr("class",function(d){return d.key+" text"});nutexts.append("text").attr("class","wc-data-mark");function attachMarks(d){d.mark=d3.select(this.parentNode).datum();d3.select(this).select("text").attr(d.mark.attributes)}texts.each(attachMarks);texts.select("text").text(function(d){var tt=d.mark.text||"";var xformat=config.x.summary==="percent"?d3.format("0%"):config.x.type==="time"?d3.time.format(config.x.format):d3.format(config.x.format);var yformat=config.y.summary==="percent"?d3.format("0%"):config.y.type==="time"?d3.time.format(config.y.format):d3.format(config.y.format);return tt.replace(/\$x/g,config.x.type==="time"?xformat(new Date(d.values.x)):xformat(d.values.x)).replace(/\$y/g,config.y.type==="time"?yformat(new Date(d.values.y)):yformat(d.values.y)).replace(/\[(.+?)\]/g,function(str,orig){return d.values.raw[0][orig]})});var textsTrans=config.transitions?texts.select("text").transition():texts.select("text");textsTrans.attr("x",function(d){var xPos=_this.x(d.values.x)||0;return config.x.type==="ordinal"?xPos+_this.x.rangeBand()/2:xPos}).attr("y",function(d){var yPos=_this.y(d.values.y)||0;return config.y.type==="ordinal"?yPos+_this.y.rangeBand()/2:yPos});textSupergroups.each(function(d){d.supergroup=d3.select(this);d.groups=d.supergroup.selectAll("g.text");d.texts=d.groups.select("text")});return texts}function destroy(){var destroyControls=arguments.length>0&&arguments[0]!==undefined?arguments[0]:true;this.events.onDestroy.call(this);var context=this;d3.select(window).on("resize."+context.element+context.id,null);if(destroyControls&&this.controls){this.controls.destroy()}this.wrap.remove()}var chartProto={raw_data:[],config:{}};var chart=Object.create(chartProto,{checkRequired:{value:checkRequired},consolidateData:{value:consolidateData},draw:{value:draw},destroy:{value:destroy},drawArea:{value:drawArea},drawBars:{value:drawBars},drawGridlines:{value:drawGridLines},drawLines:{value:drawLines},drawPoints:{value:drawPoints},drawText:{value:drawText},init:{value:init},layout:{value:layout},makeLegend:{value:makeLegend},resize:{value:resize},setColorScale:{value:setColorScale},setDefaults:{value:setDefaults},setMargins:{value:setMargins},textSize:{value:textSize},transformData:{value:transformData},updateDataMarks:{value:updateDataMarks},xScaleAxis:{value:xScaleAxis},yScaleAxis:{value:yScaleAxis}});var chartCount=0;function createChart(){var element=arguments.length>0&&arguments[0]!==undefined?arguments[0]:"body";var config=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};var controls=arguments.length>2&&arguments[2]!==undefined?arguments[2]:null;var thisChart=Object.create(chart);thisChart.div=element;thisChart.config=Object.create(config);thisChart.controls=controls;thisChart.raw_data=[];thisChart.filters=[];thisChart.marks=[];thisChart.wrap=d3.select(thisChart.div).append("div").datum(thisChart);thisChart.events={onInit:function onInit(){},onLayout:function onLayout(){},onPreprocess:function onPreprocess(){},onDatatransform:function onDatatransform(){},onDraw:function onDraw(){},onResize:function onResize(){},onDestroy:function onDestroy(){}};thisChart.on=function(event,callback){var possible_events=["init","layout","preprocess","datatransform","draw","resize","destroy"];if(possible_events.indexOf(event)<0){return}if(callback){thisChart.events["on"+event.charAt(0).toUpperCase()+event.slice(1)]=callback}};chartCount++;thisChart.id=chartCount;return thisChart}function changeOption(option,value,callback){var _this=this;this.targets.forEach(function(e){if(option instanceof Array){option.forEach(function(o){return _this.stringAccessor(e.config,o,value)})}else{_this.stringAccessor(e.config,option,value)}if(callback){callback()}e.draw()})}function checkRequired$1(dataset){if(!dataset[0]||!this.config.inputs){return}var colnames=d3.keys(dataset[0]);this.config.inputs.forEach(function(e,i){if(e.type==="subsetter"&&colnames.indexOf(e.value_col)===-1){throw new Error('Error in settings object: the value "'+e.value_col+'" does not match any column in the provided dataset.')}})}function controlUpdate(){var _this=this;if(this.config.inputs&&this.config.inputs.length&&this.config.inputs[0]){this.config.inputs.forEach(function(e){return _this.makeControlItem(e)})}}function destroy$1(){this.wrap.remove()}function init$1(data){this.data=data;if(!this.config.builder){this.checkRequired(this.data)}this.layout()}function layout$1(){this.wrap.selectAll("*").remove();this.ready=true;this.controlUpdate()}function makeControlItem(control){var control_wrap=this.wrap.append("div").attr("class","control-group").classed("inline",control.inline).datum(control);var ctrl_label=control_wrap.append("span").attr("class","wc-control-label").text(control.label);if(control.required){ctrl_label.append("span").attr("class","label label-required").text("Required")}control_wrap.append("span").attr("class","span-description").text(control.description);if(control.type==="text"){this.makeTextControl(control,control_wrap)}else if(control.type==="number"){this.makeNumberControl(control,control_wrap)}else if(control.type==="list"){this.makeListControl(control,control_wrap)}else if(control.type==="dropdown"){this.makeDropdownControl(control,control_wrap)}else if(control.type==="btngroup"){this.makeBtnGroupControl(control,control_wrap)}else if(control.type==="checkbox"){this.makeCheckboxControl(control,control_wrap)}else if(control.type==="radio"){this.makeRadioControl(control,control_wrap)}else if(control.type==="subsetter"){this.makeSubsetterControl(control,control_wrap)}else{throw new Error('Each control must have a type! Choose from: "text", "number", "list", "dropdown", "btngroup", "checkbox", "radio", "subsetter"')}}function makeBtnGroupControl(control,control_wrap){var _this=this;var option_data=control.values?control.values:d3.keys(this.data[0]);var btn_wrap=control_wrap.append("div").attr("class","btn-group");var changers=btn_wrap.selectAll("button").data(option_data).enter().append("button").attr("class","btn btn-default btn-sm").text(function(d){return d}).classed("btn-primary",function(d){return _this.stringAccessor(_this.targets[0].config,control.option)===d});changers.on("click",function(d){changers.each(function(e){d3.select(this).classed("btn-primary",e===d)});_this.changeOption(control.option,d,control.callback)})}function makeCheckboxControl(control,control_wrap){var _this=this;var changer=control_wrap.append("input").attr("type","checkbox").attr("class","changer").datum(control).property("checked",function(d){return _this.stringAccessor(_this.targets[0].config,control.option)});changer.on("change",function(d){var value=changer.property("checked");_this.changeOption(d.option,value,control.callback)})}function makeDropdownControl(control,control_wrap){var _this=this;var mainOption=control.option||control.options[0];var changer=control_wrap.append("select").attr("class","changer").attr("multiple",control.multiple?true:null).datum(control);var opt_values=control.values&&control.values instanceof Array?control.values:control.values?d3.set(this.data.map(function(m){return m[_this.targets[0].config[control.values]]})).values():d3.keys(this.data[0]);if(!control.require||control.none){opt_values.unshift("None")}var options=changer.selectAll("option").data(opt_values).enter().append("option").text(function(d){return d}).property("selected",function(d){return _this.stringAccessor(_this.targets[0].config,mainOption)===d});changer.on("change",function(d){var value=changer.property("value")==="None"?null:changer.property("value");if(control.multiple){value=options.filter(function(f){return d3.select(this).property("selected")})[0].map(function(m){return d3.select(m).property("value")}).filter(function(f){return f!=="None"})}if(control.options){_this.changeOption(control.options,value,control.callback)}else{_this.changeOption(control.option,value,control.callback)}});return changer}function makeListControl(control,control_wrap){var _this=this;var changer=control_wrap.append("input").attr("type","text").attr("class","changer").datum(control).property("value",function(d){return _this.stringAccessor(_this.targets[0].config,control.option)});changer.on("change",function(d){var value=changer.property("value")?changer.property("value").split(",").map(function(m){return m.trim()}):null;_this.changeOption(control.option,value,control.callback)})}function makeNumberControl(control,control_wrap){var _this=this;var changer=control_wrap.append("input").attr("type","number").attr("min",control.min!==undefined?control.min:0).attr("max",control.max).attr("step",control.step||1).attr("class","changer").datum(control).property("value",function(d){return _this.stringAccessor(_this.targets[0].config,control.option)});changer.on("change",function(d){var value=+changer.property("value");_this.changeOption(control.option,value,control.callback)})}function makeRadioControl(control,control_wrap){var _this=this;var changers=control_wrap.selectAll("label").data(control.values||d3.keys(this.data[0])).enter().append("label").attr("class","radio").text(function(d,i){return control.relabels?control.relabels[i]:d}).append("input").attr("type","radio").attr("class","changer").attr("name",control.option.replace(".","-")+"-"+this.targets[0].id).property("value",function(d){return d}).property("checked",function(d){return _this.stringAccessor(_this.targets[0].config,control.option)===d});changers.on("change",function(d){var value=null;changers.each(function(c){if(d3.select(this).property("checked")){value=d3.select(this).property("value")==="none"?null:c}});_this.changeOption(control.option,value,control.callback)})}function makeSubsetterControl(control,control_wrap){var targets=this.targets;var changer=control_wrap.append("select").attr("class","changer").attr("multiple",control.multiple?true:null).datum(control);var option_data=control.values?control.values:d3.set(this.data.map(function(m){return m[control.value_col]}).filter(function(f){return f})).values();option_data.sort(naturalSorter);control.start=control.start?control.start:control.loose?option_data[0]:null;if(!control.multiple&&!control.start){option_data.unshift("All")}control.loose=!control.loose&&control.start?true:control.loose;var options=changer.selectAll("option").data(option_data).enter().append("option").text(function(d){return d}).property("selected",function(d){return d===control.start});targets.forEach(function(e){var match=e.filters.slice().map(function(m){return m.col===control.value_col}).indexOf(true);if(match>-1){e.filters[match]={col:control.value_col,val:control.start?control.start:"All",choices:option_data,loose:control.loose}}else{e.filters.push({col:control.value_col,val:control.start?control.start:"All",choices:option_data,loose:control.loose})}});function setSubsetter(target,obj){var match=-1;target.filters.forEach(function(e,i){if(e.col===obj.col){match=i}});if(match>-1){target.filters[match]=obj}}changer.on("change",function(d){if(control.multiple){var values=options.filter(function(f){return d3.select(this).property("selected")})[0].map(function(m){return d3.select(m).property("text")});var new_filter={col:control.value_col,val:values,choices:option_data,loose:control.loose};targets.forEach(function(e){setSubsetter(e,new_filter);if(control.callback){control.callback()}e.draw()})}else{var value=d3.select(this).select("option:checked").property("text");var _new_filter={col:control.value_col,val:value,choices:option_data,loose:control.loose};targets.forEach(function(e){setSubsetter(e,_new_filter);if(control.callback){control.callback()}e.draw()})}})}function makeTextControl(control,control_wrap){var _this=this;var changer=control_wrap.append("input").attr("type","text").attr("class","changer").datum(control).property("value",function(d){return _this.stringAccessor(_this.targets[0].config,control.option)});changer.on("change",function(d){var value=changer.property("value");_this.changeOption(control.option,value,control.callback)})}function stringAccessor(o,s,v){s=s.replace(/\[(\w+)\]/g,".$1");s=s.replace(/^\./,"");var a=s.split(".");for(var i=0,n=a.length;i0&&arguments[0]!==undefined?arguments[0]:"body";var config=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};var thisControls=Object.create(controls);thisControls.div=element;thisControls.config=Object.create(config);thisControls.config.inputs=thisControls.config.inputs||[];thisControls.targets=[];if(config.location==="bottom"){thisControls.wrap=d3.select(element).append("div").attr("class","wc-controls")}else{thisControls.wrap=d3.select(element).insert("div",":first-child").attr("class","wc-controls")}thisControls.wrap.datum(thisControls);return thisControls}var _typeof=typeof Symbol==="function"&&typeof Symbol.iterator==="symbol"?function(obj){return typeof obj}:function(obj){return obj&&typeof Symbol==="function"&&obj.constructor===Symbol&&obj!==Symbol.prototype?"symbol":typeof obj};function clone(obj){var copy=void 0;if("object"!=(typeof obj==="undefined"?"undefined":_typeof(obj))||null==obj)return obj;if(obj instanceof Date){copy=new Date;copy.setTime(obj.getTime());return copy}if(obj instanceof Array){copy=[];for(var i=0,len=obj.length;i-1:filter.val===d[filter.col]});return match}):clone(this.data.raw)}function updateDataObject(){this.data.raw=this.data.passed;this.data.filtered=this.data.passed;this.config.activePage=0;this.config.startIndex=this.config.activePage*this.config.nRowsPerPage;this.config.endIndex=this.config.startIndex+this.config.nRowsPerPage}function applySearchTerm(data){var _this=this;if(this.searchable.searchTerm){this.data.searched=this.data.filtered.filter(function(d){var match=false;Object.keys(d).filter(function(key){return _this.config.cols.indexOf(key)>-1}).forEach(function(var_name){if(match===false){var cellText=""+d[var_name];match=cellText.toLowerCase().indexOf(_this.searchable.searchTerm)>-1}});return match});this.data.processing=this.data.searched}else{delete this.data.searched;this.data.processing=this.data.filtered}}if(Array.prototype.equals)console.warn("Overriding existing Array.prototype.equals. Possible causes: New API defines the method, there's a framework conflict or you've got double inclusions in your code.");Array.prototype.equals=function(array){if(!array)return false;if(this.length!=array.length)return false;for(var i=0,l=this.length;i=Math.max(widths.top,widths.bottom)&&this.config.layout==="vertical"){this.config.layout="horizontal";this.wrap.style("display","table").selectAll(".table-top,.table-bottom").style("display","block").selectAll(".interactivity").style({display:"inline-block",float:function float(){return select(this).classed("searchable-container")||select(this).classed("pagination-container")?"right":null},clear:null})}}function draw$1(passed_data){var _this=this;var table=this;var config=this.config;this.data.passed=passed_data;this.events.onPreprocess.call(this);if(!passed_data)applyFilters.call(this);else updateDataObject.call(this);checkFilters.call(this);applySearchTerm.call(this);this.searchable.wrap.select(".nNrecords").text(this.data.processing.length===this.data.raw.length?this.data.raw.length+" records displayed":this.data.processing.length+"/"+this.data.raw.length+" records displayed");updateTableHeaders.call(this);this.tbody.selectAll("tr").remove();if(this.data.processing.length===0){this.tbody.append("tr").classed("no-data",true).append("td").attr("colspan",this.config.cols.length).text("No data selected.");this.data.current=clone(this.data.processing);this.table.datum(this.table.current);if(this.config.exportable)this.config.exports.forEach(function(fmt){_this.exportable.exports[fmt].call(_this,_this.data.processing)});if(this.config.pagination)this.pagination.addPagination.call(this,this.data.processing)}else{if(this.config.sortable){this.thead.selectAll("th").on("click",function(header){table.sortable.onClick.call(table,this,header)});if(this.sortable.order.length)this.sortable.sortData.call(this,this.data.processing)}this.data.current=clone(this.data.processing);this.table.datum(this.data.current);if(this.config.exportable)this.config.exports.forEach(function(fmt){_this.exportable.exports[fmt].call(_this,_this.data.processing)});if(this.config.pagination){this.pagination.addPagination.call(this,this.data.processing);this.data.processing=this.data.processing.filter(function(d,i){return _this.config.startIndex<=i&&i<_this.config.endIndex})}drawTableBody.call(this)}dynamicLayout.call(this);this.events.onDraw.call(this)}function layout$2(){var context=this;this.searchable.wrap=this.wrap.select(".table-top").append("div").classed("interactivity searchable-container",true).classed("hidden",!this.config.searchable);this.searchable.wrap.append("div").classed("search",true);this.searchable.wrap.select(".search").append("input").classed("search-box",true).attr("placeholder","Search").on("input",function(){context.searchable.searchTerm=this.value.toLowerCase()||null;context.config.activePage=0;context.config.startIndex=context.config.activePage*context.config.nRowsPerPage;context.config.endIndex=context.config.startIndex+context.config.nRowsPerPage;context.draw()});this.searchable.wrap.select(".search").append("span").classed("nNrecords",true)}function searchable(){return{layout:layout$2}}function layout$3(){var _this=this;this.exportable.wrap=this.wrap.select(".table-bottom").append("div").classed("interactivity exportable-container",true).classed("hidden",!this.config.exportable);this.exportable.wrap.append("span").text("Export:");if(this.config.exports&&this.config.exports.length)this.config.exports.forEach(function(fmt){_this.exportable.wrap.append("a").classed("wc-button export",true).attr({id:fmt}).text(fmt.toUpperCase())})}function csv(data){var _this=this;var CSVarray=[];var headers=this.config.headers.map(function(header){return'"'+header.replace(/"/g,'""')+'"'});CSVarray.push(headers);data.forEach(function(d,i){var row=_this.config.cols.map(function(col){var value=d[col];if(typeof value==="string")value=value.replace(/"/g,'""');return'"'+value+'"'});CSVarray.push(row)});var CSV=new Blob([CSVarray.join("\n")],{type:"text/csv;charset=utf-8;"}),fileName="webchartsTableExport_"+d3.time.format("%Y-%m-%dT%H-%M-%S")(new Date)+".csv",link=this.wrap.select(".export#csv");if(navigator.msSaveBlob){link.style({cursor:"pointer","text-decoration":"underline",color:"blue"});link.on("click",function(){navigator.msSaveBlob(CSV,fileName)})}else{if(link.node().download!==undefined){var url=URL.createObjectURL(CSV);link.node().setAttribute("href",url);link.node().setAttribute("download",fileName)}}}function xlsx(data){var _this=this;var sheetName="Selected Data",options={bookType:"xlsx",bookSST:true,type:"binary"},arrayOfArrays=data.map(function(d){return Object.keys(d).filter(function(key){return _this.config.cols.indexOf(key)>-1}).map(function(key){return d[key]})}),workbook={SheetNames:[sheetName],Sheets:{}},cols=[];workbook.Sheets[sheetName]=XLSX.utils.aoa_to_sheet([this.config.headers].concat(arrayOfArrays));workbook.Sheets[sheetName]["!autofilter"]={ref:"A1:"+String.fromCharCode(64+this.config.cols.length)+(data.length+1)};this.table.selectAll("thead tr th").each(function(){cols.push({wpx:this.offsetWidth})});workbook.Sheets[sheetName]["!cols"]=cols;var xlsx=XLSX.write(workbook,options),s2ab=function s2ab(s){var buffer=new ArrayBuffer(s.length),view=new Uint8Array(buffer);for(var i=0;i!==s.length;++i){view[i]=s.charCodeAt(i)&255}return buffer};var blob=new Blob([s2ab(xlsx)],{type:"application/octet-stream;"}),fileName="webchartsTableExport_"+d3.time.format("%Y-%m-%dT%H-%M-%S")(new Date)+".xlsx",link=this.wrap.select(".export#xlsx");if(navigator.msSaveBlob){link.style({cursor:"pointer","text-decoration":"underline",color:"blue"});link.on("click",function(){navigator.msSaveBlob(blob,fileName)})}else{if(link.node().download!==undefined){var url=URL.createObjectURL(blob);link.node().setAttribute("href",url);link.node().setAttribute("download",fileName)}}}var exports$1={csv:csv,xlsx:xlsx};function exportable(){return{layout:layout$3,exports:exports$1}}function layout$4(){this.sortable.wrap=this.wrap.select(".table-top").append("div").classed("interactivity sortable-container",true).classed("hidden",!this.config.sortable);this.sortable.wrap.append("div").classed("instruction",true).text("Click column headers to sort.")}function onClick(th,header){var context=this,selection=d3.select(th),col=this.config.cols[this.config.headers.indexOf(header)];var sortItem=this.sortable.order.filter(function(item){return item.col===col})[0];if(!sortItem){sortItem={col:col,direction:"ascending",wrap:this.sortable.wrap.append("div").datum({key:col}).classed("wc-button sort-box",true).text(header)};sortItem.wrap.append("span").classed("sort-direction",true).html("↓");sortItem.wrap.append("span").classed("remove-sort",true).html("❌");this.sortable.order.push(sortItem)}else{sortItem.direction=sortItem.direction==="ascending"?"descending":"ascending";sortItem.wrap.select("span.sort-direction").html(sortItem.direction==="ascending"?"↓":"↑")}this.sortable.wrap.select(".instruction").classed("hidden",true);this.sortable.order.forEach(function(item,i){item.wrap.on("click",function(d){d3.select(this).remove();context.sortable.order.splice(context.sortable.order.map(function(d){return d.col}).indexOf(d.key),1);context.sortable.wrap.select(".instruction").classed("hidden",context.sortable.order.length);context.draw()})});this.draw()}function sortData(data){var _this=this;data=data.sort(function(a,b){var order=0;_this.sortable.order.forEach(function(item){var aCell=a[item.col],bCell=b[item.col];if(order===0){if(item.direction==="ascending"&&aCellbCell)order=-1;else if(item.direction==="ascending"&&aCell>bCell||item.direction==="descending"&&aCell=_this.config.nPageLinksDisplayed:_this.config.activePage>=_this.config.nPages-_this.config.nPageLinksDisplayed?i<_this.config.nPages-_this.config.nPageLinksDisplayed:i<_this.config.activePage-(Math.ceil(_this.config.nPageLinksDisplayed/2)-1)||_this.config.activePage+_this.config.nPageLinksDisplayed/2=this.config.nPages)next=this.config.nPages-1;this.pagination.wrap.insert("span",":first-child").classed("dot-dot-dot",true).text("...").classed("hidden",this.config.activePage=Math.max(this.config.nPageLinksDisplayed,this.config.nPages-this.config.nPageLinksDisplayed)||this.config.nPages<=this.config.nPageLinksDisplayed);this.pagination.next=this.pagination.wrap.append("a").classed("wc-button arrow-link wc-right",true).classed("hidden",this.config.activePage==this.config.nPages-1||this.config.nPages==0).attr({rel:next}).text(">");this.pagination.doubleNext=this.pagination.wrap.append("a").classed("wc-button arrow-link wc-right double",true).classed("hidden",this.config.activePage==this.config.nPages-1||this.config.nPages==0).attr({rel:this.config.nPages-1}).text(">>");this.pagination.arrows=this.pagination.wrap.selectAll("a.arrow-link");this.pagination.doubleArrows=this.pagination.wrap.selectAll("a.double-arrow-link")}function addPagination(data){var context=this;this.config.nRows=data.length;this.config.nPages=Math.ceil(this.config.nRows/this.config.nRowsPerPage);this.config.paginationHidden=this.config.nPages===1;this.pagination.wrap.classed("hidden",this.config.paginationHidden);addLinks.call(this);this.pagination.links.on("click",function(){context.config.activePage=+d3.select(this).attr("rel");updatePagination.call(context)});addArrows.call(this);this.pagination.arrows.on("click",function(){if(context.config.activePage!==+d3.select(this).attr("rel")){context.config.activePage=+d3.select(this).attr("rel");context.pagination.prev.attr("rel",context.config.activePage>0?context.config.activePage-1:0);context.pagination.next.attr("rel",context.config.activePage1&&arguments[1]!==undefined?arguments[1]:false;if(d3.select(this.div).select(".loader").empty()){d3.select(this.div).insert("div",":first-child").attr("class","loader").selectAll(".blockG").data(d3.range(8)).enter().append("div").attr("class",function(d){return"blockG rotate"+(d+1)})}this.setDefaults.call(this,data[0]);this.wrap.classed("wc-chart",true).classed("wc-table",this.config.applyCSS);this.data={raw:data};this.searchable=searchable.call(this);this.sortable=sortable.call(this);this.pagination=pagination.call(this);this.exportable=exportable.call(this);var startup=function startup(data){if(_this.controls){_this.controls.targets.push(_this);if(!_this.controls.ready){_this.controls.init(_this.data.raw)}else{_this.controls.layout()}}var visible=d3.select(_this.div).property("offsetWidth")>0||test;if(!visible){console.warn("The table cannot be initialized inside an element with 0 width. The table will be initialized as soon as the container element is given a width > 0.");var onVisible=setInterval(function(i){var visible_now=d3.select(_this.div).property("offsetWidth")>0;if(visible_now){_this.layout();_this.wrap.datum(_this);_this.draw();clearInterval(onVisible)}},500)}else{_this.layout();_this.wrap.datum(_this);_this.draw()}};this.events.onInit.call(this);if(this.data.raw.length){this.checkRequired(this.data.raw)}startup(data);return this}function layout$6(){d3.select(this.div).select(".loader").remove();this.wrap.append("div").classed("table-top",true);this.searchable.layout.call(this);this.sortable.layout.call(this);this.table=this.wrap.append("table").classed("table",this.config.bootstrap);this.thead=this.table.append("thead");this.thead.append("tr");this.tbody=this.table.append("tbody");this.wrap.append("div").classed("table-bottom",true);this.pagination.layout.call(this);this.exportable.layout.call(this);this.events.onLayout.call(this)}function destroy$2(){var destroyControls=arguments.length>0&&arguments[0]!==undefined?arguments[0]:false;this.events.onDestroy.call(this);if(destroyControls&&this.controls){this.controls.destroy()}this.wrap.remove()}function setDefault(setting){var _default_=arguments.length>1&&arguments[1]!==undefined?arguments[1]:true;this.config[setting]=this.config[setting]!==undefined?this.config[setting]:_default_}function setDefaults$1(firstItem){if(this.config.cols instanceof Array&&this.config.headers instanceof Array){if(this.config.cols.length===0)delete this.config.cols;if(this.config.headers.length===0||this.config.headers.length!==this.config.cols.length)delete this.config.headers}this.config.cols=this.config.cols||d3.keys(firstItem);this.config.headers=this.config.headers||this.config.cols;this.config.layout="horizontal";setDefault.call(this,"searchable");setDefault.call(this,"exportable");setDefault.call(this,"exports",["csv"]);setDefault.call(this,"sortable");setDefault.call(this,"pagination");setDefault.call(this,"nRowsPerPage",10);setDefault.call(this,"nPageLinksDisplayed",5);setDefault.call(this,"applyCSS")}function transformData$1(processed_data){var _this=this;this.data.processed=this.transformData(this.wrap.datum);if(!data){return}this.config.cols=this.config.cols||d3.keys(data[0]);this.config.headers=this.config.headers||this.config.cols;if(this.config.keep){this.config.keep.forEach(function(e){if(_this.config.cols.indexOf(e)===-1){_this.config.cols.unshift(e)}})}var filtered=data;if(this.filters.length){this.filters.forEach(function(e){var is_array=e.val instanceof Array;filtered=filtered.filter(function(d){if(is_array){return e.val.indexOf(d[e.col])!==-1}else{return e.val!=="All"?d[e.col]===e.val:d}})})}var slimmed=d3.nest().key(function(d){if(_this.config.row_per){return _this.config.row_per.map(function(m){return d[m]}).join(" ")}else{return d}}).rollup(function(r){if(_this.config.dataManipulate){r=_this.config.dataManipulate(r)}var nuarr=r.map(function(m){var arr=[];for(var x in m){arr.push({col:x,text:m[x]})}arr.sort(function(a,b){return _this.config.cols.indexOf(a.col)-_this.config.cols.indexOf(b.col)});return{cells:arr,raw:m}});return nuarr}).entries(filtered);this.data.current=slimmed.length?slimmed:[{key:null,values:[]}];this.pagination.wrap.selectAll("*").remove();this.events.onDatatransform.call(this);if(config.row_per){var rev_order=config.row_per.slice(0).reverse();rev_order.forEach(function(e){tbodies.sort(function(a,b){return a.values[0].raw[e]-b.values[0].raw[e]})})}if(config.row_per){rows.filter(function(f,i){return i>0}).selectAll("td").filter(function(f){return config.row_per.indexOf(f.col)>-1}).text("")}return this.data.current}var table=Object.create(chart,{draw:{value:draw$1},init:{value:init$2},layout:{value:layout$6},setDefaults:{value:setDefaults$1},transformData:{value:transformData$1},destroy:{value:destroy$2}});function createTable(){var element=arguments.length>0&&arguments[0]!==undefined?arguments[0]:"body";var config=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};var controls=arguments.length>2&&arguments[2]!==undefined?arguments[2]:null;var thisTable=Object.create(table);thisTable.div=element;thisTable.config=Object.create(config);thisTable.controls=controls;thisTable.filters=[];thisTable.required_cols=[];thisTable.wrap=d3.select(thisTable.div).append("div").datum(thisTable);thisTable.events={onInit:function onInit(){},onLayout:function onLayout(){},onPreprocess:function onPreprocess(){},onDraw:function onDraw(){},onDestroy:function onDestroy(){}};thisTable.on=function(event,callback){var possible_events=["init","layout","preprocess","draw","destroy"];if(possible_events.indexOf(event)<0){return}if(callback){thisTable.events["on"+event.charAt(0).toUpperCase()+event.slice(1)]=callback}};return thisTable}function multiply(chart,data,split_by,order){var test=arguments.length>4&&arguments[4]!==undefined?arguments[4]:false;chart.wrap.classed("wc-layout wc-small-multiples",true).classed("wc-chart",false);chart.master_legend=chart.wrap.append("ul").attr("class","legend");chart.master_legend.append("span").classed("legend-title",true);chart.multiples=[];function goAhead(data){var split_vals=d3.set(data.map(function(m){return m[split_by]})).values().filter(function(f){return f});if(order){split_vals=split_vals.sort(function(a,b){return d3.ascending(order.indexOf(a),order.indexOf(b))})}split_vals.forEach(function(e){var mchart=createChart(chart.wrap.node(),chart.config,chart.controls);chart.multiples.push(mchart);mchart.parent=chart;mchart.events=chart.events;mchart.legend=chart.master_legend;mchart.filters.unshift({col:split_by,val:e,choices:split_vals});mchart.wrap.insert("span","svg").attr("class","wc-chart-title").text(e);mchart.init(data,test)})}goAhead(data)}function getValType(data,variable){var var_vals=d3.set(data.map(function(m){return m[variable]})).values();var vals_numbers=var_vals.filter(function(f){return+f||+f===0});if(var_vals.length===vals_numbers.length&&var_vals.length>4){return"continuous"}else{return"categorical"}}function lengthenRaw(data,columns){var my_data=[];data.forEach(function(e){columns.forEach(function(g){var obj=Object.create(e);obj.wc_category=g;obj.wc_value=e[g];my_data.push(obj)})});return my_data}var dataOps={getValType:getValType,lengthenRaw:lengthenRaw,naturalSorter:naturalSorter,summarize:summarize};var index={version:version,createChart:createChart,createControls:createControls,createTable:createTable,multiply:multiply,dataOps:dataOps};return index}); +(function(global,factory){typeof exports==="object"&&typeof module!=="undefined"?module.exports=factory(require("d3")):typeof define==="function"&&define.amd?define(["d3"],factory):global.webCharts=factory(global.d3)})(this,function(d3){"use strict";var version="1.10.0";function checkRequired(data){var _this=this;var colnames=Object.keys(data[0]);var requiredVars=[];var requiredCols=[];if(this.config.x&&this.config.x.column){requiredVars.push("this.config.x.column");requiredCols.push(this.config.x.column)}if(this.config.y&&this.config.y.column){requiredVars.push("this.config.y.column");requiredCols.push(this.config.y.column)}if(this.config.color_by){requiredVars.push("this.config.color_by");requiredCols.push(this.config.color_by)}if(this.config.marks)this.config.marks.forEach(function(e,i){if(e.per&&e.per.length){e.per.forEach(function(p,j){requiredVars.push("this.config.marks["+i+"].per["+j+"]");requiredCols.push(p)})}if(e.split){requiredVars.push("this.config.marks["+i+"].split");requiredCols.push(e.split)}if(e.values){for(var value in e.values){requiredVars.push("this.config.marks["+i+"].values['"+value+"']");requiredCols.push(value)}}});var missingDataField=false;requiredCols.forEach(function(e,i){if(colnames.indexOf(e)<0){missingDataField=true;d3.select(_this.div).select(".loader").remove();_this.wrap.append("div").style("color","red").html('The value "'+e+'" for the '+requiredVars[i]+" setting does not match any column in the provided dataset.");throw new Error('Error in settings object: The value "'+e+'" for the '+requiredVars[i]+" setting does not match any column in the provided dataset.")}});return{missingDataField:missingDataField,dataFieldArguments:requiredVars,requiredDataFields:requiredCols}}function naturalSorter(a,b){function chunkify(t){var tz=[];var x=0,y=-1,n=0,i=void 0,j=void 0;while(i=(j=t.charAt(x++)).charCodeAt(0)){var m=i==46||i>=48&&i<=57;if(m!==n){tz[++y]="";n=m}tz[y]+=j}return tz}var aa=chunkify(a.toLowerCase());var bb=chunkify(b.toLowerCase());for(var x=0;aa[x]&&bb[x];x++){if(aa[x]!==bb[x]){var c=Number(aa[x]),d=Number(bb[x]);if(c==aa[x]&&d==bb[x]){return c-d}else{return aa[x]>bb[x]?1:-1}}}return aa.length-bb.length}function consolidateData(raw){var _this=this;var config=this.config;var all_data=[];var all_x=[];var all_y=[];this.setDefaults();this.filtered_data=raw;if(this.filters.length){this.filters.forEach(function(e){_this.filtered_data=_this.filtered_data.filter(function(d){return e.val==="All"?d:e.val instanceof Array?e.val.indexOf(d[e.col])>-1:d[e.col]===e.val})})}config.marks.forEach(function(e,i){if(e.type!=="bar"){e.arrange=null;e.split=null}var mark_info=e.per?_this.transformData(raw,e):{data:[],x_dom:[],y_dom:[]};all_data.push(mark_info.data);all_x.push(mark_info.x_dom);all_y.push(mark_info.y_dom);_this.marks[i]={id:e.id,type:e.type,per:e.per,data:mark_info.data,split:e.split,text:e.text,arrange:e.arrange,order:e.order,summarizeX:e.summarizeX,summarizeY:e.summarizeY,tooltip:e.tooltip,radius:e.radius,attributes:e.attributes,values:e.values}});if(config.x.type==="ordinal"){if(config.x.domain){this.x_dom=config.x.domain}else if(config.x.order){this.x_dom=d3.set(d3.merge(all_x)).values().sort(function(a,b){return d3.ascending(config.x.order.indexOf(a),config.x.order.indexOf(b))})}else if(config.x.sort&&config.x.sort==="alphabetical-ascending"){this.x_dom=d3.set(d3.merge(all_x)).values().sort(naturalSorter)}else if(config.y.type==="time"&&config.x.sort==="earliest"){this.x_dom=d3.nest().key(function(d){return d[config.x.column]}).rollup(function(d){return d.map(function(m){return m[config.y.column]}).filter(function(f){return f instanceof Date})}).entries(this.raw_data).sort(function(a,b){return d3.min(b.values)-d3.min(a.values)}).map(function(m){return m.key})}else if(!config.x.sort||config.x.sort==="alphabetical-descending"){this.x_dom=d3.set(d3.merge(all_x)).values().sort(naturalSorter)}else{this.x_dom=d3.set(d3.merge(all_x)).values()}}else if(config.marks.map(function(m){return m.summarizeX==="percent"}).indexOf(true)>-1){this.x_dom=[0,1]}else{this.x_dom=d3.extent(d3.merge(all_x))}if(config.y.type==="ordinal"){if(config.y.domain){this.y_dom=config.y.domain}else if(config.y.order){this.y_dom=d3.set(d3.merge(all_y)).values().sort(function(a,b){return d3.ascending(config.y.order.indexOf(a),config.y.order.indexOf(b))})}else if(config.y.sort&&config.y.sort==="alphabetical-ascending"){this.y_dom=d3.set(d3.merge(all_y)).values().sort(naturalSorter)}else if(config.x.type==="time"&&config.y.sort==="earliest"){this.y_dom=d3.nest().key(function(d){return d[config.y.column]}).rollup(function(d){return d.map(function(m){return m[config.x.column]}).filter(function(f){return f instanceof Date})}).entries(this.raw_data).sort(function(a,b){return d3.min(b.values)-d3.min(a.values)}).map(function(m){return m.key})}else if(!config.y.sort||config.y.sort==="alphabetical-descending"){this.y_dom=d3.set(d3.merge(all_y)).values().sort(naturalSorter).reverse()}else{this.y_dom=d3.set(d3.merge(all_y)).values()}}else if(config.marks.map(function(m){return m.summarizeY==="percent"}).indexOf(true)>-1){this.y_dom=[0,1]}else{this.y_dom=d3.extent(d3.merge(all_y))}}function destroy(){var destroyControls=arguments.length>0&&arguments[0]!==undefined?arguments[0]:true;this.events.onDestroy.call(this);var context=this;d3.select(window).on("resize."+context.element+context.id,null);if(destroyControls&&this.controls){this.controls.destroy()}this.wrap.remove()}function draw(raw_data,processed_data){var _this=this;var context=this;var config=this.config;var aspect2=1/config.aspect;this.events.onPreprocess.call(this);var raw=raw_data?raw_data:this.raw_data?this.raw_data:[];if(processed_data){console.warn("Drawing the chart using user-defined 'processed_data', this is an experimental, untested feature.")}var data=processed_data||this.consolidateData(raw);var div_width=parseInt(this.wrap.style("width"));this.setColorScale();var max_width=config.max_width?config.max_width:div_width;this.raw_width=config.x.type==="ordinal"&&+config.range_band?(+config.range_band+config.range_band*config.padding)*this.x_dom.length:config.resizable?max_width:config.width?config.width:div_width;this.raw_height=config.y.type==="ordinal"&&+config.range_band?(+config.range_band+config.range_band*config.padding)*this.y_dom.length:config.resizable?max_width*aspect2:config.height?config.height:div_width*aspect2;var pseudo_width=this.svg.select(".overlay").attr("width")?this.svg.select(".overlay").attr("width"):this.raw_width;var pseudo_height=this.svg.select(".overlay").attr("height")?this.svg.select(".overlay").attr("height"):this.raw_height;this.svg.select(".x.axis").select(".axis-title").text(function(d){return typeof config.x.label==="string"?config.x.label:typeof config.x.label==="function"?config.x.label.call(_this):null});this.svg.select(".y.axis").select(".axis-title").text(function(d){return typeof config.y.label==="string"?config.y.label:typeof config.y.label==="function"?config.y.label.call(_this):null});this.xScaleAxis(pseudo_width);this.yScaleAxis(pseudo_height);if(config.resizable&&typeof window!=="undefined"){d3.select(window).on("resize."+context.element+context.id,function(){context.resize()})}else if(typeof window!=="undefined"){d3.select(window).on("resize."+context.element+context.id,null)}this.events.onDraw.call(this);this.resize()}function drawArea(area_drawer,area_data,datum_accessor){var class_match=arguments.length>3&&arguments[3]!==undefined?arguments[3]:"chart-area";var _this=this;var bind_accessor=arguments[4];var attr_accessor=arguments.length>5&&arguments[5]!==undefined?arguments[5]:function(d){return d};var area_grps=this.svg.selectAll("."+class_match).data(area_data,bind_accessor);area_grps.exit().remove();area_grps.enter().append("g").attr("class",function(d){return class_match+" "+d.key}).append("path");var areaPaths=area_grps.select("path").datum(datum_accessor).attr("fill",function(d){var d_attr=attr_accessor(d);return d_attr?_this.colorScale(d_attr[_this.config.color_by]):null}).attr("fill-opacity",this.config.fill_opacity||this.config.fill_opacity===0?this.config.fill_opacity:.3);var areaPathTransitions=this.config.transitions?areaPaths.transition():areaPaths;areaPathTransitions.attr("d",area_drawer);return area_grps}function drawBars(marks){var _this=this;var rawData=this.raw_data;var config=this.config;var bar_supergroups=this.svg.selectAll(".bar-supergroup").data(marks,function(d,i){return i+"-"+d.per.join("-")});bar_supergroups.enter().append("g").attr("class",function(d){return"supergroup bar-supergroup "+d.id});bar_supergroups.exit().remove();var bar_groups=bar_supergroups.selectAll(".bar-group").data(function(d){return d.data},function(d){return d.key});var old_bar_groups=bar_groups.exit();var nu_bar_groups=void 0;var bars=void 0;var oldBarsTrans=config.transitions?old_bar_groups.selectAll(".bar").transition():old_bar_groups.selectAll(".bar");var oldBarGroupsTrans=config.transitions?old_bar_groups.transition():old_bar_groups;if(config.x.type==="ordinal"){oldBarsTrans.attr("y",this.y(0)).attr("height",0);oldBarGroupsTrans.remove();nu_bar_groups=bar_groups.enter().append("g").attr("class",function(d){return"bar-group "+d.key});nu_bar_groups.append("title");bars=bar_groups.selectAll("rect").data(function(d){return d.values instanceof Array?d.values.sort(function(a,b){return _this.colorScale.domain().indexOf(b.key)-_this.colorScale.domain().indexOf(a.key)}):[d]},function(d){return d.key});var exitBars=config.transitions?bars.exit().transition():bars.exit();exitBars.attr("y",this.y(0)).attr("height",0).remove();bars.enter().append("rect").attr("class",function(d){return"wc-data-mark bar "+d.key}).style("clip-path","url(#"+this.id+")").attr("y",this.y(0)).attr("height",0).append("title");bars.attr("shape-rendering","crispEdges").attr("stroke",function(d){return _this.colorScale(d.values.raw[0][config.color_by])}).attr("fill",function(d){return _this.colorScale(d.values.raw[0][config.color_by])});bars.each(function(d){var mark=d3.select(this.parentNode.parentNode).datum();d.tooltip=mark.tooltip;d.arrange=mark.split?mark.arrange:null;d.subcats=config.legend.order?config.legend.order.slice().reverse():mark.values&&mark.values[mark.split]?mark.values[mark.split]:d3.set(rawData.map(function(m){return m[mark.split]})).values();d3.select(this).attr(mark.attributes)});var xformat=config.marks.map(function(m){return m.summarizeX==="percent"}).indexOf(true)>-1?d3.format("0%"):d3.format(config.x.format);var yformat=config.marks.map(function(m){return m.summarizeY==="percent"}).indexOf(true)>-1?d3.format("0%"):d3.format(config.y.format);bars.select("title").text(function(d){var tt=d.tooltip||"";return tt.replace(/\$x/g,xformat(d.values.x)).replace(/\$y/g,yformat(d.values.y)).replace(/\[(.+?)\]/g,function(str,orig){return d.values.raw[0][orig]})});var barsTrans=config.transitions?bars.transition():bars;barsTrans.attr("x",function(d){var position=void 0;if(!d.arrange||d.arrange==="stacked"){return _this.x(d.values.x)}else if(d.arrange==="nested"){var _position=d.subcats.indexOf(d.key);var offset=_position?_this.x.rangeBand()/(d.subcats.length*.75)/_position:_this.x.rangeBand();return _this.x(d.values.x)+(_this.x.rangeBand()-offset)/2}else{position=d.subcats.indexOf(d.key);return _this.x(d.values.x)+_this.x.rangeBand()/d.subcats.length*position}}).attr("y",function(d){if(d.arrange!=="stacked"){return _this.y(d.values.y)}else{return _this.y(d.values.start)}}).attr("width",function(d){if(!d.arrange||d.arrange==="stacked"){return _this.x.rangeBand()}else if(d.arrange==="nested"){var position=d.subcats.indexOf(d.key);return position?_this.x.rangeBand()/(d.subcats.length*.75)/position:_this.x.rangeBand()}else{return _this.x.rangeBand()/d.subcats.length}}).attr("height",function(d){return _this.y(0)-_this.y(d.values.y)})}else if(config.y.type==="ordinal"){oldBarsTrans.attr("x",this.x(0)).attr("width",0);oldBarGroupsTrans.remove();nu_bar_groups=bar_groups.enter().append("g").attr("class",function(d){return"bar-group "+d.key});nu_bar_groups.append("title");bars=bar_groups.selectAll("rect").data(function(d){return d.values instanceof Array?d.values.sort(function(a,b){return _this.colorScale.domain().indexOf(b.key)-_this.colorScale.domain().indexOf(a.key)}):[d]},function(d){return d.key});var _exitBars=config.transitions?bars.exit().transition():bars.exit();_exitBars.attr("x",this.x(0)).attr("width",0).remove();bars.enter().append("rect").attr("class",function(d){return"wc-data-mark bar "+d.key}).style("clip-path","url(#"+this.id+")").attr("x",this.x(0)).attr("width",0).append("title");bars.attr("shape-rendering","crispEdges").attr("stroke",function(d){return _this.colorScale(d.values.raw[0][config.color_by])}).attr("fill",function(d){return _this.colorScale(d.values.raw[0][config.color_by])});bars.each(function(d){var mark=d3.select(this.parentNode.parentNode).datum();d.arrange=mark.split&&mark.arrange?mark.arrange:mark.split?"grouped":null;d.subcats=config.legend.order?config.legend.order.slice().reverse():mark.values&&mark.values[mark.split]?mark.values[mark.split]:d3.set(rawData.map(function(m){return m[mark.split]})).values();d.tooltip=mark.tooltip});var _xformat=config.marks.map(function(m){return m.summarizeX==="percent"}).indexOf(true)>-1?d3.format("0%"):d3.format(config.x.format);var _yformat=config.marks.map(function(m){return m.summarizeY==="percent"}).indexOf(true)>-1?d3.format("0%"):d3.format(config.y.format);bars.select("title").text(function(d){var tt=d.tooltip||"";return tt.replace(/\$x/g,_xformat(d.values.x)).replace(/\$y/g,_yformat(d.values.y)).replace(/\[(.+?)\]/g,function(str,orig){return d.values.raw[0][orig]})});var _barsTrans=config.transitions?bars.transition():bars;_barsTrans.attr("x",function(d){if(d.arrange==="stacked"||!d.arrange){return d.values.start!==undefined?_this.x(d.values.start):_this.x(0)}else{return _this.x(0)}}).attr("y",function(d){if(d.arrange==="nested"){var position=d.subcats.indexOf(d.key);var offset=position?_this.y.rangeBand()/(d.subcats.length*.75)/position:_this.y.rangeBand();return _this.y(d.values.y)+(_this.y.rangeBand()-offset)/2}else if(d.arrange==="grouped"){var _position2=d.subcats.indexOf(d.key);return _this.y(d.values.y)+_this.y.rangeBand()/d.subcats.length*_position2}else{return _this.y(d.values.y)}}).attr("width",function(d){return _this.x(d.values.x)-_this.x(0)}).attr("height",function(d){if(config.y.type==="quantile"){return 20}else if(d.arrange==="nested"){var position=d.subcats.indexOf(d.key);return position?_this.y.rangeBand()/(d.subcats.length*.75)/position:_this.y.rangeBand()}else if(d.arrange==="grouped"){return _this.y.rangeBand()/d.subcats.length}else{return _this.y.rangeBand()}})}else if(["linear","log"].indexOf(config.x.type)>-1&&config.x.bin){oldBarsTrans.attr("y",this.y(0)).attr("height",0);oldBarGroupsTrans.remove();nu_bar_groups=bar_groups.enter().append("g").attr("class",function(d){return"bar-group "+d.key});nu_bar_groups.append("title");bars=bar_groups.selectAll("rect").data(function(d){return d.values instanceof Array?d.values:[d]},function(d){return d.key});var _exitBars2=config.transitions?bars.exit().transition():bars.exit();_exitBars2.attr("y",this.y(0)).attr("height",0).remove();bars.enter().append("rect").attr("class",function(d){return"wc-data-mark bar "+d.key}).style("clip-path","url(#"+this.id+")").attr("y",this.y(0)).attr("height",0).append("title");bars.attr("shape-rendering","crispEdges").attr("stroke",function(d){return _this.colorScale(d.values.raw[0][config.color_by])}).attr("fill",function(d){return _this.colorScale(d.values.raw[0][config.color_by])});bars.each(function(d){var mark=d3.select(this.parentNode.parentNode).datum();d.arrange=mark.split?mark.arrange:null;d.subcats=config.legend.order?config.legend.order.slice().reverse():mark.values&&mark.values[mark.split]?mark.values[mark.split]:d3.set(rawData.map(function(m){return m[mark.split]})).values();d3.select(this).attr(mark.attributes);var parent=d3.select(this.parentNode).datum();var rangeSet=parent.key.split(",").map(function(m){return+m});d.rangeLow=d3.min(rangeSet);d.rangeHigh=d3.max(rangeSet);d.tooltip=mark.tooltip});var _xformat2=config.marks.map(function(m){return m.summarizeX==="percent"}).indexOf(true)>-1?d3.format("0%"):d3.format(config.x.format);var _yformat2=config.marks.map(function(m){return m.summarizeY==="percent"}).indexOf(true)>-1?d3.format("0%"):d3.format(config.y.format);bars.select("title").text(function(d){var tt=d.tooltip||"";return tt.replace(/\$x/g,_xformat2(d.values.x)).replace(/\$y/g,_yformat2(d.values.y)).replace(/\[(.+?)\]/g,function(str,orig){return d.values.raw[0][orig]})});var _barsTrans2=config.transitions?bars.transition():bars;_barsTrans2.attr("x",function(d){return _this.x(d.rangeLow)}).attr("y",function(d){if(d.arrange!=="stacked"){return _this.y(d.values.y)}else{return _this.y(d.values.start)}}).attr("width",function(d){return _this.x(d.rangeHigh)-_this.x(d.rangeLow)}).attr("height",function(d){return _this.y(0)-_this.y(d.values.y)})}else if(["linear","log"].indexOf(config.y.type)>-1&&config.y.type==="linear"&&config.y.bin){oldBarsTrans.attr("x",this.x(0)).attr("width",0);oldBarGroupsTrans.remove();nu_bar_groups=bar_groups.enter().append("g").attr("class",function(d){return"bar-group "+d.key});nu_bar_groups.append("title");bars=bar_groups.selectAll("rect").data(function(d){return d.values instanceof Array?d.values:[d]},function(d){return d.key});var _exitBars3=config.transitions?bars.exit().transition():bars.exit();_exitBars3.attr("x",this.x(0)).attr("width",0).remove();bars.enter().append("rect").attr("class",function(d){return"wc-data-mark bar "+d.key}).style("clip-path","url(#"+this.id+")").attr("x",this.x(0)).attr("width",0).append("title");bars.attr("shape-rendering","crispEdges").attr("stroke",function(d){return _this.colorScale(d.values.raw[0][config.color_by])}).attr("fill",function(d){return _this.colorScale(d.values.raw[0][config.color_by])});bars.each(function(d){var mark=d3.select(this.parentNode.parentNode).datum();d.arrange=mark.split?mark.arrange:null;d.subcats=config.legend.order?config.legend.order.slice().reverse():mark.values&&mark.values[mark.split]?mark.values[mark.split]:d3.set(rawData.map(function(m){return m[mark.split]})).values();var parent=d3.select(this.parentNode).datum();var rangeSet=parent.key.split(",").map(function(m){return+m});d.rangeLow=d3.min(rangeSet);d.rangeHigh=d3.max(rangeSet);d.tooltip=mark.tooltip});var _xformat3=config.marks.map(function(m){return m.summarizeX==="percent"}).indexOf(true)>-1?d3.format("0%"):d3.format(config.x.format);var _yformat3=config.marks.map(function(m){return m.summarizeY==="percent"}).indexOf(true)>-1?d3.format("0%"):d3.format(config.y.format);bars.select("title").text(function(d){var tt=d.tooltip||"";return tt.replace(/\$x/g,_xformat3(d.values.x)).replace(/\$y/g,_yformat3(d.values.y)).replace(/\[(.+?)\]/g,function(str,orig){return d.values.raw[0][orig]})});var _barsTrans3=config.transitions?bars.transition():bars;_barsTrans3.attr("x",function(d){if(d.arrange==="stacked"){return _this.x(d.values.start)}else{return _this.x(0)}}).attr("y",function(d){return _this.y(d.rangeHigh)}).attr("width",function(d){return _this.x(d.values.x)}).attr("height",function(d){return _this.y(d.rangeLow)-_this.y(d.rangeHigh)})}else{oldBarsTrans.attr("y",this.y(0)).attr("height",0);oldBarGroupsTrans.remove();bar_supergroups.remove()}bar_supergroups.each(function(d){d.supergroup=d3.select(this);d.groups=d.supergroup.selectAll(".bar-group")})}function drawGridLines(){this.wrap.classed("gridlines",this.config.gridlines);if(this.config.gridlines){this.svg.select(".y.axis").selectAll(".tick line").attr("x1",0);this.svg.select(".x.axis").selectAll(".tick line").attr("y1",0);if(this.config.gridlines==="y"||this.config.gridlines==="xy")this.svg.select(".y.axis").selectAll(".tick line").attr("x1",this.plot_width);if(this.config.gridlines==="x"||this.config.gridlines==="xy")this.svg.select(".x.axis").selectAll(".tick line").attr("y1",-this.plot_height)}else{this.svg.select(".y.axis").selectAll(".tick line").attr("x1",0);this.svg.select(".x.axis").selectAll(".tick line").attr("y1",0)}}function drawLines(marks){var _this=this;var config=this.config;var line=d3.svg.line().interpolate(config.interpolate).x(function(d){return config.x.type==="linear"||config.x.type=="log"?_this.x(+d.values.x):config.x.type==="time"?_this.x(new Date(d.values.x)):_this.x(d.values.x)+_this.x.rangeBand()/2}).y(function(d){return config.y.type==="linear"||config.y.type=="log"?_this.y(+d.values.y):config.y.type==="time"?_this.y(new Date(d.values.y)):_this.y(d.values.y)+_this.y.rangeBand()/2});var line_supergroups=this.svg.selectAll(".line-supergroup").data(marks,function(d,i){return i+"-"+d.per.join("-")});line_supergroups.enter().append("g").attr("class",function(d){return"supergroup line-supergroup "+d.id});line_supergroups.exit().remove();var line_grps=line_supergroups.selectAll(".line").data(function(d){return d.data},function(d){return d.key});line_grps.exit().remove();var nu_line_grps=line_grps.enter().append("g").attr("class",function(d){return d.key+" line"});nu_line_grps.append("path");nu_line_grps.append("title");var linePaths=line_grps.select("path").attr("class","wc-data-mark").datum(function(d){return d.values}).attr("stroke",function(d){return _this.colorScale(d[0].values.raw[0][config.color_by])}).attr("stroke-width",config.stroke_width?config.stroke_width:config.flex_stroke_width).attr("stroke-linecap","round").attr("fill","none");var linePathsTrans=config.transitions?linePaths.transition():linePaths;linePathsTrans.attr("d",line);line_grps.each(function(d){var mark=d3.select(this.parentNode).datum();d.tooltip=mark.tooltip;d3.select(this).select("path").attr(mark.attributes)});line_grps.select("title").text(function(d){var tt=d.tooltip||"";var xformat=config.x.summary==="percent"?d3.format("0%"):d3.format(config.x.format);var yformat=config.y.summary==="percent"?d3.format("0%"):d3.format(config.y.format);return tt.replace(/\$x/g,xformat(d.values.x)).replace(/\$y/g,yformat(d.values.y)).replace(/\[(.+?)\]/g,function(str,orig){return d.values[0].values.raw[0][orig]})});line_supergroups.each(function(d){d.supergroup=d3.select(this);d.groups=d.supergroup.selectAll("g.line");d.paths=d.groups.select("path")});return line_grps}function drawPoints(marks){var _this=this;var config=this.config;var point_supergroups=this.svg.selectAll(".point-supergroup").data(marks,function(d,i){return i+"-"+d.per.join("-")});point_supergroups.enter().append("g").attr("class",function(d){return"supergroup point-supergroup "+d.id});point_supergroups.exit().remove();var points=point_supergroups.selectAll(".point").data(function(d){return d.data},function(d){return d.key});var oldPoints=points.exit();var oldPointsTrans=config.transitions?oldPoints.selectAll("circle").transition():oldPoints.selectAll("circle");oldPointsTrans.attr("r",0);var oldPointGroupTrans=config.transitions?oldPoints.transition():oldPoints;oldPointGroupTrans.remove();var nupoints=points.enter().append("g").attr("class",function(d){return d.key+" point"});nupoints.append("circle").attr("class","wc-data-mark").attr("r",0);nupoints.append("title");points.select("circle").attr("fill-opacity",config.fill_opacity||config.fill_opacity===0?config.fill_opacity:.6).attr("fill",function(d){return _this.colorScale(d.values.raw[0][config.color_by])}).attr("stroke",function(d){return _this.colorScale(d.values.raw[0][config.color_by])});points.each(function(d){var mark=d3.select(this.parentNode).datum();d.mark=mark;d3.select(this).select("circle").attr(mark.attributes)});var pointsTrans=config.transitions?points.select("circle").transition():points.select("circle");pointsTrans.attr("r",function(d){return d.mark.radius||config.flex_point_size}).attr("cx",function(d){var x_pos=_this.x(d.values.x)||0;return config.x.type==="ordinal"?x_pos+_this.x.rangeBand()/2:x_pos}).attr("cy",function(d){var y_pos=_this.y(d.values.y)||0;return config.y.type==="ordinal"?y_pos+_this.y.rangeBand()/2:y_pos});points.select("title").text(function(d){var tt=d.mark.tooltip||"";var xformat=config.x.summary==="percent"?d3.format("0%"):config.x.type==="time"?d3.time.format(config.x.format):d3.format(config.x.format);var yformat=config.y.summary==="percent"?d3.format("0%"):config.y.type==="time"?d3.time.format(config.y.format):d3.format(config.y.format);return tt.replace(/\$x/g,config.x.type==="time"?xformat(new Date(d.values.x)):xformat(d.values.x)).replace(/\$y/g,config.y.type==="time"?yformat(new Date(d.values.y)):yformat(d.values.y)).replace(/\[(.+?)\]/g,function(str,orig){return d.values.raw[0][orig]})});point_supergroups.each(function(d){d.supergroup=d3.select(this);d.groups=d.supergroup.selectAll("g.point");d.circles=d.groups.select("circle")});return points}function drawText(marks){var _this=this;var config=this.config;var textSupergroups=this.svg.selectAll(".text-supergroup").data(marks,function(d,i){return i+"-"+d.per.join("-")});textSupergroups.enter().append("g").attr("class",function(d){return"supergroup text-supergroup "+d.id});textSupergroups.exit().remove();var texts=textSupergroups.selectAll(".text").data(function(d){return d.data},function(d){return d.key});var oldTexts=texts.exit();var oldTextGroupTrans=config.transitions?oldTexts.transition():oldTexts;oldTextGroupTrans.remove();var nutexts=texts.enter().append("g").attr("class",function(d){return d.key+" text"});nutexts.append("text").attr("class","wc-data-mark");function attachMarks(d){d.mark=d3.select(this.parentNode).datum();d3.select(this).select("text").attr(d.mark.attributes)}texts.each(attachMarks);texts.select("text").text(function(d){var tt=d.mark.text||"";var xformat=config.x.summary==="percent"?d3.format("0%"):config.x.type==="time"?d3.time.format(config.x.format):d3.format(config.x.format);var yformat=config.y.summary==="percent"?d3.format("0%"):config.y.type==="time"?d3.time.format(config.y.format):d3.format(config.y.format);return tt.replace(/\$x/g,config.x.type==="time"?xformat(new Date(d.values.x)):xformat(d.values.x)).replace(/\$y/g,config.y.type==="time"?yformat(new Date(d.values.y)):yformat(d.values.y)).replace(/\[(.+?)\]/g,function(str,orig){return d.values.raw[0][orig]})});var textsTrans=config.transitions?texts.select("text").transition():texts.select("text");textsTrans.attr("x",function(d){var xPos=_this.x(d.values.x)||0;return config.x.type==="ordinal"?xPos+_this.x.rangeBand()/2:xPos}).attr("y",function(d){var yPos=_this.y(d.values.y)||0;return config.y.type==="ordinal"?yPos+_this.y.rangeBand()/2:yPos});textSupergroups.each(function(d){d.supergroup=d3.select(this);d.groups=d.supergroup.selectAll("g.text");d.texts=d.groups.select("text")});return texts}function init(data){var _this=this;var test=arguments.length>1&&arguments[1]!==undefined?arguments[1]:false;if(d3.select(this.div).select(".loader").empty()){d3.select(this.div).insert("div",":first-child").attr("class","loader").selectAll(".blockG").data(d3.range(8)).enter().append("div").attr("class",function(d){return"blockG rotate"+(d+1)})}this.wrap.attr("class","wc-chart");this.setDefaults();this.raw_data=data;this.initial_data=data;var startup=function startup(data){if(_this.controls){_this.controls.targets.push(_this);if(!_this.controls.ready){_this.controls.init(_this.raw_data)}else{_this.controls.layout()}}var visible=d3.select(_this.div).property("offsetWidth")>0||test;if(!visible){console.warn("The chart cannot be initialized inside an element with 0 width. The chart will be initialized as soon as the container element is given a width > 0.");var onVisible=setInterval(function(i){var visible_now=d3.select(_this.div).property("offsetWidth")>0;if(visible_now){_this.layout();_this.draw();clearInterval(onVisible)}},500)}else{_this.layout();_this.draw()}};this.events.onInit.call(this);if(this.raw_data.length){this.checkRequired(this.raw_data)}startup(data);return this}function layout(){this.svg=this.wrap.append("svg").attr({class:"wc-svg",xmlns:"http://www.w3.org/2000/svg",version:"1.1",xlink:"http://www.w3.org/1999/xlink"}).append("g").style("display","inline-block");var defs=this.svg.append("defs");defs.append("pattern").attr({id:"diagonal-stripes",x:0,y:0,width:3,height:8,patternUnits:"userSpaceOnUse",patternTransform:"rotate(30)"}).append("rect").attr({x:"0",y:"0",width:"2",height:"8",style:"stroke:none; fill:black"});defs.append("clipPath").attr("id",this.id).append("rect").attr("class","plotting-area");this.svg.append("g").attr("class","y axis").append("text").attr("class","axis-title").attr("transform","rotate(-90)").attr("dy",".75em").attr("text-anchor","middle");this.svg.append("g").attr("class","x axis").append("text").attr("class","axis-title").attr("dy","-.35em").attr("text-anchor","middle");this.svg.append("rect").attr("class","overlay").attr("opacity",0).attr("fill","none").style("pointer-events","all");var legend=this.wrap.append("ul");legend.attr("class","legend").style("vertical-align","top").append("span").attr("class","legend-title");d3.select(this.div).select(".loader").remove();this.events.onLayout.call(this)}function makeLegend(){var scale$$1=arguments.length>0&&arguments[0]!==undefined?arguments[0]:this.colorScale;var label=arguments.length>1&&arguments[1]!==undefined?arguments[1]:"";var custom_data=arguments.length>2&&arguments[2]!==undefined?arguments[2]:null;var config=this.config;config.legend.mark=config.legend.mark?config.legend.mark:config.marks.length&&config.marks[0].type==="bar"?"square":config.marks.length?config.marks[0].type:"square";var legend_label=label?label:typeof config.legend.label==="string"?config.legend.label:"";var legendOriginal=this.legend||this.wrap.select(".legend");var legend=legendOriginal;if(this.config.legend.location==="top"||this.config.legend.location==="left"){this.wrap.node().insertBefore(legendOriginal.node(),this.svg.node().parentNode)}else{this.wrap.node().appendChild(legendOriginal.node())}legend.style("padding",0);var legend_data=custom_data||scale$$1.domain().slice(0).filter(function(f){return f!==undefined&&f!==null}).map(function(m){return{label:m,mark:config.legend.mark}});legend.select(".legend-title").text(legend_label).style("display",legend_label?"inline":"none").style("margin-right","1em");var leg_parts=legend.selectAll(".legend-item").data(legend_data,function(d){return d.label+d.mark});leg_parts.exit().remove();var legendPartDisplay=this.config.legend.location==="bottom"||this.config.legend.location==="top"?"inline-block":"block";var new_parts=leg_parts.enter().append("li").attr("class","legend-item").style({"list-style-type":"none","margin-right":"1em"});new_parts.append("span").attr("class","legend-mark-text").style("color",function(d){return scale$$1(d.label)});new_parts.append("svg").attr("class","legend-color-block").attr("width","1.1em").attr("height","1.1em").style({position:"relative",top:"0.2em"});leg_parts.style("display",legendPartDisplay);if(config.legend.order){leg_parts.sort(function(a,b){return d3.ascending(config.legend.order.indexOf(a.label),config.legend.order.indexOf(b.label))})}leg_parts.selectAll(".legend-color-block").select(".legend-mark").remove();leg_parts.selectAll(".legend-color-block").each(function(e){var svg$$1=d3.select(this);if(e.mark==="circle"){svg$$1.append("circle").attr({cx:".5em",cy:".45em",r:".45em",class:"legend-mark"})}else if(e.mark==="line"){svg$$1.append("line").attr({x1:0,y1:".5em",x2:"1em",y2:".5em","stroke-width":2,"shape-rendering":"crispEdges",class:"legend-mark"})}else if(e.mark==="square"){svg$$1.append("rect").attr({height:"1em",width:"1em",class:"legend-mark","shape-rendering":"crispEdges"})}});leg_parts.selectAll(".legend-color-block").select(".legend-mark").attr("fill",function(d){return d.color||scale$$1(d.label)}).attr("stroke",function(d){return d.color||scale$$1(d.label)}).each(function(e){d3.select(this).attr(e.attributes)}) +;new_parts.append("span").attr("class","legend-label").style("margin-left","0.25em").text(function(d){return d.label});if(scale$$1.domain().length>0){var legendDisplay=this.config.legend.location==="bottom"||this.config.legend.location==="top"?"block":"inline-block";legend.style("display",legendDisplay)}else{legend.style("display","none")}this.legend=legend}function resize(){var config=this.config;var aspect2=1/config.aspect;var div_width=parseInt(this.wrap.style("width"));var max_width=config.max_width?config.max_width:div_width;var preWidth=!config.resizable?config.width:!max_width||div_width-1){max_y_text_length+=1}max_y_text_length=Math.max(2,max_y_text_length);var x_label_on=this.config.x.label?1.5:0;var y_label_on=this.config.y.label?1.5:.25;var font_size=parseInt(this.wrap.style("font-size"));var x_second=this.config.x2_interval?1:0;var y_margin=max_y_text_length*font_size*.5+font_size*y_label_on*1.5||8;var x_margin=font_size+font_size/1.5+font_size*x_label_on+font_size*x_second||8;y_margin+=6;x_margin+=3;return{top:this.config.margin&&this.config.margin.top?this.config.margin.top:8,right:this.config.margin&&this.config.margin.right?this.config.margin.right:16,bottom:this.config.margin&&this.config.margin.bottom?this.config.margin.bottom:x_margin,left:this.config.margin&&this.config.margin.left?this.config.margin.left:y_margin}}function textSize(width){var font_size="14px";var point_size=4;var stroke_width=2;if(!this.config.scale_text){font_size=this.config.font_size;point_size=this.config.point_size||4;stroke_width=this.config.stroke_width||2}else if(width>=600){font_size="14px";point_size=4;stroke_width=2}else if(width>450&&width<600){font_size="12px";point_size=3;stroke_width=2}else if(width>300&&width<450){font_size="10px";point_size=2;stroke_width=2}else if(width<=300){font_size="10px";point_size=2;stroke_width=1}this.wrap.style("font-size",font_size);this.config.flex_point_size=point_size;this.config.flex_stroke_width=stroke_width}var stats={mean:d3.mean,min:d3.min,max:d3.max,median:d3.median,sum:d3.sum};function summarize(vals){var operation=arguments.length>1&&arguments[1]!==undefined?arguments[1]:"mean";var nvals=vals.filter(function(f){return+f||+f===0}).map(function(m){return+m});if(operation==="cumulative"){return null}var mathed=operation==="count"?vals.length:operation==="percent"?vals.length:stats[operation](nvals);return mathed}function transformData(raw,mark){var _this=this;var config=this.config;var x_behavior=config.x.behavior||"raw";var y_behavior=config.y.behavior||"raw";var sublevel=mark.type==="line"?config.x.column:mark.type==="bar"&&mark.split?mark.split:null;var dateConvert=d3.time.format(config.date_format);var totalOrder=void 0;function calcStartTotal(e){var axis=config.x.type==="ordinal"||config.x.type==="linear"&&config.x.bin?"y":"x";e.total=d3.sum(e.values.map(function(m){return+m.values[axis]}));var counter=0;e.values.forEach(function(v,i){if(config.x.type==="ordinal"||config.x.type==="linear"&&config.x.bin){v.values.y=mark.summarizeY==="percent"?v.values.y/e.total:v.values.y||0;counter+=+v.values.y;v.values.start=e.values[i-1]?counter:v.values.y}else{v.values.x=mark.summarizeX==="percent"?v.values.x/e.total:v.values.x||0;v.values.start=counter;counter+=+v.values.x}})}function makeNest(entries,sublevel){var dom_xs=[];var dom_ys=[];var this_nest=d3.nest();if(config.x.type==="linear"&&config.x.bin||config.y.type==="linear"&&config.y.bin){var xy=config.x.type==="linear"&&config.x.bin?"x":"y";var quant=d3.scale.quantile().domain(d3.extent(entries.map(function(m){return+m[config[xy].column]}))).range(d3.range(+config[xy].bin));entries.forEach(function(e){return e.wc_bin=quant(e[config[xy].column])});this_nest.key(function(d){return quant.invertExtent(d.wc_bin)})}else{this_nest.key(function(d){return mark.per.map(function(m){return d[m]}).join(" ")})}if(sublevel){this_nest.key(function(d){return d[sublevel]});this_nest.sortKeys(function(a,b){return config.x.type==="time"?d3.ascending(new Date(a),new Date(b)):config.x.order?d3.ascending(config.x.order.indexOf(a),config.x.order.indexOf(b)):sublevel===config.color_by&&config.legend.order?d3.ascending(config.legend.order.indexOf(a),config.legend.order.indexOf(b)):config.x.type==="ordinal"||config.y.type==="ordinal"?naturalSorter(a,b):d3.ascending(+a,+b)})}this_nest.rollup(function(r){var obj={raw:r};var y_vals=r.map(function(m){return m[config.y.column]}).sort(d3.ascending);var x_vals=r.map(function(m){return m[config.x.column]}).sort(d3.ascending);obj.x=config.x.type==="ordinal"?r[0][config.x.column]:summarize(x_vals,mark.summarizeX);obj.y=config.y.type==="ordinal"?r[0][config.y.column]:summarize(y_vals,mark.summarizeY);obj.x_q25=config.error_bars&&config.y.type==="ordinal"?d3.quantile(x_vals,.25):obj.x;obj.x_q75=config.error_bars&&config.y.type==="ordinal"?d3.quantile(x_vals,.75):obj.x;obj.y_q25=config.error_bars?d3.quantile(y_vals,.25):obj.y;obj.y_q75=config.error_bars?d3.quantile(y_vals,.75):obj.y;dom_xs.push([obj.x_q25,obj.x_q75,obj.x]);dom_ys.push([obj.y_q25,obj.y_q75,obj.y]);if(mark.summarizeY==="cumulative"){var interm=entries.filter(function(f){return config.x.type==="time"?new Date(f[config.x.column])<=new Date(r[0][config.x.column]):+f[config.x.column]<=+r[0][config.x.column]});if(mark.per.length){interm=interm.filter(function(f){return f[mark.per[0]]===r[0][mark.per[0]]})}var cumul=config.x.type==="time"?interm.length:d3.sum(interm.map(function(m){return+m[config.y.column]||+m[config.y.column]===0?+m[config.y.column]:1}));dom_ys.push([cumul]);obj.y=cumul}if(mark.summarizeX==="cumulative"){var _interm=entries.filter(function(f){return config.y.type==="time"?new Date(f[config.y.column])<=new Date(r[0][config.y.column]):+f[config.y.column]<=+r[0][config.y.column]});if(mark.per.length){_interm=_interm.filter(function(f){return f[mark.per[0]]===r[0][mark.per[0]]})}dom_xs.push([_interm.length]);obj.x=_interm.length}return obj});var test=this_nest.entries(entries);var dom_x=d3.extent(d3.merge(dom_xs));var dom_y=d3.extent(d3.merge(dom_ys));if(sublevel&&mark.type==="bar"&&mark.arrange==="stacked"){test.forEach(calcStartTotal);if(config.x.type==="ordinal"||config.x.type==="linear"&&config.x.bin){dom_y=d3.extent(test.map(function(m){return m.total}))}if(config.y.type==="ordinal"||config.y.type==="linear"&&config.y.bin){dom_x=d3.extent(test.map(function(m){return m.total}))}}else if(sublevel&&mark.type==="bar"&&mark.split){test.forEach(calcStartTotal)}else{var axis=config.x.type==="ordinal"||config.x.type==="linear"&&config.x.bin?"y":"x";test.forEach(function(e){return e.total=e.values[axis]})}if(config.x.sort==="total-ascending"&&config.x.type=="ordinal"||config.y.sort==="total-descending"&&config.y.type=="ordinal"){totalOrder=test.sort(function(a,b){return d3.ascending(a.total,b.total)}).map(function(m){return m.key})}else if(config.x.sort==="total-descending"&&config.x.type=="ordinal"||config.y.sort==="total-ascending"&&config.y.type=="ordinal"){totalOrder=test.sort(function(a,b){return d3.descending(+a.total,+b.total)}).map(function(m){return m.key})}return{nested:test,dom_x:dom_x,dom_y:dom_y}}raw=mark.per&&mark.per.length?raw.filter(function(f){return f[mark.per[0]]}):raw;if(config.x.column){raw=raw.filter(function(f){return f[config.x.column]!==undefined})}if(config.y.column){raw=raw.filter(function(f){return f[config.y.column]!==undefined})}if(config.x.type==="time"){raw=raw.filter(function(f){return f[config.x.column]instanceof Date?f[config.x.column]:dateConvert.parse(f[config.x.column])});raw.forEach(function(e){return e[config.x.column]=e[config.x.column]instanceof Date?e[config.x.column]:dateConvert.parse(e[config.x.column])})}if(config.y.type==="time"){raw=raw.filter(function(f){return f[config.y.column]instanceof Date?f[config.y.column]:dateConvert.parse(f[config.y.column])});raw.forEach(function(e){return e[config.y.column]=e[config.y.column]instanceof Date?e[config.y.column]:dateConvert.parse(e[config.y.column])})}if((config.x.type==="linear"||config.x.type==="log")&&config.x.column){raw=raw.filter(function(f){return mark.summarizeX!=="count"&&mark.summarizeX!=="percent"?+f[config.x.column]||+f[config.x.column]===0:f})}if((config.y.type==="linear"||config.y.type==="log")&&config.y.column){raw=raw.filter(function(f){return mark.summarizeY!=="count"&&mark.summarizeY!=="percent"?+f[config.y.column]||+f[config.y.column]===0:f})}var raw_nest=void 0;if(mark.type==="bar"){raw_nest=mark.arrange!=="stacked"?makeNest(raw,sublevel):makeNest(raw)}else if(mark.summarizeX==="count"||mark.summarizeY==="count"){raw_nest=makeNest(raw)}var raw_dom_x=mark.summarizeX==="cumulative"?[0,raw.length]:config.x.type==="ordinal"?d3.set(raw.map(function(m){return m[config.x.column]})).values().filter(function(f){return f}):mark.split&&mark.arrange!=="stacked"?d3.extent(d3.merge(raw_nest.nested.map(function(m){return m.values.map(function(p){return p.values.raw.length})}))):mark.summarizeX==="count"?d3.extent(raw_nest.nested.map(function(m){return m.values.raw.length})):d3.extent(raw.map(function(m){return+m[config.x.column]}).filter(function(f){return+f||+f===0}));var raw_dom_y=mark.summarizeY==="cumulative"?[0,raw.length]:config.y.type==="ordinal"?d3.set(raw.map(function(m){return m[config.y.column]})).values().filter(function(f){return f}):mark.split&&mark.arrange!=="stacked"?d3.extent(d3.merge(raw_nest.nested.map(function(m){return m.values.map(function(p){return p.values.raw.length})}))):mark.summarizeY==="count"?d3.extent(raw_nest.nested.map(function(m){return m.values.raw.length})):d3.extent(raw.map(function(m){return+m[config.y.column]}).filter(function(f){return+f||+f===0}));var filtered=raw;var filt1_xs=[];var filt1_ys=[];if(this.filters.length){this.filters.forEach(function(e){filtered=filtered.filter(function(d){return e.val==="All"?d:e.val instanceof Array?e.val.indexOf(d[e.col])>-1:d[e.col]===e.val})});if(config.x.behavior==="firstfilter"||config.y.behavior==="firstfilter"){this.filters[0].choices.filter(function(f){return f!=="All"}).forEach(function(e){var perfilter=raw.filter(function(f){return f[_this.filters[0].col]===e});var filt_nested=makeNest(perfilter,sublevel);filt1_xs.push(filt_nested.dom_x);filt1_ys.push(filt_nested.dom_y)})}}if(mark.values){var _loop=function _loop(a){filtered=filtered.filter(function(f){return mark.values[a].indexOf(f[a])>-1})};for(var a in mark.values){_loop(a)}}var filt1_dom_x=d3.extent(d3.merge(filt1_xs));var filt1_dom_y=d3.extent(d3.merge(filt1_ys));var current_nested=makeNest(filtered,sublevel);var flex_dom_x=current_nested.dom_x;var flex_dom_y=current_nested.dom_y;if(mark.type==="bar"){if(config.y.type==="ordinal"&&mark.summarizeX==="count"){config.x.domain=config.x.domain?[0,config.x.domain[1]]:[0,null]}else if(config.x.type==="ordinal"&&mark.summarizeY==="count"){config.y.domain=config.y.domain?[0,config.y.domain[1]]:[0,null]}}var nonall=Boolean(this.filters.length&&this.filters[0].val!=="All"&&this.filters.slice(1).filter(function(f){return f.val==="All"}).length===this.filters.length-1);var pre_x_dom=!this.filters.length?flex_dom_x:x_behavior==="raw"?raw_dom_x:nonall&&x_behavior==="firstfilter"?filt1_dom_x:flex_dom_x;var pre_y_dom=!this.filters.length?flex_dom_y:y_behavior==="raw"?raw_dom_y:nonall&&y_behavior==="firstfilter"?filt1_dom_y:flex_dom_y;var x_dom=config.x_dom?config.x_dom:config.x.type==="ordinal"&&config.x.behavior==="flex"?d3.set(filtered.map(function(m){return m[config.x.column]})).values():config.x.type==="ordinal"?d3.set(raw.map(function(m){return m[config.x.column]})).values():config.x_from0?[0,d3.max(pre_x_dom)]:pre_x_dom;var y_dom=config.y_dom?config.y_dom:config.y.type==="ordinal"&&config.y.behavior==="flex"?d3.set(filtered.map(function(m){return m[config.y.column]})).values():config.y.type==="ordinal"?d3.set(raw.map(function(m){return m[config.y.column]})).values():config.y_from0?[0,d3.max(pre_y_dom)]:pre_y_dom;if(config.x.domain&&(config.x.domain[0]||config.x.domain[0]===0)){x_dom[0]=config.x.domain[0]}if(config.x.domain&&(config.x.domain[1]||config.x.domain[1]===0)){x_dom[1]=config.x.domain[1]}if(config.y.domain&&(config.y.domain[0]||config.y.domain[0]===0)){y_dom[0]=config.y.domain[0]}if(config.y.domain&&(config.y.domain[1]||config.y.domain[1]===0)){y_dom[1]=config.y.domain[1]}if(config.x.type==="ordinal"&&!config.x.order){config.x.order=totalOrder}if(config.y.type==="ordinal"&&!config.y.order){config.y.order=totalOrder}this.current_data=current_nested.nested;this.events.onDatatransform.call(this);return{config:mark,data:current_nested.nested,x_dom:x_dom,y_dom:y_dom}}function updateDataMarks(){this.drawBars(this.marks.filter(function(f){return f.type==="bar"}));this.drawLines(this.marks.filter(function(f){return f.type==="line"}));this.drawPoints(this.marks.filter(function(f){return f.type==="circle"}));this.drawText(this.marks.filter(function(f){return f.type==="text"}));this.marks.supergroups=this.svg.selectAll("g.supergroup")}function xScaleAxis(max_range,domain,type){if(max_range===undefined){max_range=this.plot_width}if(domain===undefined){domain=this.x_dom}if(type===undefined){type=this.config.x.type}var config=this.config;var x=void 0;if(type==="log"){x=d3.scale.log()}else if(type==="ordinal"){x=d3.scale.ordinal()}else if(type==="time"){x=d3.time.scale()}else{x=d3.scale.linear()}x.domain(domain);if(type==="ordinal"){x.rangeBands([0,+max_range],config.padding,config.outer_pad)}else{x.range([0,+max_range]).clamp(Boolean(config.x.clamp))}var xFormat=config.x.format?config.x.format:config.marks.map(function(m){return m.summarizeX==="percent"}).indexOf(true)>-1?"0%":type==="time"?"%x":".0f";var tick_count=Math.max(2,Math.min(max_range/80,8));var xAxis=d3.svg.axis().scale(x).orient(config.x.location).ticks(tick_count).tickFormat(type==="ordinal"?null:type==="time"?d3.time.format(xFormat):d3.format(xFormat)).tickValues(config.x.ticks?config.x.ticks:null).innerTickSize(6).outerTickSize(3);this.svg.select("g.x.axis").attr("class","x axis "+type);this.x=x;this.xAxis=xAxis}function yScaleAxis(max_range,domain,type){if(max_range===undefined){max_range=this.plot_height}if(domain===undefined){domain=this.y_dom}if(type===undefined){type=this.config.y.type}var config=this.config;var y=void 0;if(type==="log"){y=d3.scale.log()}else if(type==="ordinal"){y=d3.scale.ordinal()}else if(type==="time"){y=d3.time.scale()}else{y=d3.scale.linear()}y.domain(domain);if(type==="ordinal"){y.rangeBands([+max_range,0],config.padding,config.outer_pad)}else{y.range([+max_range,0]).clamp(Boolean(config.y_clamp))}var yFormat=config.y.format?config.y.format:config.marks.map(function(m){return m.summarizeY==="percent"}).indexOf(true)>-1?"0%":".0f";var tick_count=Math.max(2,Math.min(max_range/80,8));var yAxis=d3.svg.axis().scale(y).orient("left").ticks(tick_count).tickFormat(type==="ordinal"?null:type==="time"?d3.time.format(yFormat):d3.format(yFormat)).tickValues(config.y.ticks?config.y.ticks:null).innerTickSize(6).outerTickSize(3);this.svg.select("g.y.axis").attr("class","y axis "+type);this.y=y;this.yAxis=yAxis}var chartProto={raw_data:[],config:{}};var chart=Object.create(chartProto,{checkRequired:{value:checkRequired},consolidateData:{value:consolidateData},draw:{value:draw},destroy:{value:destroy},drawArea:{value:drawArea},drawBars:{value:drawBars},drawGridlines:{value:drawGridLines},drawLines:{value:drawLines},drawPoints:{value:drawPoints},drawText:{value:drawText},init:{value:init},layout:{value:layout},makeLegend:{value:makeLegend},resize:{value:resize},setColorScale:{value:setColorScale},setDefaults:{value:setDefaults},setMargins:{value:setMargins},textSize:{value:textSize},transformData:{value:transformData},updateDataMarks:{value:updateDataMarks},xScaleAxis:{value:xScaleAxis},yScaleAxis:{value:yScaleAxis}});var chartCount=0;function createChart(){var element=arguments.length>0&&arguments[0]!==undefined?arguments[0]:"body";var config=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};var controls=arguments.length>2&&arguments[2]!==undefined?arguments[2]:null;var thisChart=Object.create(chart);thisChart.div=element;thisChart.config=Object.create(config);thisChart.controls=controls;thisChart.raw_data=[];thisChart.filters=[];thisChart.marks=[];thisChart.wrap=d3.select(thisChart.div).append("div").datum(thisChart);thisChart.events={onInit:function onInit(){},onLayout:function onLayout(){},onPreprocess:function onPreprocess(){},onDatatransform:function onDatatransform(){},onDraw:function onDraw(){},onResize:function onResize(){},onDestroy:function onDestroy(){}};thisChart.on=function(event,callback){var possible_events=["init","layout","preprocess","datatransform","draw","resize","destroy"];if(possible_events.indexOf(event)<0){return}if(callback){thisChart.events["on"+event.charAt(0).toUpperCase()+event.slice(1)]=callback}};chartCount++;thisChart.id=chartCount;return thisChart}function changeOption(option,value,callback){var _this=this;this.targets.forEach(function(e){if(option instanceof Array){option.forEach(function(o){return _this.stringAccessor(e.config,o,value)})}else{_this.stringAccessor(e.config,option,value)}if(callback){callback()}e.draw()})}function checkRequired$1(dataset){if(!dataset[0]||!this.config.inputs){return}var colnames=d3.keys(dataset[0]);this.config.inputs.forEach(function(e,i){if(e.type==="subsetter"&&colnames.indexOf(e.value_col)===-1){throw new Error('Error in settings object: the value "'+e.value_col+'" does not match any column in the provided dataset.')}})}function controlUpdate(){var _this=this;if(this.config.inputs&&this.config.inputs.length&&this.config.inputs[0]){this.config.inputs.forEach(function(e){return _this.makeControlItem(e)})}}function destroy$1(){this.wrap.remove()}function init$1(data){this.data=data;if(!this.config.builder){this.checkRequired(this.data)}this.layout()}function layout$1(){this.wrap.selectAll("*").remove();this.ready=true;this.controlUpdate()}function makeControlItem(control){var control_wrap=this.wrap.append("div").attr("class","control-group").classed("inline",control.inline).datum(control);var ctrl_label=control_wrap.append("span").attr("class","control-label").text(control.label);if(control.required){ctrl_label.append("span").attr("class","label label-required").text("Required")}control_wrap.append("span").attr("class","span-description").text(control.description);if(control.type==="text"){this.makeTextControl(control,control_wrap)}else if(control.type==="number"){this.makeNumberControl(control,control_wrap)}else if(control.type==="list"){this.makeListControl(control,control_wrap)}else if(control.type==="dropdown"){this.makeDropdownControl(control,control_wrap)}else if(control.type==="btngroup"){this.makeBtnGroupControl(control,control_wrap)}else if(control.type==="checkbox"){this.makeCheckboxControl(control,control_wrap)}else if(control.type==="radio"){this.makeRadioControl(control,control_wrap)}else if(control.type==="subsetter"){this.makeSubsetterControl(control,control_wrap)}else{throw new Error('Each control must have a type! Choose from: "text", "number", "list", "dropdown", "btngroup", "checkbox", "radio", "subsetter"')}}function makeBtnGroupControl(control,control_wrap){var _this=this;var option_data=control.values?control.values:d3.keys(this.data[0]);var btn_wrap=control_wrap.append("div").attr("class","btn-group");var changers=btn_wrap.selectAll("button").data(option_data).enter().append("button").attr("class","btn btn-default btn-sm").text(function(d){return d}).classed("btn-primary",function(d){return _this.stringAccessor(_this.targets[0].config,control.option)===d});changers.on("click",function(d){changers.each(function(e){d3.select(this).classed("btn-primary",e===d)});_this.changeOption(control.option,d,control.callback)})}function makeCheckboxControl(control,control_wrap){var _this=this;var changer=control_wrap.append("input").attr("type","checkbox").attr("class","changer").datum(control).property("checked",function(d){return _this.stringAccessor(_this.targets[0].config,control.option)});changer.on("change",function(d){var value=changer.property("checked");_this.changeOption(d.option,value,control.callback)})}function makeDropdownControl(control,control_wrap){var _this=this;var mainOption=control.option||control.options[0];var changer=control_wrap.append("select").attr("class","changer").attr("multiple",control.multiple?true:null).datum(control);var opt_values=control.values&&control.values instanceof Array?control.values:control.values?d3.set(this.data.map(function(m){return m[_this.targets[0].config[control.values]]})).values():d3.keys(this.data[0]);if(!control.require||control.none){opt_values.unshift("None")}var options=changer.selectAll("option").data(opt_values).enter().append("option").text(function(d){return d}).property("selected",function(d){return _this.stringAccessor(_this.targets[0].config,mainOption)===d});changer.on("change",function(d){var value=changer.property("value")==="None"?null:changer.property("value");if(control.multiple){value=options.filter(function(f){return d3.select(this).property("selected")})[0].map(function(m){return d3.select(m).property("value")}).filter(function(f){return f!=="None"})}if(control.options){_this.changeOption(control.options,value,control.callback)}else{_this.changeOption(control.option,value,control.callback)}});return changer}function makeListControl(control,control_wrap){var _this=this;var changer=control_wrap.append("input").attr("type","text").attr("class","changer").datum(control).property("value",function(d){return _this.stringAccessor(_this.targets[0].config,control.option)});changer.on("change",function(d){var value=changer.property("value")?changer.property("value").split(",").map(function(m){return m.trim()}):null;_this.changeOption(control.option,value,control.callback)})}function makeNumberControl(control,control_wrap){var _this=this;var changer=control_wrap.append("input").attr("type","number").attr("min",control.min!==undefined?control.min:0).attr("max",control.max).attr("step",control.step||1).attr("class","changer").datum(control).property("value",function(d){return _this.stringAccessor(_this.targets[0].config,control.option)});changer.on("change",function(d){var value=+changer.property("value");_this.changeOption(control.option,value,control.callback)})}function makeRadioControl(control,control_wrap){var _this=this;var changers=control_wrap.selectAll("label").data(control.values||d3.keys(this.data[0])).enter().append("label").attr("class","radio").text(function(d,i){return control.relabels?control.relabels[i]:d}).append("input").attr("type","radio").attr("class","changer").attr("name",control.option.replace(".","-")+"-"+this.targets[0].id).property("value",function(d){return d}).property("checked",function(d){return _this.stringAccessor(_this.targets[0].config,control.option)===d});changers.on("change",function(d){var value=null;changers.each(function(c){if(d3.select(this).property("checked")){value=d3.select(this).property("value")==="none"?null:c}});_this.changeOption(control.option,value,control.callback)})}function makeSubsetterControl(control,control_wrap){var targets=this.targets;var changer=control_wrap.append("select").attr("class","changer").attr("multiple",control.multiple?true:null).datum(control);var option_data=control.values?control.values:d3.set(this.data.map(function(m){return m[control.value_col]}).filter(function(f){return f})).values();option_data.sort(naturalSorter);control.start=control.start?control.start:control.loose?option_data[0]:null;if(!control.multiple&&!control.start){option_data.unshift("All")}control.loose=!control.loose&&control.start?true:control.loose;var options=changer.selectAll("option").data(option_data).enter().append("option").text(function(d){return d}).property("selected",function(d){return d===control.start});targets.forEach(function(e){var match=e.filters.slice().map(function(m){return m.col===control.value_col}).indexOf(true);if(match>-1){e.filters[match]={col:control.value_col,val:control.start?control.start:"All",choices:option_data,loose:control.loose}}else{e.filters.push({col:control.value_col,val:control.start?control.start:"All",choices:option_data,loose:control.loose})}});function setSubsetter(target,obj){var match=-1;target.filters.forEach(function(e,i){if(e.col===obj.col){match=i}});if(match>-1){target.filters[match]=obj}}changer.on("change",function(d){if(control.multiple){var values=options.filter(function(f){return d3.select(this).property("selected")})[0].map(function(m){return d3.select(m).property("text")});var new_filter={col:control.value_col,val:values,choices:option_data,loose:control.loose};targets.forEach(function(e){setSubsetter(e,new_filter);if(control.callback){control.callback()}e.draw()})}else{var value=d3.select(this).select("option:checked").property("text");var _new_filter={col:control.value_col,val:value,choices:option_data,loose:control.loose};targets.forEach(function(e){setSubsetter(e,_new_filter);if(control.callback){control.callback()}e.draw()})}})}function makeTextControl(control,control_wrap){var _this=this;var changer=control_wrap.append("input").attr("type","text").attr("class","changer").datum(control).property("value",function(d){return _this.stringAccessor(_this.targets[0].config,control.option)});changer.on("change",function(d){var value=changer.property("value");_this.changeOption(control.option,value,control.callback)})}function stringAccessor(o,s,v){s=s.replace(/\[(\w+)\]/g,".$1");s=s.replace(/^\./,"");var a=s.split(".");for(var i=0,n=a.length;i0&&arguments[0]!==undefined?arguments[0]:"body";var config=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};var thisControls=Object.create(controls);thisControls.div=element;thisControls.config=Object.create(config);thisControls.config.inputs=thisControls.config.inputs||[];thisControls.targets=[];if(config.location==="bottom"){thisControls.wrap=d3.select(element).append("div").attr("class","wc-controls")}else{thisControls.wrap=d3.select(element).insert("div",":first-child").attr("class","wc-controls")}thisControls.wrap.datum(thisControls);return thisControls}var _typeof=typeof Symbol==="function"&&typeof Symbol.iterator==="symbol"?function(obj){return typeof obj}:function(obj){return obj&&typeof Symbol==="function"&&obj.constructor===Symbol&&obj!==Symbol.prototype?"symbol":typeof obj};function clone(obj){var copy=void 0;if("object"!=(typeof obj==="undefined"?"undefined":_typeof(obj))||null==obj)return obj;if(obj instanceof Date){copy=new Date;copy.setTime(obj.getTime());return copy}if(obj instanceof Array){copy=[];for(var i=0,len=obj.length;i-1:filter.val===d[filter.col]});return match}):clone(this.data.raw)}function applySearchTerm(){var _this=this;this.data.searched=this.data.filtered.filter(function(d){var match=false;Object.keys(d).filter(function(key){return _this.config.cols.indexOf(key)>-1}).forEach(function(var_name){if(match===false){var cellText=""+d[var_name];match=cellText.toLowerCase().indexOf(_this.searchable.searchTerm)>-1}});return match})}if(Array.prototype.equals)console.warn("Overriding existing Array.prototype.equals. Possible causes: New API defines the method, there's a framework conflict or you've got double inclusions in your code.");Array.prototype.equals=function(array){if(!array)return false;if(this.length!=array.length)return false;for(var i=0,l=this.length;i=Math.max(widths.top,widths.bottom)&&this.config.layout==="vertical"){this.config.layout="horizontal";this.wrap.style("display","table").selectAll(".table-top,.table-bottom").style("display","block").selectAll(".interactivity").style({display:"inline-block",float:function float(){return d3.select(this).classed("searchable-container")||d3.select(this).classed("pagination-container")?"right":null},clear:null})}this.events.onDraw.call(this)}function layout$2(){var context=this;this.searchable.wrap=this.wrap.select(".table-top").append("div").classed("interactivity searchable-container",true).classed("hidden",!this.config.searchable);this.searchable.wrap.append("div").classed("search",true);this.searchable.wrap.select(".search").append("input").classed("search-box",true).attr("placeholder","Search").on("input",function(){context.searchable.searchTerm=this.value.toLowerCase()||null;context.config.activePage=0;context.config.startIndex=context.config.activePage*context.config.nRowsPerPage;context.config.endIndex=context.config.startIndex+context.config.nRowsPerPage;context.draw()});this.searchable.wrap.select(".search").append("span").classed("nNrecords",true)}function searchable(){return{layout:layout$2}}function layout$3(){var _this=this;this.exportable.wrap=this.wrap.select(".table-bottom").append("div").classed("interactivity exportable-container",true).classed("hidden",!this.config.exportable);this.exportable.wrap.append("span").text("Export:");if(this.config.exports&&this.config.exports.length)this.config.exports.forEach(function(fmt){_this.exportable.wrap.append("a").classed("wc-button export",true).attr({id:fmt}).text(fmt.toUpperCase())})}function csv(data){var _this=this;var CSVarray=[];data.forEach(function(d,i){if(i===0){var headers=_this.config.headers.map(function(header){return'"'+header.replace(/"/g,'""')+'"'});CSVarray.push(headers)}var row=_this.config.cols.map(function(col){var value=d[col];if(typeof value==="string")value=value.replace(/"/g,'""');return'"'+value+'"'});CSVarray.push(row)});var CSV=new Blob([CSVarray.join("\n")],{type:"text/csv;charset=utf-8;"}),fileName="webchartsTableExport_"+d3.time.format("%Y-%m-%dT%H-%M-%S")(new Date)+".csv",link=this.wrap.select(".export#csv");if(navigator.msSaveBlob){link.style({cursor:"pointer","text-decoration":"underline",color:"blue"});link.on("click",function(){navigator.msSaveBlob(CSV,fileName)})}else{if(link.node().download!==undefined){var url=URL.createObjectURL(CSV);link.node().setAttribute("href",url);link.node().setAttribute("download",fileName)}}}function xlsx(data){var _this=this;var sheetName="Selected Data",options={bookType:"xlsx",bookSST:true,type:"binary"},arrayOfArrays=data.map(function(d){return Object.keys(d).filter(function(key){return _this.config.cols.indexOf(key)>-1}).map(function(key){return d[key]})}),workbook={SheetNames:[sheetName],Sheets:{}},cols=[];workbook.Sheets[sheetName]=XLSX.utils.aoa_to_sheet([this.config.headers].concat(arrayOfArrays));workbook.Sheets[sheetName]["!autofilter"]={ref:"A1:"+String.fromCharCode(64+this.config.cols.length)+(data.length+1)};this.table.selectAll("thead tr th").each(function(){cols.push({wpx:this.offsetWidth})});workbook.Sheets[sheetName]["!cols"]=cols;var xlsx=XLSX.write(workbook,options),s2ab=function s2ab(s){var buffer=new ArrayBuffer(s.length),view=new Uint8Array(buffer);for(var i=0;i!==s.length;++i){view[i]=s.charCodeAt(i)&255}return buffer};var blob=new Blob([s2ab(xlsx)],{type:"application/octet-stream;"}),fileName="webchartsTableExport_"+d3.time.format("%Y-%m-%dT%H-%M-%S")(new Date)+".xlsx",link=this.wrap.select(".export#xlsx");if(navigator.msSaveBlob){link.style({cursor:"pointer","text-decoration":"underline",color:"blue"});link.on("click",function(){navigator.msSaveBlob(blob,fileName)})}else{if(link.node().download!==undefined){var url=URL.createObjectURL(blob);link.node().setAttribute("href",url);link.node().setAttribute("download",fileName)}}}var exports$1={csv:csv,xlsx:xlsx};function exportable(){return{layout:layout$3,exports:exports$1}}function layout$4(){this.sortable.wrap=this.wrap.select(".table-top").append("div").classed("interactivity sortable-container",true).classed("hidden",!this.config.sortable);this.sortable.wrap.append("div").classed("instruction",true).text("Click column headers to sort.")}function onClick(th,header){var context=this,selection=d3.select(th),col=this.config.cols[this.config.headers.indexOf(header)];var sortItem=this.sortable.order.filter(function(item){return item.col===col})[0];if(!sortItem){sortItem={col:col,direction:"ascending",wrap:this.sortable.wrap.append("div").datum({key:col}).classed("wc-button sort-box",true).text(header)};sortItem.wrap.append("span").classed("sort-direction",true).html("↓");sortItem.wrap.append("span").classed("remove-sort",true).html("❌");this.sortable.order.push(sortItem)}else{sortItem.direction=sortItem.direction==="ascending"?"descending":"ascending";sortItem.wrap.select("span.sort-direction").html(sortItem.direction==="ascending"?"↓":"↑")}this.sortable.wrap.select(".instruction").classed("hidden",true);this.sortable.order.forEach(function(item,i){item.wrap.on("click",function(d){d3.select(this).remove();context.sortable.order.splice(context.sortable.order.map(function(d){return d.col}).indexOf(d.key),1);context.sortable.wrap.select(".instruction").classed("hidden",context.sortable.order.length);context.draw()})});this.draw()}function sortData(data){var _this=this;data=data.sort(function(a,b){var order=0;_this.sortable.order.forEach(function(item){var aCell=a[item.col],bCell=b[item.col];if(order===0){if(item.direction==="ascending"&&aCellbCell)order=-1;else if(item.direction==="ascending"&&aCell>bCell||item.direction==="descending"&&aCell=_this.config.nPageLinksDisplayed:_this.config.activePage>=_this.config.nPages-_this.config.nPageLinksDisplayed?i<_this.config.nPages-_this.config.nPageLinksDisplayed:i<_this.config.activePage-(Math.ceil(_this.config.nPageLinksDisplayed/2)-1)||_this.config.activePage+_this.config.nPageLinksDisplayed/2=this.config.nPages)next=this.config.nPages-1;this.pagination.wrap.insert("span",":first-child").classed("dot-dot-dot",true).text("...").classed("hidden",this.config.activePage=Math.max(this.config.nPageLinksDisplayed,this.config.nPages-this.config.nPageLinksDisplayed)||this.config.nPages<=this.config.nPageLinksDisplayed);this.pagination.next=this.pagination.wrap.append("a").classed("wc-button arrow-link right",true).classed("hidden",this.config.activePage==this.config.nPages-1||this.config.nPages==0).attr({rel:next}).text(">");this.pagination.doubleNext=this.pagination.wrap.append("a").classed("wc-button arrow-link right double",true).classed("hidden",this.config.activePage==this.config.nPages-1||this.config.nPages==0).attr({rel:this.config.nPages-1}).text(">>");this.pagination.arrows=this.pagination.wrap.selectAll("a.arrow-link");this.pagination.doubleArrows=this.pagination.wrap.selectAll("a.double-arrow-link")}function addPagination(data){var context=this;this.config.nRows=data.length;this.config.nPages=Math.ceil(this.config.nRows/this.config.nRowsPerPage);this.config.paginationHidden=this.config.nPages===1;this.pagination.wrap.classed("hidden",this.config.paginationHidden);addLinks.call(this);this.pagination.links.on("click",function(){context.config.activePage=+d3.select(this).attr("rel");updatePagination.call(context)});addArrows.call(this);this.pagination.arrows.on("click",function(){if(context.config.activePage!==+d3.select(this).attr("rel")){context.config.activePage=+d3.select(this).attr("rel");context.pagination.prev.attr("rel",context.config.activePage>0?context.config.activePage-1:0);context.pagination.next.attr("rel",context.config.activePage1&&arguments[1]!==undefined?arguments[1]:false;if(d3.select(this.div).select(".loader").empty()){d3.select(this.div).insert("div",":first-child").attr("class","loader").selectAll(".blockG").data(d3.range(8)).enter().append("div").attr("class",function(d){return"blockG rotate"+(d+1)})}this.setDefaults.call(this,data[0]);this.wrap.classed("wc-chart",true).classed("wc-table",this.config.applyCSS);this.data={raw:data};this.searchable=searchable.call(this);this.sortable=sortable.call(this);this.pagination=pagination.call(this);this.exportable=exportable.call(this);var startup=function startup(data){if(_this.controls){_this.controls.targets.push(_this);if(!_this.controls.ready){_this.controls.init(_this.data.raw)}else{_this.controls.layout()}}var visible=d3.select(_this.div).property("offsetWidth")>0||test;if(!visible){console.warn("The table cannot be initialized inside an element with 0 width. The table will be initialized as soon as the container element is given a width > 0.");var onVisible=setInterval(function(i){var visible_now=d3.select(_this.div).property("offsetWidth")>0;if(visible_now){_this.layout();_this.wrap.datum(_this);_this.draw();clearInterval(onVisible)}},500)}else{_this.layout();_this.wrap.datum(_this);_this.draw()}};this.events.onInit.call(this);if(this.data.raw.length){this.checkRequired(this.data.raw)}startup(data);return this}function layout$6(){d3.select(this.div).select(".loader").remove();this.wrap.append("div").classed("table-top",true);this.searchable.layout.call(this);this.sortable.layout.call(this);this.table=this.wrap.append("table").classed("table",this.config.bootstrap);this.thead=this.table.append("thead");this.thead.append("tr");this.tbody=this.table.append("tbody");this.wrap.append("div").classed("table-bottom",true);this.pagination.layout.call(this);this.exportable.layout.call(this);this.events.onLayout.call(this)}function destroy$2(){var destroyControls=arguments.length>0&&arguments[0]!==undefined?arguments[0]:false;this.events.onDestroy.call(this);if(destroyControls&&this.controls){this.controls.destroy()}this.wrap.remove()}function setDefault(setting){var _default_=arguments.length>1&&arguments[1]!==undefined?arguments[1]:true;this.config[setting]=this.config[setting]!==undefined?this.config[setting]:_default_}function setDefaults$1(firstItem){if(this.config.cols instanceof Array&&this.config.headers instanceof Array){if(this.config.cols.length===0)delete this.config.cols;if(this.config.headers.length===0||this.config.headers.length!==this.config.cols.length)delete this.config.headers}this.config.cols=this.config.cols||d3.keys(firstItem);this.config.headers=this.config.headers||this.config.cols;this.config.layout="horizontal";setDefault.call(this,"searchable");setDefault.call(this,"exportable");setDefault.call(this,"exports",["csv"]);setDefault.call(this,"sortable");setDefault.call(this,"pagination");setDefault.call(this,"nRowsPerPage",10);setDefault.call(this,"nPageLinksDisplayed",5);setDefault.call(this,"applyCSS")}function transformData$1(processed_data){var _this=this;this.data.processed=this.transformData(this.wrap.datum);if(!data){return}this.config.cols=this.config.cols||d3.keys(data[0]);this.config.headers=this.config.headers||this.config.cols;if(this.config.keep){this.config.keep.forEach(function(e){if(_this.config.cols.indexOf(e)===-1){_this.config.cols.unshift(e)}})}var filtered=data;if(this.filters.length){this.filters.forEach(function(e){var is_array=e.val instanceof Array;filtered=filtered.filter(function(d){if(is_array){return e.val.indexOf(d[e.col])!==-1}else{return e.val!=="All"?d[e.col]===e.val:d}})})}var slimmed=d3.nest().key(function(d){if(_this.config.row_per){return _this.config.row_per.map(function(m){return d[m]}).join(" ")}else{return d}}).rollup(function(r){if(_this.config.dataManipulate){r=_this.config.dataManipulate(r)}var nuarr=r.map(function(m){var arr=[];for(var x in m){arr.push({col:x,text:m[x]})}arr.sort(function(a,b){return _this.config.cols.indexOf(a.col)-_this.config.cols.indexOf(b.col)});return{cells:arr,raw:m}});return nuarr}).entries(filtered);this.data.current=slimmed.length?slimmed:[{key:null,values:[]}];this.pagination.wrap.selectAll("*").remove();this.events.onDatatransform.call(this);if(config.row_per){var rev_order=config.row_per.slice(0).reverse();rev_order.forEach(function(e){tbodies.sort(function(a,b){return a.values[0].raw[e]-b.values[0].raw[e]})})}if(config.row_per){rows.filter(function(f,i){return i>0}).selectAll("td").filter(function(f){return config.row_per.indexOf(f.col)>-1}).text("")}return this.data.current}var table=Object.create(chart,{draw:{value:draw$1},init:{value:init$2},layout:{value:layout$6},setDefaults:{value:setDefaults$1},transformData:{value:transformData$1},destroy:{value:destroy$2}});function createTable(){var element=arguments.length>0&&arguments[0]!==undefined?arguments[0]:"body";var config=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};var controls=arguments.length>2&&arguments[2]!==undefined?arguments[2]:null;var thisTable=Object.create(table);thisTable.div=element;thisTable.config=Object.create(config);thisTable.controls=controls;thisTable.filters=[];thisTable.required_cols=[];thisTable.wrap=d3.select(thisTable.div).append("div");thisTable.events={onInit:function onInit(){},onLayout:function onLayout(){},onPreprocess:function onPreprocess(){},onDatatransform:function onDatatransform(){},onDraw:function onDraw(){},onResize:function onResize(){},onDestroy:function onDestroy(){}};thisTable.on=function(event,callback){var possible_events=["init","layout","preprocess","datatransform","draw","resize","destroy"];if(possible_events.indexOf(event)<0){return}if(callback){thisTable.events["on"+event.charAt(0).toUpperCase()+event.slice(1)]=callback}};return thisTable}function multiply(chart,data,split_by,order){var test=arguments.length>4&&arguments[4]!==undefined?arguments[4]:false;var config=chart.config;var wrap=chart.wrap.classed("wc-layout wc-small-multiples",true).classed("wc-chart",false);var master_legend=wrap.append("ul").attr("class","legend");chart.multiples=[];function goAhead(data){var split_vals=d3.set(data.map(function(m){return m[split_by]})).values().filter(function(f){return f});if(order){split_vals=split_vals.sort(function(a,b){return d3.ascending(order.indexOf(a),order.indexOf(b))})}split_vals.forEach(function(e){var mchart=createChart(chart.wrap.node(),config,chart.controls);chart.multiples.push(mchart);mchart.parent=chart;mchart.events=chart.events;mchart.legend=master_legend;mchart.filters.unshift({col:split_by,val:e,choices:split_vals});mchart.wrap.insert("span","svg").attr("class","wc-chart-title").text(e);mchart.init(data,test)})}goAhead(data)}function getValType(data,variable){var var_vals=d3.set(data.map(function(m){return m[variable]})).values();var vals_numbers=var_vals.filter(function(f){return+f||+f===0});if(var_vals.length===vals_numbers.length&&var_vals.length>4){return"continuous"}else{return"categorical"}}function lengthenRaw(data,columns){var my_data=[];data.forEach(function(e){columns.forEach(function(g){var obj=Object.create(e);obj.wc_category=g;obj.wc_value=e[g];my_data.push(obj)})});return my_data}var dataOps={getValType:getValType,lengthenRaw:lengthenRaw,naturalSorter:naturalSorter,summarize:summarize};var index={version:version,createChart:createChart,createControls:createControls,createTable:createTable,multiply:multiply,dataOps:dataOps};return index}); \ No newline at end of file diff --git a/css/webcharts.css b/css/webcharts.css index 1caf00e..4232c46 100644 --- a/css/webcharts.css +++ b/css/webcharts.css @@ -75,7 +75,6 @@ font-size: .9em; padding: 0; margin: 0; - display: inline-block; } *[class*="wc-"] .legend .legend-title { diff --git a/css/webcharts.min.css b/css/webcharts.min.css index 4a2969b..086b535 100644 --- a/css/webcharts.min.css +++ b/css/webcharts.min.css @@ -1 +1 @@ -@import url(//fonts.googleapis.com/css?family=Open+Sans:400,300);div.wc-layout.wc-small-multiples::after{content:"";clear:both;display:block}.wc-layout.wc-small-multiples>.wc-chart{float:left;padding:0 2em 2em 0}.wc-layout.wc-small-multiples>.wc-chart>.wc-chart-title{display:block;font-weight:700;text-align:center}.wc-small-multiples .wc-chart>.legend{display:none}.wc-chart{position:relative;font-family:'Open Sans',Helvetica,Arial,sans-serif}.wc-chart line,.wc-chart rect{shape-rendering:crispEdges}.wc-chart.brushable .overlay{cursor:crosshair}.wc-chart rect.background{display:none}.wc-chart rect.extent{fill:#ccc;fill-opacity:.4;shape-rendering:crispEdges}.wc-chart .axis path.domain{fill:none;stroke:#ccc;shape-rendering:crispEdges}.wc-chart .axis .tick line{stroke:#eee;shape-rendering:crispEdges}.wc-chart .axis .tick text{font-size:.9em}.wc-chart .axis .axis-title{fill:#555}[class*=wc-] .legend{font-size:.9em;padding:0;margin:0;display:inline-block}[class*=wc-] .legend .legend-title{font-weight:700;margin-right:1em}[class*=wc-] .legend .legend-item{display:inline-block;margin-right:1em}[class*=wc-] .legend .legend-item .legend-color-block{position:relative;top:.2em;right:.25em;display:inline-block}[class*=wc-] .legend .legend-item .legend-mark-text{font-weight:700;margin-right:.5em}.wc-chart .ordinal.axis .tick line,.wc-chart .ordinal.axis path{display:none}.wc-chart.gridlines .ordinal.axis .tick line{display:block}.wc-controls{display:block;font-family:'Open Sans',Helvetica,Arial,sans-serif;font-size:.9em;margin-bottom:10px}.wc-controls:empty{display:none}.intro>.wc-controls{display:block}.wc-controls .control-group{display:inline-table;max-width:100%;margin:0 1em 1em 0}.wc-controls.bottom .control-group{display:inline-table}.wc-controls .control-group .wc-control-label{display:block}.wc-controls .control-group.inline .wc-control-label{display:inline;margin-right:.5em}.wc-controls .control-group.inline .changer{display:inline;margin-top:0}.wc-controls .control-group .wc-control-label+.changer{margin-top:2px}.wc-controls .control-group .wc-control-label.inline{display:inline;margin-right:.5em}.wc-controls .control-group .wc-control-label .label-required{color:#de2d26;padding:0 .25em;border:1px solid;margin-left:.5em}.wc-controls .span-description{display:block;font-size:.75em;color:#777;margin-bottom:3px}.wc-controls .span-description:empty{display:none}.wc-controls .span-description.standout{font-style:italic;color:#d9534f}.wc-controls .control-group label.filter-values,.wc-controls .control-group label.radio{display:inline-block;cursor:pointer;font-weight:400;font-size:.9em;padding:0;margin:5px 10px 0 0}.wc-controls .inline{display:inline}.wc-controls .control-group input[type=text],.wc-controls select{display:block;width:auto;max-width:100%;padding:0 2px;height:auto;border-radius:0}.wc-controls .control-group input[type=number]{width:70px;text-align:right;max-width:100%}.wc-controls .control-group input[type=checkbox],.wc-controls .control-group input[type=radio]{cursor:pointer;position:relative;top:.1em;float:none;margin:0}.wc-controls .control-group input[type=radio]{vertical-align:bottom;margin-left:.25em}.wc-controls .control-group input.inline{margin:0 2px 2px 0}.wc-controls .control-group .changer+.changer{margin-top:2px}.wc-controls .subsetter-ui{position:relative;display:inline-block;max-width:100%;padding:3px;border:1px dashed #888;margin:5px 5px 0 0}.wc-controls .subsetter-ui .remove-btn{cursor:pointer;position:absolute;top:2px;right:2px}.wc-table{display:block}.wc-table .hidden{display:none!important}.wc-table .invisible{visibility:hidden!important}.wc-table>*{display:block}.wc-table .interactivity{display:inline-block;vertical-align:middle;margin:10px 0;padding:0}.wc-table .interactivity .wc-button{display:inline-block;border:2px solid gray;border-radius:4px;padding:2px 8px;margin:0 2px;cursor:pointer;background:#fff;color:#000}.wc-table .interactivity .wc-button:hover{background:#000;color:#fff}.wc-table .searchable-container{float:right;overflow:hidden}.wc-table .searchable-container input{margin:0 10px 0 0;padding:4px}.wc-table .sortable-container{margin-right:10px}.wc-table .sortable-container .instruction{margin-top:4px}.wc-table .sortable-container .sort-box{cursor:default;padding:2px 4px}.wc-table .sortable-container .sort-direction{font-weight:700;margin:3px}.wc-table .sortable-container .sort-box .remove-sort{font-weight:700;float:right;border:1px solid gray;margin-top:3px;padding:2px 3px;font-size:8px;background:#fff;color:red}.wc-table .sortable-container .sort-box .remove-sort:hover{cursor:pointer;background:red;color:#fff}.wc-table table{font-size:.9em;border-collapse:collapse}.wc-table table thead tr th{cursor:pointer;padding:2px 5px;border-bottom:2px solid #000;text-align:left}.wc-table table tbody tr:nth-child(even){background:#eee}.wc-table table tbody tr:hover{background:#ccc}.wc-table table tbody tr td{padding:2px 5px}.wc-table table tbody tr:last-child{border-bottom:1px solid #000}.wc-table table tbody tr.no-data td{color:red;font-weight:700}.wc-table .pagination-container{float:right}.wc-table .pagination-container a{text-decoration:none}.wc-table .pagination-container a:not(.active){border:none}.wc-table .exportable-container{float:left}.wc-table .exportable-container a{text-decoration:none}.loader{position:relative;width:20px;height:25px}.blockG{position:absolute;background-color:#eee;width:3px;height:8px;-moz-border-radius:4px 4px 0 0;-moz-transform:scale(.4);-moz-animation-name:fadeG;-moz-animation-duration:.48s;-moz-animation-iteration-count:infinite;-moz-animation-direction:linear;-webkit-border-radius:4px 4px 0 0;-webkit-transform:scale(.4);-webkit-animation-name:fadeG;-webkit-animation-duration:.48s;-webkit-animation-iteration-count:infinite;-webkit-animation-direction:linear;-ms-border-radius:4px 4px 0 0;-ms-transform:scale(.4);-ms-animation-name:fadeG;-ms-animation-duration:.48s;-ms-animation-iteration-count:infinite;-ms-animation-direction:linear;-o-border-radius:4px 4px 0 0;-o-transform:scale(.4);-o-animation-name:fadeG;-o-animation-duration:.48s;-o-animation-iteration-count:infinite;-o-animation-direction:linear;border-radius:4px 4px 0 0;transform:scale(.4);animation-name:fadeG;animation-duration:.48s;animation-iteration-count:infinite;animation-direction:linear}.rotate1{left:0;top:9px;-moz-animation-delay:.18s;-moz-transform:rotate(-90deg);-webkit-animation-delay:.18s;-webkit-transform:rotate(-90deg);-ms-animation-delay:.18s;-ms-transform:rotate(-90deg);-o-animation-delay:.18s;-o-transform:rotate(-90deg);animation-delay:.18s;transform:rotate(-90deg)}.rotate2{left:3px;top:3px;-moz-animation-delay:.24s;-moz-transform:rotate(-45deg);-webkit-animation-delay:.24s;-webkit-transform:rotate(-45deg);-ms-animation-delay:.24s;-ms-transform:rotate(-45deg);-o-animation-delay:.24s;-o-transform:rotate(-45deg);animation-delay:.24s;transform:rotate(-45deg)}.rotate3{left:8px;top:1px;-moz-animation-delay:.3s;-moz-transform:rotate(0);-webkit-animation-delay:.3s;-webkit-transform:rotate(0);-ms-animation-delay:.3s;-ms-transform:rotate(0);-o-animation-delay:.3s;-o-transform:rotate(0);animation-delay:.3s;transform:rotate(0)}.rotate4{right:3px;top:3px;-moz-animation-delay:.36s;-moz-transform:rotate(45deg);-webkit-animation-delay:.36s;-webkit-transform:rotate(45deg);-ms-animation-delay:.36s;-ms-transform:rotate(45deg);-o-animation-delay:.36s;-o-transform:rotate(45deg);animation-delay:.36s;transform:rotate(45deg)}.rotate5{right:0;top:9px;-moz-animation-delay:.42000000000000004s;-moz-transform:rotate(90deg);-webkit-animation-delay:.42000000000000004s;-webkit-transform:rotate(90deg);-ms-animation-delay:.42000000000000004s;-ms-transform:rotate(90deg);-o-animation-delay:.42000000000000004s;-o-transform:rotate(90deg);animation-delay:.42000000000000004s;transform:rotate(90deg)}.rotate6{right:3px;bottom:2px;-moz-animation-delay:.48s;-moz-transform:rotate(135deg);-webkit-animation-delay:.48s;-webkit-transform:rotate(135deg);-ms-animation-delay:.48s;-ms-transform:rotate(135deg);-o-animation-delay:.48s;-o-transform:rotate(135deg);animation-delay:.48s;transform:rotate(135deg)}.rotate7{bottom:0;left:8px;-moz-animation-delay:.5399999999999999s;-moz-transform:rotate(180deg);-webkit-animation-delay:.5399999999999999s;-webkit-transform:rotate(180deg);-ms-animation-delay:.5399999999999999s;-ms-transform:rotate(180deg);-o-animation-delay:.5399999999999999s;-o-transform:rotate(180deg);animation-delay:.5399999999999999s;transform:rotate(180deg)}.rotate8{left:3px;bottom:2px;-moz-animation-delay:.6s;-moz-transform:rotate(-135deg);-webkit-animation-delay:.6s;-webkit-transform:rotate(-135deg);-ms-animation-delay:.6s;-ms-transform:rotate(-135deg);-o-animation-delay:.6s;-o-transform:rotate(-135deg);animation-delay:.6s;transform:rotate(-135deg)}@-moz-keyframes fadeG{0%{background-color:#000}100%{background-color:#eee}}@-webkit-keyframes fadeG{0%{background-color:#000}100%{background-color:#eee}}@-ms-keyframes fadeG{0%{background-color:#000}100%{background-color:#eee}}@-o-keyframes fadeG{0%{background-color:#000}100%{background-color:#eee}}@keyframes fadeG{0%{background-color:#000}100%{background-color:#eee}} \ No newline at end of file +@import url(//fonts.googleapis.com/css?family=Open+Sans:400,300);div.wc-layout.wc-small-multiples::after{content:"";clear:both;display:block}.wc-layout.wc-small-multiples>.wc-chart{float:left;padding:0 2em 2em 0}.wc-layout.wc-small-multiples>.wc-chart>.wc-chart-title{display:block;font-weight:700;text-align:center}.wc-small-multiples .wc-chart>.legend{display:none}.wc-chart{position:relative;font-family:'Open Sans',Helvetica,Arial,sans-serif}.wc-chart line,.wc-chart rect{shape-rendering:crispEdges}.wc-chart.brushable .overlay{cursor:crosshair}.wc-chart rect.background{display:none}.wc-chart rect.extent{fill:#ccc;fill-opacity:.4;shape-rendering:crispEdges}.wc-chart .axis path.domain{fill:none;stroke:#ccc;shape-rendering:crispEdges}.wc-chart .axis .tick line{stroke:#eee;shape-rendering:crispEdges}.wc-chart .axis .tick text{font-size:.9em}.wc-chart .axis .axis-title{fill:#555}[class*=wc-] .legend{font-size:.9em;padding:0;margin:0}[class*=wc-] .legend .legend-title{font-weight:700;margin-right:1em}[class*=wc-] .legend .legend-item{display:inline-block;margin-right:1em}[class*=wc-] .legend .legend-item .legend-color-block{position:relative;top:.2em;right:.25em;display:inline-block}[class*=wc-] .legend .legend-item .legend-mark-text{font-weight:700;margin-right:.5em}.wc-chart .ordinal.axis .tick line,.wc-chart .ordinal.axis path{display:none}.wc-chart.gridlines .ordinal.axis .tick line{display:block}.wc-controls{display:block;font-family:'Open Sans',Helvetica,Arial,sans-serif;font-size:.9em;margin-bottom:10px}.wc-controls:empty{display:none}.intro>.wc-controls{display:block}.wc-controls .control-group{display:inline-table;max-width:100%;margin:0 1em 1em 0}.wc-controls.bottom .control-group{display:inline-table}.wc-controls .control-group .wc-control-label{display:block}.wc-controls .control-group.inline .wc-control-label{display:inline;margin-right:.5em}.wc-controls .control-group.inline .changer{display:inline;margin-top:0}.wc-controls .control-group .wc-control-label+.changer{margin-top:2px}.wc-controls .control-group .wc-control-label.inline{display:inline;margin-right:.5em}.wc-controls .control-group .wc-control-label .label-required{color:#de2d26;padding:0 .25em;border:1px solid;margin-left:.5em}.wc-controls .span-description{display:block;font-size:.75em;color:#777;margin-bottom:3px}.wc-controls .span-description:empty{display:none}.wc-controls .span-description.standout{font-style:italic;color:#d9534f}.wc-controls .control-group label.filter-values,.wc-controls .control-group label.radio{display:inline-block;cursor:pointer;font-weight:400;font-size:.9em;padding:0;margin:5px 10px 0 0}.wc-controls .inline{display:inline}.wc-controls .control-group input[type=text],.wc-controls select{display:block;width:auto;max-width:100%;padding:0 2px;height:auto;border-radius:0}.wc-controls .control-group input[type=number]{width:70px;text-align:right;max-width:100%}.wc-controls .control-group input[type=checkbox],.wc-controls .control-group input[type=radio]{cursor:pointer;position:relative;top:.1em;float:none;margin:0}.wc-controls .control-group input[type=radio]{vertical-align:bottom;margin-left:.25em}.wc-controls .control-group input.inline{margin:0 2px 2px 0}.wc-controls .control-group .changer+.changer{margin-top:2px}.wc-controls .subsetter-ui{position:relative;display:inline-block;max-width:100%;padding:3px;border:1px dashed #888;margin:5px 5px 0 0}.wc-controls .subsetter-ui .remove-btn{cursor:pointer;position:absolute;top:2px;right:2px}.wc-table{display:block}.wc-table .hidden{display:none!important}.wc-table .invisible{visibility:hidden!important}.wc-table>*{display:block}.wc-table .interactivity{display:inline-block;vertical-align:middle;margin:10px 0;padding:0}.wc-table .interactivity .wc-button{display:inline-block;border:2px solid gray;border-radius:4px;padding:2px 8px;margin:0 2px;cursor:pointer;background:#fff;color:#000}.wc-table .interactivity .wc-button:hover{background:#000;color:#fff}.wc-table .searchable-container{float:right;overflow:hidden}.wc-table .searchable-container input{margin:0 10px 0 0;padding:4px}.wc-table .sortable-container{margin-right:10px}.wc-table .sortable-container .instruction{margin-top:4px}.wc-table .sortable-container .sort-box{cursor:default;padding:2px 4px}.wc-table .sortable-container .sort-direction{font-weight:700;margin:3px}.wc-table .sortable-container .sort-box .remove-sort{font-weight:700;float:right;border:1px solid gray;margin-top:3px;padding:2px 3px;font-size:8px;background:#fff;color:red}.wc-table .sortable-container .sort-box .remove-sort:hover{cursor:pointer;background:red;color:#fff}.wc-table table{font-size:.9em;border-collapse:collapse}.wc-table table thead tr th{cursor:pointer;padding:2px 5px;border-bottom:2px solid #000;text-align:left}.wc-table table tbody tr:nth-child(even){background:#eee}.wc-table table tbody tr:hover{background:#ccc}.wc-table table tbody tr td{padding:2px 5px}.wc-table table tbody tr:last-child{border-bottom:1px solid #000}.wc-table table tbody tr.no-data td{color:red;font-weight:700}.wc-table .pagination-container{float:right}.wc-table .pagination-container a{text-decoration:none}.wc-table .pagination-container a:not(.active){border:none}.wc-table .exportable-container{float:left}.wc-table .exportable-container a{text-decoration:none}.loader{position:relative;width:20px;height:25px}.blockG{position:absolute;background-color:#eee;width:3px;height:8px;-moz-border-radius:4px 4px 0 0;-moz-transform:scale(.4);-moz-animation-name:fadeG;-moz-animation-duration:.48s;-moz-animation-iteration-count:infinite;-moz-animation-direction:linear;-webkit-border-radius:4px 4px 0 0;-webkit-transform:scale(.4);-webkit-animation-name:fadeG;-webkit-animation-duration:.48s;-webkit-animation-iteration-count:infinite;-webkit-animation-direction:linear;-ms-border-radius:4px 4px 0 0;-ms-transform:scale(.4);-ms-animation-name:fadeG;-ms-animation-duration:.48s;-ms-animation-iteration-count:infinite;-ms-animation-direction:linear;-o-border-radius:4px 4px 0 0;-o-transform:scale(.4);-o-animation-name:fadeG;-o-animation-duration:.48s;-o-animation-iteration-count:infinite;-o-animation-direction:linear;border-radius:4px 4px 0 0;transform:scale(.4);animation-name:fadeG;animation-duration:.48s;animation-iteration-count:infinite;animation-direction:linear}.rotate1{left:0;top:9px;-moz-animation-delay:.18s;-moz-transform:rotate(-90deg);-webkit-animation-delay:.18s;-webkit-transform:rotate(-90deg);-ms-animation-delay:.18s;-ms-transform:rotate(-90deg);-o-animation-delay:.18s;-o-transform:rotate(-90deg);animation-delay:.18s;transform:rotate(-90deg)}.rotate2{left:3px;top:3px;-moz-animation-delay:.24s;-moz-transform:rotate(-45deg);-webkit-animation-delay:.24s;-webkit-transform:rotate(-45deg);-ms-animation-delay:.24s;-ms-transform:rotate(-45deg);-o-animation-delay:.24s;-o-transform:rotate(-45deg);animation-delay:.24s;transform:rotate(-45deg)}.rotate3{left:8px;top:1px;-moz-animation-delay:.3s;-moz-transform:rotate(0);-webkit-animation-delay:.3s;-webkit-transform:rotate(0);-ms-animation-delay:.3s;-ms-transform:rotate(0);-o-animation-delay:.3s;-o-transform:rotate(0);animation-delay:.3s;transform:rotate(0)}.rotate4{right:3px;top:3px;-moz-animation-delay:.36s;-moz-transform:rotate(45deg);-webkit-animation-delay:.36s;-webkit-transform:rotate(45deg);-ms-animation-delay:.36s;-ms-transform:rotate(45deg);-o-animation-delay:.36s;-o-transform:rotate(45deg);animation-delay:.36s;transform:rotate(45deg)}.rotate5{right:0;top:9px;-moz-animation-delay:.42000000000000004s;-moz-transform:rotate(90deg);-webkit-animation-delay:.42000000000000004s;-webkit-transform:rotate(90deg);-ms-animation-delay:.42000000000000004s;-ms-transform:rotate(90deg);-o-animation-delay:.42000000000000004s;-o-transform:rotate(90deg);animation-delay:.42000000000000004s;transform:rotate(90deg)}.rotate6{right:3px;bottom:2px;-moz-animation-delay:.48s;-moz-transform:rotate(135deg);-webkit-animation-delay:.48s;-webkit-transform:rotate(135deg);-ms-animation-delay:.48s;-ms-transform:rotate(135deg);-o-animation-delay:.48s;-o-transform:rotate(135deg);animation-delay:.48s;transform:rotate(135deg)}.rotate7{bottom:0;left:8px;-moz-animation-delay:.5399999999999999s;-moz-transform:rotate(180deg);-webkit-animation-delay:.5399999999999999s;-webkit-transform:rotate(180deg);-ms-animation-delay:.5399999999999999s;-ms-transform:rotate(180deg);-o-animation-delay:.5399999999999999s;-o-transform:rotate(180deg);animation-delay:.5399999999999999s;transform:rotate(180deg)}.rotate8{left:3px;bottom:2px;-moz-animation-delay:.6s;-moz-transform:rotate(-135deg);-webkit-animation-delay:.6s;-webkit-transform:rotate(-135deg);-ms-animation-delay:.6s;-ms-transform:rotate(-135deg);-o-animation-delay:.6s;-o-transform:rotate(-135deg);animation-delay:.6s;transform:rotate(-135deg)}@-moz-keyframes fadeG{0%{background-color:#000}100%{background-color:#eee}}@-webkit-keyframes fadeG{0%{background-color:#000}100%{background-color:#eee}}@-ms-keyframes fadeG{0%{background-color:#000}100%{background-color:#eee}}@-o-keyframes fadeG{0%{background-color:#000}100%{background-color:#eee}}@keyframes fadeG{0%{background-color:#000}100%{background-color:#eee}} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 2c9b19f..e698a1a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "webcharts", - "version": "1.11.0", + "version": "1.9.1", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -14,174 +14,6 @@ "printj": "1.1.0" } }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", - "dev": true, - "requires": { - "chalk": "1.1.3", - "esutils": "2.0.2", - "js-tokens": "3.0.2" - } - }, - "babel-helper-builder-binary-assignment-operator-visitor": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz", - "integrity": "sha1-zORReto1b0IgvK6KAsKzRvmlZmQ=", - "dev": true, - "requires": { - "babel-helper-explode-assignable-expression": "6.24.1", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-helper-call-delegate": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz", - "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", - "dev": true, - "requires": { - "babel-helper-hoist-variables": "6.24.1", - "babel-runtime": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-helper-define-map": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz", - "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=", - "dev": true, - "requires": { - "babel-helper-function-name": "6.24.1", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "lodash": "4.17.10" - } - }, - "babel-helper-explode-assignable-expression": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz", - "integrity": "sha1-8luCz33BBDPFX3BZLVdGQArCLKo=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-helper-function-name": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", - "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", - "dev": true, - "requires": { - "babel-helper-get-function-arity": "6.24.1", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-helper-get-function-arity": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", - "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-helper-hoist-variables": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz", - "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-helper-optimise-call-expression": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz", - "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-helper-regex": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz", - "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "lodash": "4.17.10" - } - }, - "babel-helper-remap-async-to-generator": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz", - "integrity": "sha1-XsWBgnrXI/7N04HxySg5BnbkVRs=", - "dev": true, - "requires": { - "babel-helper-function-name": "6.24.1", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-helper-replace-supers": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz", - "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", - "dev": true, - "requires": { - "babel-helper-optimise-call-expression": "6.24.1", - "babel-messages": "6.23.0", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-messages": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", - "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-check-es2015-constants": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz", - "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0" - } - }, "babel-plugin-external-helpers": { "version": "6.22.0", "resolved": "https://registry.npmjs.org/babel-plugin-external-helpers/-/babel-plugin-external-helpers-6.22.0.tgz", @@ -215,308 +47,13 @@ } } }, - "babel-plugin-syntax-async-functions": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", - "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=", - "dev": true - }, - "babel-plugin-syntax-exponentiation-operator": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", - "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=", - "dev": true - }, - "babel-plugin-syntax-trailing-function-commas": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz", - "integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM=", - "dev": true - }, - "babel-plugin-transform-async-to-generator": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz", - "integrity": "sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E=", - "dev": true, - "requires": { - "babel-helper-remap-async-to-generator": "6.24.1", - "babel-plugin-syntax-async-functions": "6.13.0", - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-transform-es2015-arrow-functions": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", - "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-transform-es2015-block-scoped-functions": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz", - "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-transform-es2015-block-scoping": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz", - "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0", - "lodash": "4.17.10" - } - }, - "babel-plugin-transform-es2015-classes": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz", - "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", - "dev": true, - "requires": { - "babel-helper-define-map": "6.26.0", - "babel-helper-function-name": "6.24.1", - "babel-helper-optimise-call-expression": "6.24.1", - "babel-helper-replace-supers": "6.24.1", - "babel-messages": "6.23.0", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-plugin-transform-es2015-computed-properties": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz", - "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-template": "6.26.0" - } - }, - "babel-plugin-transform-es2015-destructuring": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz", - "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-transform-es2015-duplicate-keys": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz", - "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-plugin-transform-es2015-for-of": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz", - "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-transform-es2015-function-name": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz", - "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", - "dev": true, - "requires": { - "babel-helper-function-name": "6.24.1", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-plugin-transform-es2015-literals": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz", - "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-transform-es2015-modules-amd": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz", - "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=", - "dev": true, - "requires": { - "babel-plugin-transform-es2015-modules-commonjs": "6.26.2", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0" - } - }, - "babel-plugin-transform-es2015-modules-commonjs": { - "version": "6.26.2", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz", - "integrity": "sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q==", - "dev": true, - "requires": { - "babel-plugin-transform-strict-mode": "6.24.1", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-plugin-transform-es2015-modules-systemjs": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz", - "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=", - "dev": true, - "requires": { - "babel-helper-hoist-variables": "6.24.1", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0" - } - }, - "babel-plugin-transform-es2015-modules-umd": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz", - "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=", - "dev": true, - "requires": { - "babel-plugin-transform-es2015-modules-amd": "6.24.1", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0" - } - }, - "babel-plugin-transform-es2015-object-super": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz", - "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", - "dev": true, - "requires": { - "babel-helper-replace-supers": "6.24.1", - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-transform-es2015-parameters": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz", - "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", - "dev": true, - "requires": { - "babel-helper-call-delegate": "6.24.1", - "babel-helper-get-function-arity": "6.24.1", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-plugin-transform-es2015-shorthand-properties": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz", - "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-plugin-transform-es2015-spread": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz", - "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-transform-es2015-sticky-regex": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz", - "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=", - "dev": true, - "requires": { - "babel-helper-regex": "6.26.0", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-plugin-transform-es2015-template-literals": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz", - "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-transform-es2015-typeof-symbol": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz", - "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-transform-es2015-unicode-regex": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz", - "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=", - "dev": true, - "requires": { - "babel-helper-regex": "6.26.0", - "babel-runtime": "6.26.0", - "regexpu-core": "2.0.0" - } - }, - "babel-plugin-transform-exponentiation-operator": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz", - "integrity": "sha1-KrDJx/MJj6SJB3cruBP+QejeOg4=", - "dev": true, - "requires": { - "babel-helper-builder-binary-assignment-operator-visitor": "6.24.1", - "babel-plugin-syntax-exponentiation-operator": "6.13.0", - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-transform-regenerator": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz", - "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=", - "dev": true, - "requires": { - "regenerator-transform": "0.10.1" - } - }, - "babel-plugin-transform-strict-mode": { + "babel-preset-es2015": { "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", - "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-preset-env": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.7.0.tgz", - "integrity": "sha512-9OR2afuKDneX2/q2EurSftUYM0xGu4O2D9adAhVfADDhrYDaxXV0rBbevVYoY9n6nyX1PmQW/0jtpJvUNr9CHg==", + "resolved": "https://registry.npmjs.org/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz", + "integrity": "sha1-1EBQ1rwsn+6nAqrzjXJ6AhBTiTk=", "dev": true, "requires": { "babel-plugin-check-es2015-constants": "6.22.0", - "babel-plugin-syntax-trailing-function-commas": "6.22.0", - "babel-plugin-transform-async-to-generator": "6.24.1", "babel-plugin-transform-es2015-arrow-functions": "6.22.0", "babel-plugin-transform-es2015-block-scoped-functions": "6.22.0", "babel-plugin-transform-es2015-block-scoping": "6.26.0", @@ -528,7 +65,7 @@ "babel-plugin-transform-es2015-function-name": "6.24.1", "babel-plugin-transform-es2015-literals": "6.22.0", "babel-plugin-transform-es2015-modules-amd": "6.24.1", - "babel-plugin-transform-es2015-modules-commonjs": "6.26.2", + "babel-plugin-transform-es2015-modules-commonjs": "6.26.0", "babel-plugin-transform-es2015-modules-systemjs": "6.24.1", "babel-plugin-transform-es2015-modules-umd": "6.24.1", "babel-plugin-transform-es2015-object-super": "6.24.1", @@ -539,11 +76,626 @@ "babel-plugin-transform-es2015-template-literals": "6.22.0", "babel-plugin-transform-es2015-typeof-symbol": "6.23.0", "babel-plugin-transform-es2015-unicode-regex": "6.24.1", - "babel-plugin-transform-exponentiation-operator": "6.24.1", - "babel-plugin-transform-regenerator": "6.26.0", - "browserslist": "3.2.8", - "invariant": "2.2.4", - "semver": "5.5.0" + "babel-plugin-transform-regenerator": "6.26.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + } + }, + "babel-helper-call-delegate": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz", + "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", + "dev": true, + "requires": { + "babel-helper-hoist-variables": "6.24.1", + "babel-runtime": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-define-map": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz", + "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=", + "dev": true, + "requires": { + "babel-helper-function-name": "6.24.1", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "lodash": "4.17.5" + } + }, + "babel-helper-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", + "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", + "dev": true, + "requires": { + "babel-helper-get-function-arity": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-get-function-arity": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", + "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-hoist-variables": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz", + "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-optimise-call-expression": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz", + "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-regex": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz", + "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "lodash": "4.17.5" + } + }, + "babel-helper-replace-supers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz", + "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", + "dev": true, + "requires": { + "babel-helper-optimise-call-expression": "6.24.1", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-check-es2015-constants": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz", + "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-arrow-functions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", + "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-block-scoped-functions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz", + "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-block-scoping": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz", + "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "lodash": "4.17.5" + } + }, + "babel-plugin-transform-es2015-classes": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz", + "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", + "dev": true, + "requires": { + "babel-helper-define-map": "6.26.0", + "babel-helper-function-name": "6.24.1", + "babel-helper-optimise-call-expression": "6.24.1", + "babel-helper-replace-supers": "6.24.1", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-computed-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz", + "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-plugin-transform-es2015-destructuring": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz", + "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-duplicate-keys": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz", + "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-for-of": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz", + "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz", + "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", + "dev": true, + "requires": { + "babel-helper-function-name": "6.24.1", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz", + "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-amd": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz", + "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=", + "dev": true, + "requires": { + "babel-plugin-transform-es2015-modules-commonjs": "6.26.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-commonjs": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz", + "integrity": "sha1-DYOUApt9xqvhqX7xgeAHWN0uXYo=", + "dev": true, + "requires": { + "babel-plugin-transform-strict-mode": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-systemjs": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz", + "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=", + "dev": true, + "requires": { + "babel-helper-hoist-variables": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-umd": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz", + "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=", + "dev": true, + "requires": { + "babel-plugin-transform-es2015-modules-amd": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-plugin-transform-es2015-object-super": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz", + "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", + "dev": true, + "requires": { + "babel-helper-replace-supers": "6.24.1", + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-parameters": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz", + "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", + "dev": true, + "requires": { + "babel-helper-call-delegate": "6.24.1", + "babel-helper-get-function-arity": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-shorthand-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz", + "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-spread": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz", + "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-sticky-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz", + "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=", + "dev": true, + "requires": { + "babel-helper-regex": "6.26.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-template-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz", + "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-typeof-symbol": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz", + "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-unicode-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz", + "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=", + "dev": true, + "requires": { + "babel-helper-regex": "6.26.0", + "babel-runtime": "6.26.0", + "regexpu-core": "2.0.0" + } + }, + "babel-plugin-transform-regenerator": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz", + "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=", + "dev": true, + "requires": { + "regenerator-transform": "0.10.1" + } + }, + "babel-plugin-transform-strict-mode": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", + "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "dev": true, + "requires": { + "core-js": "2.5.3", + "regenerator-runtime": "0.11.1" + } + }, + "babel-template": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", + "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "lodash": "4.17.5" + } + }, + "babel-traverse": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "dev": true, + "requires": { + "babel-code-frame": "6.26.0", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "debug": "2.6.9", + "globals": "9.18.0", + "invariant": "2.2.2", + "lodash": "4.17.5" + } + }, + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "esutils": "2.0.2", + "lodash": "4.17.5", + "to-fast-properties": "1.0.3" + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "core-js": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.3.tgz", + "integrity": "sha1-isw4NFgk8W2DZbfJtCWRaOjtYD4=", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "dev": true + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "invariant": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz", + "integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=", + "dev": true, + "requires": { + "loose-envify": "1.3.1" + } + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + }, + "lodash": { + "version": "4.17.5", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", + "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==", + "dev": true + }, + "loose-envify": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", + "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", + "dev": true, + "requires": { + "js-tokens": "3.0.2" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", + "dev": true + }, + "regenerate": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.3.tgz", + "integrity": "sha512-jVpo1GadrDAK59t/0jRx5VxYWQEDkkEKi6+HjE3joFVLfDOh9Xrdh0dF1eSq+BI/SwvTQ44gSscJ8N5zYL61sg==", + "dev": true + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "dev": true + }, + "regenerator-transform": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz", + "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "private": "0.1.8" + } + }, + "regexpu-core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", + "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=", + "dev": true, + "requires": { + "regenerate": "1.3.3", + "regjsgen": "0.2.0", + "regjsparser": "0.1.5" + } + }, + "regjsgen": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", + "dev": true + }, + "regjsparser": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", + "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", + "dev": true, + "requires": { + "jsesc": "0.5.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + }, + "to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", + "dev": true + } } }, "babel-register": { @@ -982,80 +1134,6 @@ } } }, - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "dev": true, - "requires": { - "core-js": "2.5.6", - "regenerator-runtime": "0.11.1" - } - }, - "babel-template": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", - "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "lodash": "4.17.10" - } - }, - "babel-traverse": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", - "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", - "dev": true, - "requires": { - "babel-code-frame": "6.26.0", - "babel-messages": "6.23.0", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "debug": "2.6.9", - "globals": "9.18.0", - "invariant": "2.2.4", - "lodash": "4.17.10" - } - }, - "babel-types": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", - "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0", - "esutils": "2.0.2", - "lodash": "4.17.10", - "to-fast-properties": "1.0.3" - } - }, - "babylon": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", - "dev": true - }, - "browserslist": { - "version": "3.2.8", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-3.2.8.tgz", - "integrity": "sha512-WHVocJYavUwVgVViC0ORikPHQquXwVh939TaelZ4WDqpWgTX/FsGhl/+P4qBUAGcRvtOgDgC+xftNWWp2RUTAQ==", - "dev": true, - "requires": { - "caniuse-lite": "1.0.30000846", - "electron-to-chromium": "1.3.48" - } - }, - "caniuse-lite": { - "version": "1.0.30000846", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000846.tgz", - "integrity": "sha512-qxUOHr5mTaadWH1ap0ueivHd8x42Bnemcn+JutVr7GWmm2bU4zoBhjuv5QdXgALQnnT626lOQros7cCDf8PwCg==", - "dev": true - }, "cfb": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.0.1.tgz", @@ -1074,19 +1152,6 @@ } } }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" - } - }, "clean-css-cli": { "version": "4.1.10", "resolved": "https://registry.npmjs.org/clean-css-cli/-/clean-css-cli-4.1.10.tgz", @@ -1245,12 +1310,6 @@ "typedarray": "0.0.6" } }, - "core-js": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.6.tgz", - "integrity": "sha512-lQUVfQi0aLix2xpyjrrJEvfuYCqPc/HwmTKsC/VNf8q0zsjX7SQZtp4+oRONN5Tsur9GDETPjj+Ub2iDiGZfSQ==", - "dev": true - }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -1271,33 +1330,6 @@ "resolved": "https://registry.npmjs.org/d3/-/d3-3.5.17.tgz", "integrity": "sha1-vEZ0gAQ3iyGjYMn8fPUjF5B2L7g=" }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "electron-to-chromium": { - "version": "1.3.48", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.48.tgz", - "integrity": "sha1-07DYWTgUBE4JLs4hCPw6ya6kuQA=", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", - "dev": true - }, "exit-on-epipe": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz", @@ -1502,21 +1534,6 @@ "integrity": "sha1-V3Z3t/3L5vr3xGHxgB00E3zaQ1Q=", "optional": true }, - "globals": { - "version": "9.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", - "dev": true - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, "he": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", @@ -1527,27 +1544,12 @@ "version": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, - "invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "dev": true, - "requires": { - "loose-envify": "1.3.1" - } - }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "optional": true }, - "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", - "dev": true - }, "js-xlsx": { "version": "0.8.22", "resolved": "https://registry.npmjs.org/js-xlsx/-/js-xlsx-0.8.22.tgz", @@ -2268,12 +2270,6 @@ } } }, - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "dev": true - }, "json-schema-traverse": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", @@ -2289,21 +2285,6 @@ "pako": "0.2.9" } }, - "lodash": { - "version": "4.17.10", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", - "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==", - "dev": true - }, - "loose-envify": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", - "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", - "dev": true, - "requires": { - "js-tokens": "3.0.2" - } - }, "mocha": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/mocha/-/mocha-3.5.3.tgz", @@ -2572,12 +2553,6 @@ } } }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, "pako": { "version": "0.2.9", "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", @@ -2587,7 +2562,7 @@ "prettier": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.4.4.tgz", - "integrity": "sha1-qNFEexTJv2fm1CDcrdEPuaT61lo=", + "integrity": "sha512-GuuPazIvjW1DG26yLQgO+nagmRF/h9M4RaCtZWqu/eFW7csdZkQEwPJUeXX10d+LzmCnR9DuIZndqIOn3p2YoA==", "dev": true }, "printj": { @@ -2595,12 +2570,6 @@ "resolved": "https://registry.npmjs.org/printj/-/printj-1.1.0.tgz", "integrity": "sha512-NbiNBOQ0GioHyeD3ni8wZB7ZmfU7mxIrqhWR5XSreX3rUVvk5UOwpzxOnWqrLdCtoBbdQ40sEwC+nXxxjlUo0A==" }, - "private": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", - "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", - "dev": true - }, "process-nextick-args": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", @@ -2630,55 +2599,6 @@ } } }, - "regenerate": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", - "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==", - "dev": true - }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", - "dev": true - }, - "regenerator-transform": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz", - "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==", - "dev": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "private": "0.1.8" - } - }, - "regexpu-core": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", - "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=", - "dev": true, - "requires": { - "regenerate": "1.4.0", - "regjsgen": "0.2.0", - "regjsparser": "0.1.5" - } - }, - "regjsgen": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", - "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", - "dev": true - }, - "regjsparser": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", - "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", - "dev": true, - "requires": { - "jsesc": "0.5.0" - } - }, "rollup": { "version": "0.53.3", "resolved": "https://registry.npmjs.org/rollup/-/rollup-0.53.3.tgz", @@ -3192,12 +3112,6 @@ "integrity": "sha1-/kyEYDl/nqqqWOc75GJzQIpF4iM=", "optional": true }, - "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", - "dev": true - }, "ssf": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.8.2.tgz", @@ -3218,27 +3132,6 @@ "safe-buffer": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.0.tgz" } }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - }, - "to-fast-properties": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", - "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", - "dev": true - }, "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", diff --git a/package.json b/package.json index fc819d9..30dedc7 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "webcharts", "description": "A library for creating flexible, interactive charts", - "version": "1.11.0", + "version": "1.10.0", "keywords": [ "charts", "javascript", @@ -33,7 +33,6 @@ "test-controls": "mocha --timeout 5000 --require babel-register --recursive ./test/controls/*.js", "test-miscellaneous": "mocha --timeout 5000 --require babel-register --recursive ./test/miscellaneous/*.js", "test-multiply": "mocha --timeout 5000 --require babel-register --recursive ./test/multiply/*.js", - "test-new": "mocha --timeout 5000 --require babel-register --recursive ./test/testNewUnitTests.js", "test-table": "mocha --timeout 5000 --require babel-register --recursive ./test/table/*.js", "watch": "rollup -c -w" }, @@ -48,7 +47,7 @@ }, "devDependencies": { "babel-plugin-external-helpers": "^6.22.0", - "babel-preset-env": "^1.7.0", + "babel-preset-es2015": "^6.0.0", "babel-register": "6", "clean-css-cli": "^4.0.0", "expect": "1", diff --git a/rollup.config.js b/rollup.config.js index 994272c..d95bb6d 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,27 +1,21 @@ import babel from 'rollup-plugin-babel'; -var pkg = require('./package.json'); - -module.exports = { - input: pkg.module, +export default { + input: './src/index.js', output: { name: 'webCharts', - file: pkg.main, + file: './build/webcharts.js', format: 'umd', globals: { d3: 'd3' - }, + } }, - external: (function() { - var dependencies = pkg.dependencies; - - return Object.keys(dependencies); - }()), + external: ['d3'], plugins: [ babel({ exclude: 'node_modules/**', presets: [ - [ 'env', {modules: false} ] + [ 'es2015' , {modules: false} ] ], plugins: [ 'external-helpers' @@ -29,4 +23,4 @@ module.exports = { babelrc: false }) ] -}; +} diff --git a/src/chart/init/checkRequired.js b/src/chart/checkRequired.js similarity index 100% rename from src/chart/init/checkRequired.js rename to src/chart/checkRequired.js diff --git a/src/chart/consolidateData.js b/src/chart/consolidateData.js new file mode 100644 index 0000000..db58362 --- /dev/null +++ b/src/chart/consolidateData.js @@ -0,0 +1,110 @@ +import naturalSorter from '../dataOps/naturalSorter'; +import { set, merge, ascending, nest, min, extent } from 'd3'; + +export default function consolidateData(raw) { + let config = this.config; + let all_data = []; + let all_x = []; + let all_y = []; + + this.setDefaults(); + + //apply filters from associated controls objects + this.filtered_data = raw; + if (this.filters.length) { + this.filters.forEach(e => { + this.filtered_data = this.filtered_data.filter(d => { + return e.val === 'All' + ? d + : e.val instanceof Array ? e.val.indexOf(d[e.col]) > -1 : d[e.col] === e.val; + }); + }); + } + + //create data for each set of marks + config.marks.forEach((e, i) => { + if (e.type !== 'bar') { + e.arrange = null; + e.split = null; + } + let mark_info = e.per ? this.transformData(raw, e) : { data: [], x_dom: [], y_dom: [] }; + + all_data.push(mark_info.data); + all_x.push(mark_info.x_dom); + all_y.push(mark_info.y_dom); + this.marks[i] = { + id: e.id, + type: e.type, + per: e.per, + data: mark_info.data, + split: e.split, + text: e.text, + arrange: e.arrange, + order: e.order, + summarizeX: e.summarizeX, + summarizeY: e.summarizeY, + tooltip: e.tooltip, + radius: e.radius, + attributes: e.attributes, + values: e.values + }; + }); + + if (config.x.type === 'ordinal') { + if (config.x.domain) { + this.x_dom = config.x.domain; + } else if (config.x.order) { + this.x_dom = set(merge(all_x)) + .values() + .sort((a, b) => ascending(config.x.order.indexOf(a), config.x.order.indexOf(b))); + } else if (config.x.sort && config.x.sort === 'alphabetical-ascending') { + this.x_dom = set(merge(all_x)).values().sort(naturalSorter); + } else if (config.y.type === 'time' && config.x.sort === 'earliest') { + this.x_dom = nest() + .key(d => d[config.x.column]) + .rollup(d => { + return d.map(m => m[config.y.column]).filter(f => f instanceof Date); + }) + .entries(this.raw_data) + .sort((a, b) => min(b.values) - min(a.values)) + .map(m => m.key); + } else if (!config.x.sort || config.x.sort === 'alphabetical-descending') { + this.x_dom = set(merge(all_x)).values().sort(naturalSorter); + } else { + this.x_dom = set(merge(all_x)).values(); + } + } else if (config.marks.map(m => m.summarizeX === 'percent').indexOf(true) > -1) { + this.x_dom = [0, 1]; + } else { + this.x_dom = extent(merge(all_x)); + } + + if (config.y.type === 'ordinal') { + if (config.y.domain) { + this.y_dom = config.y.domain; + } else if (config.y.order) { + this.y_dom = set(merge(all_y)) + .values() + .sort((a, b) => ascending(config.y.order.indexOf(a), config.y.order.indexOf(b))); + } else if (config.y.sort && config.y.sort === 'alphabetical-ascending') { + this.y_dom = set(merge(all_y)).values().sort(naturalSorter); + } else if (config.x.type === 'time' && config.y.sort === 'earliest') { + this.y_dom = nest() + .key(d => d[config.y.column]) + .rollup(d => { + return d.map(m => m[config.x.column]).filter(f => f instanceof Date); + }) + .entries(this.raw_data) + .sort((a, b) => min(b.values) - min(a.values)) + .map(m => m.key); + } else if (!config.y.sort || config.y.sort === 'alphabetical-descending') { + this.y_dom = set(merge(all_y)).values().sort(naturalSorter).reverse(); + } else { + this.y_dom = set(merge(all_y)).values(); + } + } else if (config.marks.map(m => m.summarizeY === 'percent').indexOf(true) > -1) { + this.y_dom = [0, 1]; + } else { + this.y_dom = extent(merge(all_y)); + } +} diff --git a/src/chart/draw.js b/src/chart/draw.js index f31e7d0..7d23c13 100644 --- a/src/chart/draw.js +++ b/src/chart/draw.js @@ -1,18 +1,19 @@ import { select } from 'd3'; export default function draw(raw_data, processed_data) { - const chart = this; - const config = this.config; - - //if pre-processing callback, run it now - this.events.onPreprocess.call(this); + var context = this; + let config = this.config; + let aspect2 = 1 / config.aspect; ///////////////////////// // Data prep pipeline // ///////////////////////// + //if pre-processing callback, run it now + this.events.onPreprocess.call(this); + // if user passed raw_data to chart.draw(), use that, otherwise use chart.raw_data - const raw = raw_data ? raw_data : this.raw_data ? this.raw_data : []; + let raw = raw_data ? raw_data : this.raw_data ? this.raw_data : []; // warn the user about the perils of "processed_data" if (processed_data) { @@ -22,7 +23,7 @@ export default function draw(raw_data, processed_data) { } //Call consolidateData - this applies filters from controls and prepares data for each set of marks. - this.consolidateData(raw); + let data = processed_data || this.consolidateData(raw); ///////////////////////////// // Prepare scales and axes // @@ -33,14 +34,14 @@ export default function draw(raw_data, processed_data) { this.setColorScale(); let max_width = config.max_width ? config.max_width : div_width; - this.raw_width = config.x.type === 'ordinal' && +config.x.range_band - ? (+config.x.range_band + config.x.range_band * config.padding) * this.x_dom.length + this.raw_width = config.x.type === 'ordinal' && +config.range_band + ? (+config.range_band + config.range_band * config.padding) * this.x_dom.length : config.resizable ? max_width : config.width ? config.width : div_width; - this.raw_height = config.y.type === 'ordinal' && +config.y.range_band - ? (+config.y.range_band + config.y.range_band * config.padding) * this.y_dom.length + this.raw_height = config.y.type === 'ordinal' && +config.range_band + ? (+config.range_band + config.range_band * config.padding) * this.y_dom.length : config.resizable - ? max_width * (1 / config.aspect) - : config.height ? config.height : div_width * (1 / config.aspect); + ? max_width * aspect2 + : config.height ? config.height : div_width * aspect2; let pseudo_width = this.svg.select('.overlay').attr('width') ? this.svg.select('.overlay').attr('width') @@ -64,11 +65,11 @@ export default function draw(raw_data, processed_data) { this.yScaleAxis(pseudo_height); if (config.resizable && typeof window !== 'undefined') { - select(window).on('resize.' + this.element + this.id, function() { - chart.resize(); + select(window).on('resize.' + context.element + context.id, function() { + context.resize(); }); } else if (typeof window !== 'undefined') { - select(window).on('resize.' + this.element + this.id, null); + select(window).on('resize.' + context.element + context.id, null); } this.events.onDraw.call(this); diff --git a/src/chart/draw/consolidateData.js b/src/chart/draw/consolidateData.js deleted file mode 100644 index 8d48e2d..0000000 --- a/src/chart/draw/consolidateData.js +++ /dev/null @@ -1,60 +0,0 @@ -import naturalSorter from '../../dataOps/naturalSorter'; -import { set, merge, ascending, nest, min, extent } from 'd3'; -import setDomain from './consolidateData/setDomain'; - -export default function consolidateData(raw) { - this.setDefaults(); - - //Apply filters from associated controls objects to raw data. - this.filtered_data = raw; - if (this.filters.length) { - this.filters.forEach(filter => { - this.filtered_data = this.filtered_data.filter(d => { - return filter.val === 'All' - ? d - : filter.val instanceof Array - ? filter.val.indexOf(d[filter.col]) > -1 - : d[filter.col] === filter.val; - }); - }); - } - - //Summarize data for each mark. - this.config.marks.forEach((mark, i) => { - if (mark.type !== 'bar') { - mark.arrange = null; - mark.split = null; - } - - const mark_info = mark.per - ? this.transformData(raw, mark) - : { - data: [], - x_dom: [], - y_dom: [] - }; - - this.marks[i] = { - id: mark.id, - type: mark.type, - per: mark.per, - data: mark_info.data, - x_dom: mark_info.x_dom, - y_dom: mark_info.y_dom, - split: mark.split, - text: mark.text, - arrange: mark.arrange, - order: mark.order, - summarizeX: mark.summarizeX, - summarizeY: mark.summarizeY, - tooltip: mark.tooltip, - radius: mark.radius, - attributes: mark.attributes, - values: mark.values - }; - }); - - //Set domains given extents of summarized mark data. - setDomain.call(this, 'x'); - setDomain.call(this, 'y'); -} diff --git a/src/chart/draw/consolidateData/setDomain.js b/src/chart/draw/consolidateData/setDomain.js deleted file mode 100644 index c9ba5b8..0000000 --- a/src/chart/draw/consolidateData/setDomain.js +++ /dev/null @@ -1,84 +0,0 @@ -import naturalSorter from '../../../dataOps/naturalSorter'; -import { set, merge, ascending, nest, extent } from 'd3'; - -export default function setDomain(axis) { - const otherAxis = axis === 'x' ? 'y' : 'x'; - - if (this.config[axis].type === 'ordinal') { - //ordinal domains - if (this.config[axis].domain) { - //user-defined domain - this[axis + '_dom'] = this.config[axis].domain; - } else if (this.config[axis].order) { - //data-driven domain with user-defined domain order - this[axis + '_dom'] = set(merge(this.marks.map(mark => mark[axis + '_dom']))) - .values() - .sort((a, b) => - ascending( - this.config[axis].order.indexOf(a), - this.config[axis].order.indexOf(b) - ) - ); - } else if (this.config[axis].sort && this.config[axis].sort === 'alphabetical-ascending') { - //data-driven domain with user-defined domain sort algorithm that sorts the axis - //alphanumerically, first to last - this[axis + '_dom'] = set(merge(this.marks.map(mark => mark[axis + '_dom']))) - .values() - .sort(naturalSorter); - } else if ( - ['time', 'linear'].indexOf(this.config[otherAxis].type) > -1 && - this.config[axis].sort === 'earliest' - ) { - //data-driven domain plotted against a time or linear axis that sorts the axis values - //by earliest event/datum; generally used with timeline charts - this[axis + '_dom'] = nest() - .key(d => d[this.config[axis].column]) - .rollup(d => { - return d - .map(m => m[this.config[otherAxis].column]) - .filter(f => f instanceof Date); - }) - .entries(this.raw_data) - .sort((a, b) => min(b.values) - min(a.values)) - .map(m => m.key); - } else if ( - !this.config[axis].sort || - this.config[axis].sort === 'alphabetical-descending' - ) { - //data-driven domain with default/user-defined domain sort algorithm that sorts the - //axis alphanumerically, last to first - this[axis + '_dom'] = set(merge(this.marks.map(mark => mark[axis + '_dom']))) - .values() - .sort(naturalSorter) - .reverse(); - } else { - //data-driven domain with an invalid user-defined sort algorithm that captures a unique - //set of values as they appear in the data - this[axis + '_dom'] = set(merge(this.marks.map(mark => mark[axis + '_dom']))).values(); - } - } else if ( - this.config.marks - .map(m => m['summarize' + otherAxis.toUpperCase()] === 'percent') - .indexOf(true) > -1 - ) { - //rate domains run from 0 to 1 - this[axis + '_dom'] = [0, 1]; - } else { - //continuous domains run from the minimum to the maximum raw value - //TODO: they should really run from the minimum to the maximum summarized value, e.g. a - //TODO: means over time chart should plot over the range of the means, not the range of the - //TODO: raw data - this[axis + '_dom'] = extent(merge(this.marks.map(mark => mark[axis + '_dom']))); - } - - //Give the domain a range when the range of the variable is 0. - if (this.config[axis].type === 'linear' && this[axis + '_dom'][0] === this[axis + '_dom'][1]) - this[axis + '_dom'] = this[axis + '_dom'][0] !== 0 - ? [ - this[axis + '_dom'][0] - this[axis + '_dom'][0] * 0.01, - this[axis + '_dom'][1] + this[axis + '_dom'][1] * 0.01 - ] - : [-1, 1]; - - return this[axis + '_dom']; -} diff --git a/src/chart/draw/consolidateData/transformData.js b/src/chart/draw/consolidateData/transformData.js deleted file mode 100644 index 356e36b..0000000 --- a/src/chart/draw/consolidateData/transformData.js +++ /dev/null @@ -1,188 +0,0 @@ -import cleanData from './transformData/cleanData'; -import makeNest from './transformData/makeNest'; -import { set, extent, merge } from 'd3'; - -////////////////////////////////////////////////////////// -// transformData(raw, mark) provides specifications and data for -// each set of marks. As such, it is called once for each -// item specified in the config.marks array. -// -// parameters -// raw - the raw data for use in the mark. Filters from controls -// are typically already applied. -// mark - a single mark object from config.marks -//////////////////////////////////////////////////////// - -export default function transformData(raw, mark) { - //convenience mappings - const config = this.config; - const x_behavior = config.x.behavior || 'raw'; - const y_behavior = config.y.behavior || 'raw'; - const sublevel = mark.type === 'line' - ? config.x.column - : mark.type === 'bar' && mark.split ? mark.split : null; - - ////////////////////////////////////////////////////////////////////////////////// - // DATA PREP - // prepare data based on the properties of the mark - drop missing records, etc - ////////////////////////////////////////////////////////////////////////////////// - const cleaned = cleanData.call(this, mark, raw); - - //prepare nested data required for bar charts - let raw_nest; - if (mark.type === 'bar') { - raw_nest = mark.arrange !== 'stacked' - ? makeNest.call(this, mark, cleaned, sublevel) - : makeNest.call(this, mark, cleaned); - } else if (mark.summarizeX === 'count' || mark.summarizeY === 'count') { - raw_nest = makeNest.call(this, mark, cleaned); - } - - // Get the domain for the mark based on the raw data - let raw_dom_x = mark.summarizeX === 'cumulative' - ? [0, cleaned.length] - : config.x.type === 'ordinal' - ? set(cleaned.map(m => m[config.x.column])).values().filter(f => f) - : mark.split && mark.arrange !== 'stacked' - ? extent(merge(raw_nest.nested.map(m => m.values.map(p => p.values.raw.length)))) - : mark.summarizeX === 'count' - ? extent(raw_nest.nested.map(m => m.values.raw.length)) - : extent(cleaned.map(m => +m[config.x.column]).filter(f => +f || +f === 0)); - - let raw_dom_y = mark.summarizeY === 'cumulative' - ? [0, cleaned.length] - : config.y.type === 'ordinal' - ? set(cleaned.map(m => m[config.y.column])).values().filter(f => f) - : mark.split && mark.arrange !== 'stacked' - ? extent(merge(raw_nest.nested.map(m => m.values.map(p => p.values.raw.length)))) - : mark.summarizeY === 'count' - ? extent(raw_nest.nested.map(m => m.values.raw.length)) - : extent(cleaned.map(m => +m[config.y.column]).filter(f => +f || +f === 0)); - - let filtered = cleaned; - - let filt1_xs = []; - let filt1_ys = []; - if (this.filters.length) { - this.filters.forEach(e => { - filtered = filtered.filter(d => { - return e.val === 'All' - ? d - : e.val instanceof Array ? e.val.indexOf(d[e.col]) > -1 : d[e.col] === e.val; - }); - }); - //get domain for all non-All values of first filter - if (config.x.behavior === 'firstfilter' || config.y.behavior === 'firstfilter') { - this.filters[0].choices.filter(f => f !== 'All').forEach(e => { - let perfilter = cleaned.filter(f => f[this.filters[0].col] === e); - let filt_nested = makeNest.call(this, mark, perfilter, sublevel); - filt1_xs.push(filt_nested.dom_x); - filt1_ys.push(filt_nested.dom_y); - }); - } - } - - //filter on mark-specific instructions - if (mark.values) { - for (let a in mark.values) { - filtered = filtered.filter(f => { - return mark.values[a].indexOf(f[a]) > -1; - }); - } - } - let filt1_dom_x = extent(merge(filt1_xs)); - let filt1_dom_y = extent(merge(filt1_ys)); - - let current_nested = makeNest.call(this, mark, filtered, sublevel); - - let flex_dom_x = current_nested.dom_x; - let flex_dom_y = current_nested.dom_y; - - if (mark.type === 'bar') { - if (config.y.type === 'ordinal' && mark.summarizeX === 'count') { - config.x.domain = config.x.domain ? [0, config.x.domain[1]] : [0, null]; - } else if (config.x.type === 'ordinal' && mark.summarizeY === 'count') { - config.y.domain = config.y.domain ? [0, config.y.domain[1]] : [0, null]; - } - } - - //several criteria must be met in order to use the 'firstfilter' domain - let nonall = Boolean( - this.filters.length && - this.filters[0].val !== 'All' && - this.filters.slice(1).filter(f => f.val === 'All').length === this.filters.length - 1 - ); - - let pre_x_dom = !this.filters.length - ? flex_dom_x - : x_behavior === 'raw' - ? raw_dom_x - : nonall && x_behavior === 'firstfilter' ? filt1_dom_x : flex_dom_x; - let pre_y_dom = !this.filters.length - ? flex_dom_y - : y_behavior === 'raw' - ? raw_dom_y - : nonall && y_behavior === 'firstfilter' ? filt1_dom_y : flex_dom_y; - - let x_dom = config.x_dom - ? config.x_dom - : config.x.type === 'ordinal' && config.x.behavior === 'flex' - ? set(filtered.map(m => m[config.x.column])).values() - : config.x.type === 'ordinal' - ? set(cleaned.map(m => m[config.x.column])).values() - : pre_x_dom; - - let y_dom = config.y_dom - ? config.y_dom - : config.y.type === 'ordinal' && config.y.behavior === 'flex' - ? set(filtered.map(m => m[config.y.column])).values() - : config.y.type === 'ordinal' - ? set(cleaned.map(m => m[config.y.column])).values() - : pre_y_dom; - - //set lower limit of linear domain to 0 when other axis is ordinal and mark type is set to 'bar', provided no values are negative - if (mark.type === 'bar') { - if ( - config.x.behavior !== 'flex' && - config.x.type === 'linear' && - config.y.type === 'ordinal' && - raw_dom_x[0] >= 0 - ) - x_dom[0] = 0; - - if ( - config.y.behavior !== 'flex' && - config.x.type === 'ordinal' && - config.y.type === 'linear' && - raw_dom_y[0] >= 0 - ) - y_dom[0] = 0; - } - - //update domains with those specified in the config - if (config.x.domain && (config.x.domain[0] || config.x.domain[0] === 0)) { - x_dom[0] = config.x.domain[0]; - } - if (config.x.domain && (config.x.domain[1] || config.x.domain[1] === 0)) { - x_dom[1] = config.x.domain[1]; - } - if (config.y.domain && (config.y.domain[0] || config.y.domain[0] === 0)) { - y_dom[0] = config.y.domain[0]; - } - if (config.y.domain && (config.y.domain[1] || config.y.domain[1] === 0)) { - y_dom[1] = config.y.domain[1]; - } - - if (config.x.type === 'ordinal' && !config.x.order) { - config.x.order = current_nested.totalOrder; - } - if (config.y.type === 'ordinal' && !config.y.order) { - config.y.order = current_nested.totalOrder; - } - - this.current_data = current_nested.nested; - - this.events.onDatatransform.call(this); - - return { config: mark, data: current_nested.nested, x_dom: x_dom, y_dom: y_dom }; -} diff --git a/src/chart/draw/consolidateData/transformData/cleanData.js b/src/chart/draw/consolidateData/transformData/cleanData.js deleted file mode 100644 index 808802c..0000000 --- a/src/chart/draw/consolidateData/transformData/cleanData.js +++ /dev/null @@ -1,63 +0,0 @@ -import { time } from 'd3'; - -export default function cleanData(mark, raw) { - const dateConvert = time.format(this.config.date_format); - let clean = raw; - // only use data for the current mark - clean = mark.per && mark.per.length ? clean.filter(f => f[mark.per[0]] !== undefined) : clean; - - // Make sure data has x and y values - if (this.config.x.column) { - clean = clean.filter(f => [undefined, null].indexOf(f[this.config.x.column]) < 0); - } - if (this.config.y.column) { - clean = clean.filter(f => [undefined, null].indexOf(f[this.config.y.column]) < 0); - } - - //check that x and y have the correct formats - if (this.config.x.type === 'time') { - clean = clean.filter( - f => - f[this.config.x.column] instanceof Date - ? f[this.config.x.column] - : dateConvert.parse(f[this.config.x.column]) - ); - clean.forEach( - e => - (e[this.config.x.column] = e[this.config.x.column] instanceof Date - ? e[this.config.x.column] - : dateConvert.parse(e[this.config.x.column])) - ); - } - if (this.config.y.type === 'time') { - clean = clean.filter( - f => - f[this.config.y.column] instanceof Date - ? f[this.config.y.column] - : dateConvert.parse(f[this.config.y.column]) - ); - clean.forEach( - e => - (e[this.config.y.column] = e[this.config.y.column] instanceof Date - ? e[this.config.y.column] - : dateConvert.parse(e[this.config.y.column])) - ); - } - - if ((this.config.x.type === 'linear' || this.config.x.type === 'log') && this.config.x.column) { - clean = clean.filter(f => { - return mark.summarizeX !== 'count' && mark.summarizeX !== 'percent' - ? !(isNaN(f[this.config.x.column]) || /^\s*$/.test(f[this.config.x.column])) // is or coerces to a number and is not a string that coerces to 0 - : f; - }); - } - if ((this.config.y.type === 'linear' || this.config.y.type === 'log') && this.config.y.column) { - clean = clean.filter(f => { - return mark.summarizeY !== 'count' && mark.summarizeY !== 'percent' - ? !(isNaN(f[this.config.y.column]) || /^\s*$/.test(f[this.config.y.column])) // is or coerces to a number and is not a string that coerces to 0 - : f; - }); - } - - return clean; -} diff --git a/src/chart/draw/consolidateData/transformData/makeNest.js b/src/chart/draw/consolidateData/transformData/makeNest.js deleted file mode 100644 index eacdd38..0000000 --- a/src/chart/draw/consolidateData/transformData/makeNest.js +++ /dev/null @@ -1,175 +0,0 @@ -import { nest, scale, extent, range, ascending, quantile, sum, merge, descending } from 'd3'; -import naturalSorter from '../../../../dataOps/naturalSorter'; -import summarize from '../../../../dataOps/summarize'; - -export default function makeNest(mark, entries, sublevel) { - let dom_xs = []; - let dom_ys = []; - let this_nest = nest(); - let totalOrder; - - if ( - (this.config.x.type === 'linear' && this.config.x.bin) || - (this.config.y.type === 'linear' && this.config.y.bin) - ) { - let xy = this.config.x.type === 'linear' && this.config.x.bin ? 'x' : 'y'; - let quant = scale - .quantile() - .domain(extent(entries.map(m => +m[this.config[xy].column]))) - .range(range(+this.config[xy].bin)); - - entries.forEach(e => (e.wc_bin = quant(e[this.config[xy].column]))); - - this_nest.key(d => quant.invertExtent(d.wc_bin)); - } else { - this_nest.key(d => mark.per.map(m => d[m]).join(' ')); - } - - if (sublevel) { - this_nest.key(d => d[sublevel]); - this_nest.sortKeys((a, b) => { - return this.config.x.type === 'time' - ? ascending(new Date(a), new Date(b)) - : this.config.x.order - ? ascending(this.config.x.order.indexOf(a), this.config.x.order.indexOf(b)) - : sublevel === this.config.color_by && this.config.legend.order - ? ascending( - this.config.legend.order.indexOf(a), - this.config.legend.order.indexOf(b) - ) - : this.config.x.type === 'ordinal' || this.config.y.type === 'ordinal' - ? naturalSorter(a, b) - : ascending(+a, +b); - }); - } - this_nest.rollup(r => { - let obj = { raw: r }; - let y_vals = r.map(m => m[this.config.y.column]).sort(ascending); - let x_vals = r.map(m => m[this.config.x.column]).sort(ascending); - obj.x = this.config.x.type === 'ordinal' - ? r[0][this.config.x.column] - : summarize(x_vals, mark.summarizeX); - obj.y = this.config.y.type === 'ordinal' - ? r[0][this.config.y.column] - : summarize(y_vals, mark.summarizeY); - - obj.x_q25 = this.config.error_bars && this.config.y.type === 'ordinal' - ? quantile(x_vals, 0.25) - : obj.x; - obj.x_q75 = this.config.error_bars && this.config.y.type === 'ordinal' - ? quantile(x_vals, 0.75) - : obj.x; - obj.y_q25 = this.config.error_bars ? quantile(y_vals, 0.25) : obj.y; - obj.y_q75 = this.config.error_bars ? quantile(y_vals, 0.75) : obj.y; - dom_xs.push([obj.x_q25, obj.x_q75, obj.x]); - dom_ys.push([obj.y_q25, obj.y_q75, obj.y]); - - if (mark.summarizeY === 'cumulative') { - let interm = entries.filter(f => { - return this.config.x.type === 'time' - ? new Date(f[this.config.x.column]) <= new Date(r[0][this.config.x.column]) - : +f[this.config.x.column] <= +r[0][this.config.x.column]; - }); - if (mark.per.length) { - interm = interm.filter(f => f[mark.per[0]] === r[0][mark.per[0]]); - } - - let cumul = this.config.x.type === 'time' - ? interm.length - : sum( - interm.map( - m => - +m[this.config.y.column] || +m[this.config.y.column] === 0 - ? +m[this.config.y.column] - : 1 - ) - ); - dom_ys.push([cumul]); - obj.y = cumul; - } - if (mark.summarizeX === 'cumulative') { - let interm = entries.filter(f => { - return this.config.y.type === 'time' - ? new Date(f[this.config.y.column]) <= new Date(r[0][this.config.y.column]) - : +f[this.config.y.column] <= +r[0][this.config.y.column]; - }); - if (mark.per.length) { - interm = interm.filter(f => f[mark.per[0]] === r[0][mark.per[0]]); - } - dom_xs.push([interm.length]); - obj.x = interm.length; - } - - return obj; - }); - - let test = this_nest.entries(entries); - - let dom_x = extent(merge(dom_xs)); - let dom_y = extent(merge(dom_ys)); - - if (sublevel && mark.type === 'bar' && mark.split) { - //calculate percentages in bars - test.forEach(e => { - let axis = this.config.x.type === 'ordinal' || - (this.config.x.type === 'linear' && this.config.x.bin) - ? 'y' - : 'x'; - e.total = sum(e.values.map(m => +m.values[axis])); - let counter = 0; - e.values.forEach((v, i) => { - if ( - this.config.x.type === 'ordinal' || - (this.config.x.type === 'linear' && this.config.x.bin) - ) { - v.values.y = mark.summarizeY === 'percent' - ? v.values.y / e.total - : v.values.y || 0; - counter += +v.values.y; - v.values.start = e.values[i - 1] ? counter : v.values.y; - } else { - v.values.x = mark.summarizeX === 'percent' - ? v.values.x / e.total - : v.values.x || 0; - v.values.start = counter; - counter += +v.values.x; - } - }); - }); - - if (mark.arrange === 'stacked') { - if ( - this.config.x.type === 'ordinal' || - (this.config.x.type === 'linear' && this.config.x.bin) - ) { - dom_y = extent(test.map(m => m.total)); - } - if ( - this.config.y.type === 'ordinal' || - (this.config.y.type === 'linear' && this.config.y.bin) - ) { - dom_x = extent(test.map(m => m.total)); - } - } - } else { - let axis = this.config.x.type === 'ordinal' || - (this.config.x.type === 'linear' && this.config.x.bin) - ? 'y' - : 'x'; - test.forEach(e => (e.total = e.values[axis])); - } - - if ( - (this.config.x.sort === 'total-ascending' && this.config.x.type == 'ordinal') || - (this.config.y.sort === 'total-descending' && this.config.y.type == 'ordinal') - ) { - totalOrder = test.sort((a, b) => ascending(a.total, b.total)).map(m => m.key); - } else if ( - (this.config.x.sort === 'total-descending' && this.config.x.type == 'ordinal') || - (this.config.y.sort === 'total-ascending' && this.config.y.type == 'ordinal') - ) { - totalOrder = test.sort((a, b) => descending(+a.total, +b.total)).map(m => m.key); - } - - return { nested: test, dom_x: dom_x, dom_y: dom_y, totalOrder: totalOrder }; -} diff --git a/src/chart/resize/updateDataMarks/drawArea.js b/src/chart/drawArea.js similarity index 100% rename from src/chart/resize/updateDataMarks/drawArea.js rename to src/chart/drawArea.js diff --git a/src/chart/resize/updateDataMarks/drawBars.js b/src/chart/drawBars.js similarity index 99% rename from src/chart/resize/updateDataMarks/drawBars.js rename to src/chart/drawBars.js index bfd8bb2..8384479 100644 --- a/src/chart/resize/updateDataMarks/drawBars.js +++ b/src/chart/drawBars.js @@ -60,7 +60,7 @@ export default function drawBars(marks) { bars.each(function(d) { let mark = select(this.parentNode.parentNode).datum(); d.tooltip = mark.tooltip; - d.arrange = mark.split && mark.arrange ? mark.arrange : mark.split ? 'grouped' : null; + d.arrange = mark.split ? mark.arrange : null; d.subcats = config.legend.order ? config.legend.order.slice().reverse() : mark.values && mark.values[mark.split] @@ -163,7 +163,6 @@ export default function drawBars(marks) { ? mark.values[mark.split] : set(rawData.map(m => m[mark.split])).values(); d.tooltip = mark.tooltip; - select(this).attr(mark.attributes); }); let xformat = config.marks.map(m => m.summarizeX === 'percent').indexOf(true) > -1 diff --git a/src/chart/resize/drawGridlines.js b/src/chart/drawGridlines.js similarity index 100% rename from src/chart/resize/drawGridlines.js rename to src/chart/drawGridlines.js diff --git a/src/chart/resize/updateDataMarks/drawLines.js b/src/chart/drawLines.js similarity index 100% rename from src/chart/resize/updateDataMarks/drawLines.js rename to src/chart/drawLines.js diff --git a/src/chart/resize/updateDataMarks/drawPoints.js b/src/chart/drawPoints.js similarity index 100% rename from src/chart/resize/updateDataMarks/drawPoints.js rename to src/chart/drawPoints.js diff --git a/src/chart/resize/updateDataMarks/drawText.js b/src/chart/drawText.js similarity index 100% rename from src/chart/resize/updateDataMarks/drawText.js rename to src/chart/drawText.js diff --git a/src/chart/index.js b/src/chart/index.js index ea453ad..0f1c897 100644 --- a/src/chart/index.js +++ b/src/chart/index.js @@ -1,29 +1,25 @@ +import checkRequired from './checkRequired'; +import consolidateData from './consolidateData'; +import destroy from './destroy'; +import draw from './draw'; +import drawArea from './drawArea'; +import drawBars from './drawBars'; +import drawGridlines from './drawGridlines'; +import drawLines from './drawLines'; +import drawPoints from './drawPoints'; +import drawText from './drawText'; import init from './init'; -import checkRequired from './init/checkRequired'; - import layout from './layout'; - -import draw from './draw'; -import consolidateData from './draw/consolidateData'; -import setDefaults from './draw/consolidateData/setDefaults'; -import transformData from './draw/consolidateData/transformData'; -import setColorScale from './draw/setColorScale'; -import xScaleAxis from './draw/xScaleAxis'; -import yScaleAxis from './draw/yScaleAxis'; - +import makeLegend from './makeLegend'; import resize from './resize'; -import textSize from './resize/textSize'; -import setMargins from './resize/setMargins'; -import drawGridlines from './resize/drawGridlines'; -import makeLegend from './resize/makeLegend'; -import updateDataMarks from './resize/updateDataMarks'; -import drawArea from './resize/updateDataMarks/drawArea'; -import drawBars from './resize/updateDataMarks/drawBars'; -import drawLines from './resize/updateDataMarks/drawLines'; -import drawPoints from './resize/updateDataMarks/drawPoints'; -import drawText from './resize/updateDataMarks/drawText'; - -import destroy from './destroy'; +import setColorScale from './setColorScale'; +import setDefaults from './setDefaults'; +import setMargins from './setMargins'; +import textSize from './textSize'; +import transformData from './transformData'; +import updateDataMarks from './updateDataMarks'; +import xScaleAxis from './xScaleAxis'; +import yScaleAxis from './yScaleAxis'; const chartProto = { raw_data: [], diff --git a/src/chart/layout.js b/src/chart/layout.js index aa14740..2b775ce 100644 --- a/src/chart/layout.js +++ b/src/chart/layout.js @@ -55,14 +55,12 @@ export default function layout() { .attr('fill', 'none') .style('pointer-events', 'all'); //add legend - if (!this.parent) - this.wrap - .append('ul') - .datum(() => null) // prevent data inheritance - .attr('class', 'legend') - .style('vertical-align', 'top') - .append('span') - .attr('class', 'legend-title'); + const legend = this.wrap.append('ul').datum(() => null); // prevent data inheritance + legend + .attr('class', 'legend') + .style('vertical-align', 'top') + .append('span') + .attr('class', 'legend-title'); select(this.div).select('.loader').remove(); diff --git a/src/chart/resize/makeLegend.js b/src/chart/makeLegend.js similarity index 77% rename from src/chart/resize/makeLegend.js rename to src/chart/makeLegend.js index e83d936..1efaf8d 100644 --- a/src/chart/resize/makeLegend.js +++ b/src/chart/makeLegend.js @@ -16,24 +16,11 @@ export default function makeLegend(scale = this.colorScale, label = '', custom_d let legendOriginal = this.legend || this.wrap.select('.legend'); let legend = legendOriginal; - if (!this.parent) { - //singular chart - if (this.config.legend.location === 'top' || this.config.legend.location === 'left') { - this.wrap.node().insertBefore(legendOriginal.node(), this.svg.node().parentNode); - } else { - this.wrap.node().appendChild(legendOriginal.node()); - } + if (this.config.legend.location === 'top' || this.config.legend.location === 'left') { + this.wrap.node().insertBefore(legendOriginal.node(), this.svg.node().parentNode); } else { - //multiples - keep legend outside of individual charts' wraps - if (this.config.legend.location === 'top' || this.config.legend.location === 'left') { - this.parent.wrap - .node() - .insertBefore(legendOriginal.node(), this.parent.wrap.select('.wc-chart').node()); - } else { - this.parent.wrap.node().appendChild(legendOriginal.node()); - } + this.wrap.node().appendChild(legendOriginal.node()); } - legend.style('padding', 0); let legend_data = @@ -84,7 +71,9 @@ export default function makeLegend(scale = this.colorScale, label = '', custom_d leg_parts.selectAll('.legend-color-block').each(function(e) { let svg = select(this); if (e.mark === 'circle') { - svg.append('circle').attr({ cx: '.5em', cy: '.5em', r: '.45em', class: 'legend-mark' }); + svg + .append('circle') + .attr({ cx: '.5em', cy: '.45em', r: '.45em', class: 'legend-mark' }); } else if (e.mark === 'line') { svg.append('line').attr({ x1: 0, @@ -120,9 +109,8 @@ export default function makeLegend(scale = this.colorScale, label = '', custom_d .text(d => d.label); if (scale.domain().length > 0) { - const legendDisplay = (this.config.legend.location === 'bottom' || - this.config.legend.location === 'top') && - !this.parent + const legendDisplay = this.config.legend.location === 'bottom' || + this.config.legend.location === 'top' ? 'block' : 'inline-block'; legend.style('display', legendDisplay); diff --git a/src/chart/resize.js b/src/chart/resize.js index c22f3c0..d887139 100644 --- a/src/chart/resize.js +++ b/src/chart/resize.js @@ -14,13 +14,13 @@ export default function resize() { this.margin = this.setMargins(); - let svg_width = config.x.type === 'ordinal' && +config.x.range_band + let svg_width = config.x.type === 'ordinal' && +config.range_band ? this.raw_width + this.margin.left + this.margin.right : !config.resizable ? this.raw_width : !config.max_width || div_width < config.max_width ? div_width : this.raw_width; this.plot_width = svg_width - this.margin.left - this.margin.right; - var svg_height = config.y.type === 'ordinal' && +config.y.range_band + var svg_height = config.y.type === 'ordinal' && +config.range_band ? this.raw_height + this.margin.top + this.margin.bottom : !config.resizable && config.height ? config.height @@ -75,7 +75,6 @@ export default function resize() { .attr({ stroke: '#eee', 'stroke-width': 1, 'shape-rendering': 'crispEdges' }); this.drawGridlines(); - //update legend - margins need to be set first this.makeLegend(); diff --git a/src/chart/draw/setColorScale.js b/src/chart/setColorScale.js similarity index 92% rename from src/chart/draw/setColorScale.js rename to src/chart/setColorScale.js index eb9ac71..4db2362 100644 --- a/src/chart/draw/setColorScale.js +++ b/src/chart/setColorScale.js @@ -1,4 +1,4 @@ -import naturalSorter from '../../dataOps/naturalSorter'; +import naturalSorter from '../dataOps/naturalSorter'; import { set, ascending, scale } from 'd3'; export default function setColorScale() { diff --git a/src/chart/draw/consolidateData/setDefaults.js b/src/chart/setDefaults.js similarity index 92% rename from src/chart/draw/consolidateData/setDefaults.js rename to src/chart/setDefaults.js index 9c4d85f..90f4a5d 100644 --- a/src/chart/draw/consolidateData/setDefaults.js +++ b/src/chart/setDefaults.js @@ -15,9 +15,6 @@ export default function setDefaults() { this.config.x.type = this.config.x.type || 'linear'; this.config.y.type = this.config.y.type || 'linear'; - this.config.x.range_band = this.config.x.range_band || this.config.range_band; - this.config.y.range_band = this.config.y.range_band || this.config.range_band; - this.config.margin = this.config.margin || {}; this.config.legend = this.config.legend || {}; this.config.legend.label = this.config.legend.label !== undefined diff --git a/src/chart/resize/setMargins.js b/src/chart/setMargins.js similarity index 100% rename from src/chart/resize/setMargins.js rename to src/chart/setMargins.js diff --git a/src/chart/resize/textSize.js b/src/chart/textSize.js similarity index 100% rename from src/chart/resize/textSize.js rename to src/chart/textSize.js diff --git a/src/chart/transformData.js b/src/chart/transformData.js new file mode 100644 index 0000000..a123f52 --- /dev/null +++ b/src/chart/transformData.js @@ -0,0 +1,392 @@ +import naturalSorter from '../dataOps/naturalSorter'; +import summarize from '../dataOps/summarize'; +import { + time, + sum, + set, + extent, + merge, + nest, + scale, + range, + ascending, + descending, + quantile, + max +} from 'd3'; + +////////////////////////////////////////////////////////// +// transformData(raw, mark) provides specifications and data for +// each set of marks. As such, it is called once for each +// item specified in the config.marks array. +// +// parameters +// raw - the raw data for use in the mark. Filters from controls +// are typically already applied. +// mark - a single mark object from config.marks +//////////////////////////////////////////////////////// + +export default function transformData(raw, mark) { + //convenience mappings + let config = this.config; + let x_behavior = config.x.behavior || 'raw'; + let y_behavior = config.y.behavior || 'raw'; + let sublevel = mark.type === 'line' + ? config.x.column + : mark.type === 'bar' && mark.split ? mark.split : null; + let dateConvert = time.format(config.date_format); + let totalOrder; + + /////////////////////////////////////////////// + // calcStartTotal() - method to calculate percentages in bars + ////////////////////////////////////////////// + function calcStartTotal(e) { + let axis = config.x.type === 'ordinal' || (config.x.type === 'linear' && config.x.bin) + ? 'y' + : 'x'; + e.total = sum(e.values.map(m => +m.values[axis])); + let counter = 0; + e.values.forEach((v, i) => { + if (config.x.type === 'ordinal' || (config.x.type === 'linear' && config.x.bin)) { + v.values.y = mark.summarizeY === 'percent' ? v.values.y / e.total : v.values.y || 0; + counter += +v.values.y; + v.values.start = e.values[i - 1] ? counter : v.values.y; + } else { + v.values.x = mark.summarizeX === 'percent' ? v.values.x / e.total : v.values.x || 0; + v.values.start = counter; + counter += +v.values.x; + } + }); + } + + function makeNest(entries, sublevel) { + let dom_xs = []; + let dom_ys = []; + let this_nest = nest(); + + if ( + (config.x.type === 'linear' && config.x.bin) || + (config.y.type === 'linear' && config.y.bin) + ) { + let xy = config.x.type === 'linear' && config.x.bin ? 'x' : 'y'; + let quant = scale + .quantile() + .domain(extent(entries.map(m => +m[config[xy].column]))) + .range(range(+config[xy].bin)); + + entries.forEach(e => (e.wc_bin = quant(e[config[xy].column]))); + + this_nest.key(d => quant.invertExtent(d.wc_bin)); + } else { + this_nest.key(d => mark.per.map(m => d[m]).join(' ')); + } + + if (sublevel) { + this_nest.key(d => d[sublevel]); + this_nest.sortKeys((a, b) => { + return config.x.type === 'time' + ? ascending(new Date(a), new Date(b)) + : config.x.order + ? ascending(config.x.order.indexOf(a), config.x.order.indexOf(b)) + : sublevel === config.color_by && config.legend.order + ? ascending(config.legend.order.indexOf(a), config.legend.order.indexOf(b)) + : config.x.type === 'ordinal' || config.y.type === 'ordinal' + ? naturalSorter(a, b) + : ascending(+a, +b); + }); + } + this_nest.rollup(r => { + let obj = { raw: r }; + let y_vals = r.map(m => m[config.y.column]).sort(ascending); + let x_vals = r.map(m => m[config.x.column]).sort(ascending); + obj.x = config.x.type === 'ordinal' + ? r[0][config.x.column] + : summarize(x_vals, mark.summarizeX); + obj.y = config.y.type === 'ordinal' + ? r[0][config.y.column] + : summarize(y_vals, mark.summarizeY); + + obj.x_q25 = config.error_bars && config.y.type === 'ordinal' + ? quantile(x_vals, 0.25) + : obj.x; + obj.x_q75 = config.error_bars && config.y.type === 'ordinal' + ? quantile(x_vals, 0.75) + : obj.x; + obj.y_q25 = config.error_bars ? quantile(y_vals, 0.25) : obj.y; + obj.y_q75 = config.error_bars ? quantile(y_vals, 0.75) : obj.y; + dom_xs.push([obj.x_q25, obj.x_q75, obj.x]); + dom_ys.push([obj.y_q25, obj.y_q75, obj.y]); + + if (mark.summarizeY === 'cumulative') { + let interm = entries.filter(f => { + return config.x.type === 'time' + ? new Date(f[config.x.column]) <= new Date(r[0][config.x.column]) + : +f[config.x.column] <= +r[0][config.x.column]; + }); + if (mark.per.length) { + interm = interm.filter(f => f[mark.per[0]] === r[0][mark.per[0]]); + } + + let cumul = config.x.type === 'time' + ? interm.length + : sum( + interm.map( + m => + +m[config.y.column] || +m[config.y.column] === 0 + ? +m[config.y.column] + : 1 + ) + ); + dom_ys.push([cumul]); + obj.y = cumul; + } + if (mark.summarizeX === 'cumulative') { + let interm = entries.filter(f => { + return config.y.type === 'time' + ? new Date(f[config.y.column]) <= new Date(r[0][config.y.column]) + : +f[config.y.column] <= +r[0][config.y.column]; + }); + if (mark.per.length) { + interm = interm.filter(f => f[mark.per[0]] === r[0][mark.per[0]]); + } + dom_xs.push([interm.length]); + obj.x = interm.length; + } + + return obj; + }); + + let test = this_nest.entries(entries); + + let dom_x = extent(merge(dom_xs)); + let dom_y = extent(merge(dom_ys)); + + if (sublevel && mark.type === 'bar' && mark.arrange === 'stacked') { + test.forEach(calcStartTotal); + if (config.x.type === 'ordinal' || (config.x.type === 'linear' && config.x.bin)) { + dom_y = extent(test.map(m => m.total)); + } + if (config.y.type === 'ordinal' || (config.y.type === 'linear' && config.y.bin)) { + dom_x = extent(test.map(m => m.total)); + } + } else if (sublevel && mark.type === 'bar' && mark.split) { + test.forEach(calcStartTotal); + } else { + let axis = config.x.type === 'ordinal' || (config.x.type === 'linear' && config.x.bin) + ? 'y' + : 'x'; + test.forEach(e => (e.total = e.values[axis])); + } + + if ( + (config.x.sort === 'total-ascending' && config.x.type == 'ordinal') || + (config.y.sort === 'total-descending' && config.y.type == 'ordinal') + ) { + totalOrder = test.sort((a, b) => ascending(a.total, b.total)).map(m => m.key); + } else if ( + (config.x.sort === 'total-descending' && config.x.type == 'ordinal') || + (config.y.sort === 'total-ascending' && config.y.type == 'ordinal') + ) { + totalOrder = test.sort((a, b) => descending(+a.total, +b.total)).map(m => m.key); + } + + return { nested: test, dom_x: dom_x, dom_y: dom_y }; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DATA PREP + // prepare data based on the properties of the mark - drop missing records, etc + ////////////////////////////////////////////////////////////////////////////////// + + // only use data for the current mark + raw = mark.per && mark.per.length ? raw.filter(f => f[mark.per[0]]) : raw; + + // Make sure data has x and y values + if (config.x.column) { + raw = raw.filter(f => f[config.x.column] !== undefined); + } + if (config.y.column) { + raw = raw.filter(f => f[config.y.column] !== undefined); + } + + //check that x and y have the correct formats + if (config.x.type === 'time') { + raw = raw.filter( + f => + f[config.x.column] instanceof Date + ? f[config.x.column] + : dateConvert.parse(f[config.x.column]) + ); + raw.forEach( + e => + (e[config.x.column] = e[config.x.column] instanceof Date + ? e[config.x.column] + : dateConvert.parse(e[config.x.column])) + ); + } + if (config.y.type === 'time') { + raw = raw.filter( + f => + f[config.y.column] instanceof Date + ? f[config.y.column] + : dateConvert.parse(f[config.y.column]) + ); + raw.forEach( + e => + (e[config.y.column] = e[config.y.column] instanceof Date + ? e[config.y.column] + : dateConvert.parse(e[config.y.column])) + ); + } + + if ((config.x.type === 'linear' || config.x.type === 'log') && config.x.column) { + raw = raw.filter(f => { + return mark.summarizeX !== 'count' && mark.summarizeX !== 'percent' + ? +f[config.x.column] || +f[config.x.column] === 0 + : f; + }); + } + if ((config.y.type === 'linear' || config.y.type === 'log') && config.y.column) { + raw = raw.filter(f => { + return mark.summarizeY !== 'count' && mark.summarizeY !== 'percent' + ? +f[config.y.column] || +f[config.y.column] === 0 + : f; + }); + } + + //prepare nested data required for bar charts + let raw_nest; + if (mark.type === 'bar') { + raw_nest = mark.arrange !== 'stacked' ? makeNest(raw, sublevel) : makeNest(raw); + } else if (mark.summarizeX === 'count' || mark.summarizeY === 'count') { + raw_nest = makeNest(raw); + } + + // Get the domain for the mark based on the raw data + let raw_dom_x = mark.summarizeX === 'cumulative' + ? [0, raw.length] + : config.x.type === 'ordinal' + ? set(raw.map(m => m[config.x.column])).values().filter(f => f) + : mark.split && mark.arrange !== 'stacked' + ? extent(merge(raw_nest.nested.map(m => m.values.map(p => p.values.raw.length)))) + : mark.summarizeX === 'count' + ? extent(raw_nest.nested.map(m => m.values.raw.length)) + : extent(raw.map(m => +m[config.x.column]).filter(f => +f || +f === 0)); + + let raw_dom_y = mark.summarizeY === 'cumulative' + ? [0, raw.length] + : config.y.type === 'ordinal' + ? set(raw.map(m => m[config.y.column])).values().filter(f => f) + : mark.split && mark.arrange !== 'stacked' + ? extent(merge(raw_nest.nested.map(m => m.values.map(p => p.values.raw.length)))) + : mark.summarizeY === 'count' + ? extent(raw_nest.nested.map(m => m.values.raw.length)) + : extent(raw.map(m => +m[config.y.column]).filter(f => +f || +f === 0)); + + let filtered = raw; + + let filt1_xs = []; + let filt1_ys = []; + if (this.filters.length) { + this.filters.forEach(e => { + filtered = filtered.filter(d => { + return e.val === 'All' + ? d + : e.val instanceof Array ? e.val.indexOf(d[e.col]) > -1 : d[e.col] === e.val; + }); + }); + //get domain for all non-All values of first filter + if (config.x.behavior === 'firstfilter' || config.y.behavior === 'firstfilter') { + this.filters[0].choices.filter(f => f !== 'All').forEach(e => { + let perfilter = raw.filter(f => f[this.filters[0].col] === e); + let filt_nested = makeNest(perfilter, sublevel); + filt1_xs.push(filt_nested.dom_x); + filt1_ys.push(filt_nested.dom_y); + }); + } + } + + //filter on mark-specific instructions + if (mark.values) { + for (let a in mark.values) { + filtered = filtered.filter(f => { + return mark.values[a].indexOf(f[a]) > -1; + }); + } + } + let filt1_dom_x = extent(merge(filt1_xs)); + let filt1_dom_y = extent(merge(filt1_ys)); + + let current_nested = makeNest(filtered, sublevel); + + let flex_dom_x = current_nested.dom_x; + let flex_dom_y = current_nested.dom_y; + + if (mark.type === 'bar') { + if (config.y.type === 'ordinal' && mark.summarizeX === 'count') { + config.x.domain = config.x.domain ? [0, config.x.domain[1]] : [0, null]; + } else if (config.x.type === 'ordinal' && mark.summarizeY === 'count') { + config.y.domain = config.y.domain ? [0, config.y.domain[1]] : [0, null]; + } + } + + //several criteria must be met in order to use the 'firstfilter' domain + let nonall = Boolean( + this.filters.length && + this.filters[0].val !== 'All' && + this.filters.slice(1).filter(f => f.val === 'All').length === this.filters.length - 1 + ); + + let pre_x_dom = !this.filters.length + ? flex_dom_x + : x_behavior === 'raw' + ? raw_dom_x + : nonall && x_behavior === 'firstfilter' ? filt1_dom_x : flex_dom_x; + let pre_y_dom = !this.filters.length + ? flex_dom_y + : y_behavior === 'raw' + ? raw_dom_y + : nonall && y_behavior === 'firstfilter' ? filt1_dom_y : flex_dom_y; + + let x_dom = config.x_dom + ? config.x_dom + : config.x.type === 'ordinal' && config.x.behavior === 'flex' + ? set(filtered.map(m => m[config.x.column])).values() + : config.x.type === 'ordinal' + ? set(raw.map(m => m[config.x.column])).values() + : config.x_from0 ? [0, max(pre_x_dom)] : pre_x_dom; + + let y_dom = config.y_dom + ? config.y_dom + : config.y.type === 'ordinal' && config.y.behavior === 'flex' + ? set(filtered.map(m => m[config.y.column])).values() + : config.y.type === 'ordinal' + ? set(raw.map(m => m[config.y.column])).values() + : config.y_from0 ? [0, max(pre_y_dom)] : pre_y_dom; + + if (config.x.domain && (config.x.domain[0] || config.x.domain[0] === 0)) { + x_dom[0] = config.x.domain[0]; + } + if (config.x.domain && (config.x.domain[1] || config.x.domain[1] === 0)) { + x_dom[1] = config.x.domain[1]; + } + if (config.y.domain && (config.y.domain[0] || config.y.domain[0] === 0)) { + y_dom[0] = config.y.domain[0]; + } + if (config.y.domain && (config.y.domain[1] || config.y.domain[1] === 0)) { + y_dom[1] = config.y.domain[1]; + } + + if (config.x.type === 'ordinal' && !config.x.order) { + config.x.order = totalOrder; + } + if (config.y.type === 'ordinal' && !config.y.order) { + config.y.order = totalOrder; + } + + this.current_data = current_nested.nested; + + this.events.onDatatransform.call(this); + + return { config: mark, data: current_nested.nested, x_dom: x_dom, y_dom: y_dom }; +} diff --git a/src/chart/resize/updateDataMarks.js b/src/chart/updateDataMarks.js similarity index 100% rename from src/chart/resize/updateDataMarks.js rename to src/chart/updateDataMarks.js diff --git a/src/chart/draw/xScaleAxis.js b/src/chart/xScaleAxis.js similarity index 100% rename from src/chart/draw/xScaleAxis.js rename to src/chart/xScaleAxis.js diff --git a/src/chart/draw/yScaleAxis.js b/src/chart/yScaleAxis.js similarity index 100% rename from src/chart/draw/yScaleAxis.js rename to src/chart/yScaleAxis.js diff --git a/src/createTable.js b/src/createTable.js index 523af57..252f4e8 100644 --- a/src/createTable.js +++ b/src/createTable.js @@ -14,18 +14,28 @@ export default function createTable(element = 'body', config = {}, controls = nu thisTable.required_cols = []; - thisTable.wrap = select(thisTable.div).append('div').datum(thisTable); + thisTable.wrap = select(thisTable.div).append('div'); thisTable.events = { onInit() {}, onLayout() {}, onPreprocess() {}, + onDatatransform() {}, onDraw() {}, + onResize() {}, onDestroy() {} }; thisTable.on = function(event, callback) { - let possible_events = ['init', 'layout', 'preprocess', 'draw', 'destroy']; + let possible_events = [ + 'init', + 'layout', + 'preprocess', + 'datatransform', + 'draw', + 'resize', + 'destroy' + ]; if (possible_events.indexOf(event) < 0) { return; } diff --git a/src/multiply.js b/src/multiply.js index c6e6121..85a0f12 100644 --- a/src/multiply.js +++ b/src/multiply.js @@ -2,13 +2,9 @@ import createChart from './createChart'; import { set, ascending } from 'd3'; export default function multiply(chart, data, split_by, order, test = false) { - chart.wrap.classed('wc-layout wc-small-multiples', true).classed('wc-chart', false); - - //Define container for legend that overrides multiples' legends. - chart.master_legend = chart.wrap.append('ul').attr('class', 'legend'); - chart.master_legend.append('span').classed('legend-title', true); - - //Instantiate multiples array. + let config = chart.config; + let wrap = chart.wrap.classed('wc-layout wc-small-multiples', true).classed('wc-chart', false); + let master_legend = wrap.append('ul').attr('class', 'legend'); chart.multiples = []; function goAhead(data) { @@ -17,16 +13,15 @@ export default function multiply(chart, data, split_by, order, test = false) { split_vals = split_vals.sort((a, b) => ascending(order.indexOf(a), order.indexOf(b))); } split_vals.forEach(e => { - var mchart = createChart(chart.wrap.node(), chart.config, chart.controls); + var mchart = createChart(chart.wrap.node(), config, chart.controls); chart.multiples.push(mchart); mchart.parent = chart; mchart.events = chart.events; - mchart.legend = chart.master_legend; + mchart.legend = master_legend; mchart.filters.unshift({ col: split_by, val: e, choices: split_vals }); mchart.wrap.insert('span', 'svg').attr('class', 'wc-chart-title').text(e); mchart.init(data, test); }); } - goAhead(data); } diff --git a/src/table/draw.js b/src/table/draw.js index 80fa2b1..d4d3ffc 100644 --- a/src/table/draw.js +++ b/src/table/draw.js @@ -1,48 +1,75 @@ import applyFilters from './draw/applyFilters'; -import updateDataObject from './draw/updateDataObject'; import applySearchTerm from './draw/applySearchTerm'; -import checkFilters from './draw/checkFilters'; -import updateTableHeaders from './draw/updateTableHeaders'; +import '../util/array-equals'; import clone from '../util/clone'; -import drawTableBody from './draw/drawTableBody'; -import dynamicLayout from './draw/dynamicLayout'; +import { select } from 'd3'; export default function draw(passed_data) { - const table = this; - const config = this.config; + const context = this, + config = this.config, + table = this.table; - this.data.passed = passed_data; // make passed data available on preprocess - this.events.onPreprocess.call(this); - - if (!passed_data) - //Apply filters if data is not passed to table.draw(). + //Apply filters if data is not passed to table.draw(). + if (!passed_data) { applyFilters.call(this); - else + } else { //Otherwise update data object. - updateDataObject.call(this); + this.data.raw = passed_data; + this.data.filtered = passed_data; + this.config.activePage = 0; + this.config.startIndex = this.config.activePage * this.config.nRowsPerPage; // first row shown + this.config.endIndex = this.config.startIndex + this.config.nRowsPerPage; // last row shown + } //Compare current filter settings to previous filter settings, if any. - checkFilters.call(this); + if (this.filters) { + this.currentFilters = this.filters.map(filter => filter.val); + + //Reset pagination if filters have changed. + if (!this.currentFilters.equals(this.previousFilters)) { + this.config.activePage = 0; + this.config.startIndex = this.config.activePage * this.config.nRowsPerPage; // first row shown + this.config.endIndex = this.config.startIndex + this.config.nRowsPerPage; // last row shown + } + + this.previousFilters = this.currentFilters; + } + + let data; //Filter data on search term if it exists and set data to searched data. - applySearchTerm.call(this); + if (this.searchable.searchTerm) { + applySearchTerm.call(this); + data = this.data.searched; + } else { + //Otherwise delete previously searched data and set data to filtered data. + delete this.data.searched; + data = this.data.filtered; + } this.searchable.wrap .select('.nNrecords') .text( - this.data.processing.length === this.data.raw.length + data.length === this.data.raw.length ? `${this.data.raw.length} records displayed` - : `${this.data.processing.length}/${this.data.raw.length} records displayed` + : `${data.length}/${this.data.raw.length} records displayed` ); - //Update table headers. - updateTableHeaders.call(this); + //update table header + this.thead_cells = this.thead.select('tr').selectAll('th').data(this.config.headers, d => d); + this.thead_cells.exit().remove(); + this.thead_cells.enter().append('th'); + + this.thead_cells + .sort((a, b) => this.config.headers.indexOf(a) - this.config.headers.indexOf(b)) + .attr('class', d => this.config.cols[this.config.headers.indexOf(d)]) // associate column header with column name + .text(d => d); //Clear table body rows. this.tbody.selectAll('tr').remove(); //Print a note that no data was selected for empty tables. - if (this.data.processing.length === 0) { + if (data.length === 0) { this.tbody .append('tr') .classed('no-data', true) @@ -50,54 +77,110 @@ export default function draw(passed_data) { .attr('colspan', this.config.cols.length) .text('No data selected.'); - //Bind table filtered/searched data to table container. - this.data.current = clone(this.data.processing); - this.table.datum(this.table.current); - //Add export. if (this.config.exportable) this.config.exports.forEach(fmt => { - this.exportable.exports[fmt].call(this, this.data.processing); + this.exportable.exports[fmt].call(this, data); }); //Add pagination. - if (this.config.pagination) this.pagination.addPagination.call(this, this.data.processing); + if (this.config.pagination) this.pagination.addPagination.call(this, data); } else { //Sort data. if (this.config.sortable) { this.thead.selectAll('th').on('click', function(header) { - table.sortable.onClick.call(table, this, header); + context.sortable.onClick.call(context, this, header); }); - if (this.sortable.order.length) this.sortable.sortData.call(this, this.data.processing); + if (this.sortable.order.length) this.sortable.sortData.call(this, data); } //Bind table filtered/searched data to table container. - this.data.current = clone(this.data.processing); - this.table.datum(this.data.current); + this.wrap.datum(clone(data)); //Add export. if (this.config.exportable) this.config.exports.forEach(fmt => { - this.exportable.exports[fmt].call(this, this.data.processing); + this.exportable.exports[fmt].call(this, data); }); //Add pagination. if (this.config.pagination) { - this.pagination.addPagination.call(this, this.data.processing); + this.pagination.addPagination.call(this, data); //Apply pagination. - this.data.processing = this.data.processing.filter( - (d, i) => this.config.startIndex <= i && i < this.config.endIndex - ); + data = data.filter((d, i) => this.config.startIndex <= i && i < this.config.endIndex); } //Define table body rows. - drawTableBody.call(this); + const rows = this.tbody.selectAll('tr').data(data).enter().append('tr'); + + //Define table body cells. + const cells = rows.selectAll('td').data(d => + this.config.cols.map(key => { + return { col: key, text: d[key] }; + }) + ); + cells.exit().remove(); + cells.enter().append('td'); + cells + .sort((a, b) => this.config.cols.indexOf(a.col) - this.config.cols.indexOf(b.col)) + .attr('class', d => d.col) + .each(function(d) { + const cell = select(this); + + //Apply text in data as html or as plain text. + if (config.as_html) { + cell.html(d.text); + } else { + cell.text(d.text); + } + }); } //Alter table layout if table is narrower than table top or bottom. - dynamicLayout.call(this); + const widths = { + table: this.table.select('thead').node().offsetWidth, + top: + this.wrap.select('.table-top .searchable-container').node().offsetWidth + + this.wrap.select('.table-top .sortable-container').node().offsetWidth, + bottom: + this.wrap.select('.table-bottom .pagination-container').node().offsetWidth + + this.wrap.select('.table-bottom .exportable-container').node().offsetWidth + }; + + if (widths.table < Math.max(widths.top, widths.bottom) && this.config.layout === 'horizontal') { + this.config.layout = 'vertical'; + this.wrap + .style('display', 'inline-block') + .selectAll('.table-top,.table-bottom') + .style('display', 'inline-block') + .selectAll('.interactivity') + .style({ + display: 'block', + clear: 'both' + }); + } else if ( + widths.table >= Math.max(widths.top, widths.bottom) && + this.config.layout === 'vertical' + ) { + this.config.layout = 'horizontal'; + this.wrap + .style('display', 'table') + .selectAll('.table-top,.table-bottom') + .style('display', 'block') + .selectAll('.interactivity') + .style({ + display: 'inline-block', + float: function() { + return select(this).classed('searchable-container') || + select(this).classed('pagination-container') + ? 'right' + : null; + }, + clear: null + }); + } this.events.onDraw.call(this); } diff --git a/src/table/draw/applySearchTerm.js b/src/table/draw/applySearchTerm.js index 9caaa00..16fe8ec 100644 --- a/src/table/draw/applySearchTerm.js +++ b/src/table/draw/applySearchTerm.js @@ -1,22 +1,15 @@ -export default function applySearchTerm(data) { - if (this.searchable.searchTerm) { - //Determine which rows contain input text. - this.data.searched = this.data.filtered.filter(d => { - let match = false; +export default function applySearchTerm() { + //Determine which rows contain input text. + this.data.searched = this.data.filtered.filter(d => { + let match = false; - Object.keys(d).filter(key => this.config.cols.indexOf(key) > -1).forEach(var_name => { - if (match === false) { - const cellText = '' + d[var_name]; - match = cellText.toLowerCase().indexOf(this.searchable.searchTerm) > -1; - } - }); - - return match; + Object.keys(d).filter(key => this.config.cols.indexOf(key) > -1).forEach(var_name => { + if (match === false) { + const cellText = '' + d[var_name]; + match = cellText.toLowerCase().indexOf(this.searchable.searchTerm) > -1; + } }); - this.data.processing = this.data.searched; - } else { - //Otherwise delete previously searched data and set data to filtered data. - delete this.data.searched; - this.data.processing = this.data.filtered; - } + + return match; + }); } diff --git a/src/table/draw/checkFilters.js b/src/table/draw/checkFilters.js deleted file mode 100644 index db9043d..0000000 --- a/src/table/draw/checkFilters.js +++ /dev/null @@ -1,16 +0,0 @@ -import '../../util/array-equals'; - -export default function checkFilters() { - if (this.filters) { - this.currentFilters = this.filters.map(filter => filter.val); - - //Reset pagination if filters have changed. - if (!this.currentFilters.equals(this.previousFilters)) { - this.config.activePage = 0; - this.config.startIndex = this.config.activePage * this.config.nRowsPerPage; // first row shown - this.config.endIndex = this.config.startIndex + this.config.nRowsPerPage; // last row shown - } - - this.previousFilters = this.currentFilters; - } -} diff --git a/src/table/draw/drawTableBody.js b/src/table/draw/drawTableBody.js deleted file mode 100644 index a6fea92..0000000 --- a/src/table/draw/drawTableBody.js +++ /dev/null @@ -1,30 +0,0 @@ -import { select } from 'd3'; - -export default function drawTableBody() { - const table = this; - - //Define table body rows. - const rows = this.tbody.selectAll('tr').data(this.data.processing).enter().append('tr'); - - //Define table body cells. - const cells = rows.selectAll('td').data(d => - this.config.cols.map(key => { - return { col: key, text: d[key] }; - }) - ); - cells.exit().remove(); - cells.enter().append('td'); - cells - .sort((a, b) => this.config.cols.indexOf(a.col) - this.config.cols.indexOf(b.col)) - .attr('class', d => d.col) - .each(function(d) { - const cell = select(this); - - //Apply text in data as html or as plain text. - if (table.config.as_html) { - cell.html(d.text); - } else { - cell.text(d.text); - } - }); -} diff --git a/src/table/draw/dynamicLayout.js b/src/table/draw/dynamicLayout.js deleted file mode 100644 index d7433d6..0000000 --- a/src/table/draw/dynamicLayout.js +++ /dev/null @@ -1,44 +0,0 @@ -export default function dynamicLayout() { - const widths = { - table: this.table.select('thead').node().offsetWidth, - top: - this.wrap.select('.table-top .searchable-container').node().offsetWidth + - this.wrap.select('.table-top .sortable-container').node().offsetWidth, - bottom: - this.wrap.select('.table-bottom .pagination-container').node().offsetWidth + - this.wrap.select('.table-bottom .exportable-container').node().offsetWidth - }; - - if (widths.table < Math.max(widths.top, widths.bottom) && this.config.layout === 'horizontal') { - this.config.layout = 'vertical'; - this.wrap - .style('display', 'inline-block') - .selectAll('.table-top,.table-bottom') - .style('display', 'inline-block') - .selectAll('.interactivity') - .style({ - display: 'block', - clear: 'both' - }); - } else if ( - widths.table >= Math.max(widths.top, widths.bottom) && - this.config.layout === 'vertical' - ) { - this.config.layout = 'horizontal'; - this.wrap - .style('display', 'table') - .selectAll('.table-top,.table-bottom') - .style('display', 'block') - .selectAll('.interactivity') - .style({ - display: 'inline-block', - float: function() { - return select(this).classed('searchable-container') || - select(this).classed('pagination-container') - ? 'right' - : null; - }, - clear: null - }); - } -} diff --git a/src/table/draw/updateDataObject.js b/src/table/draw/updateDataObject.js deleted file mode 100644 index 26e9746..0000000 --- a/src/table/draw/updateDataObject.js +++ /dev/null @@ -1,7 +0,0 @@ -export default function updateDataObject() { - this.data.raw = this.data.passed; - this.data.filtered = this.data.passed; - this.config.activePage = 0; - this.config.startIndex = this.config.activePage * this.config.nRowsPerPage; // first row shown - this.config.endIndex = this.config.startIndex + this.config.nRowsPerPage; // last row shown -} diff --git a/src/table/draw/updateTableHeaders.js b/src/table/draw/updateTableHeaders.js deleted file mode 100644 index 0806d4b..0000000 --- a/src/table/draw/updateTableHeaders.js +++ /dev/null @@ -1,9 +0,0 @@ -export default function updateTableHeaders() { - this.thead_cells = this.thead.select('tr').selectAll('th').data(this.config.headers, d => d); - this.thead_cells.exit().remove(); - this.thead_cells.enter().append('th'); - this.thead_cells - .sort((a, b) => this.config.headers.indexOf(a) - this.config.headers.indexOf(b)) - .attr('class', d => this.config.cols[this.config.headers.indexOf(d)]) // associate column header with column name - .text(d => d); -} diff --git a/src/table/exportable/exports/csv.js b/src/table/exportable/exports/csv.js index f6fa48e..4e1ff51 100644 --- a/src/table/exportable/exports/csv.js +++ b/src/table/exportable/exports/csv.js @@ -3,12 +3,14 @@ import { time } from 'd3'; export default function csv(data) { const CSVarray = []; - //add headers to CSV array - const headers = this.config.headers.map(header => `"${header.replace(/"/g, '""')}"`); - CSVarray.push(headers); - - //add rows to CSV array data.forEach((d, i) => { + //add headers to CSV array + if (i === 0) { + const headers = this.config.headers.map(header => `"${header.replace(/"/g, '""')}"`); + CSVarray.push(headers); + } + + //add rows to CSV array const row = this.config.cols.map(col => { let value = d[col]; diff --git a/src/version.js b/src/version.js index 2eef61b..80b72b7 100644 --- a/src/version.js +++ b/src/version.js @@ -1 +1 @@ -export default '1.11.0'; +export default '1.10.0'; diff --git a/test/chart/cleanData.js b/test/chart/cleanData.js deleted file mode 100644 index ba0cd07..0000000 --- a/test/chart/cleanData.js +++ /dev/null @@ -1,70 +0,0 @@ -import jsdom from 'jsdom'; -import createChart from '../../src/createChart'; -import cleanData from '../../src/chart/draw/consolidateData/transformData/cleanData'; -import expect from 'expect'; -import d3 from 'd3'; - -export default function testCleanData(settings, data) { - describe('data cleaning', () => { - const { JSDOM } = jsdom; - let dom, container, chart; - - //DOM setup - before(() => { - dom = new JSDOM(''); - container = dom.window.document.createElement('div'); - }); - - //Chart initialization - beforeEach(() => { - chart = createChart(container, settings).init(data, true); - }); - - //transformData() validation - describe('cleanData() is called for each item in settings.marks', () => { - const falseyValues = [ - '', - ' ', - 'asdf', - NaN, - null, - undefined, - false - ]; - settings.marks.forEach(mark => { - let copiedData, cleanedData; - - beforeEach(() => { - copiedData = []; - data.forEach((d,i) => { - copiedData[i] = {}; - for (const variable in d) - copiedData[i][variable] = d[variable]; - - if (Math.random() < .1) - copiedData[i][settings.x.column] = falseyValues[i%(falseyValues.length - 1)]; - if (Math.random() > .9) - copiedData[i][settings.y.column] = falseyValues[i%(falseyValues.length - 1)]; - }); - - cleanedData = cleanData.call(chart, mark, copiedData); - }); - - it('removes falsey values', () => { - const cleanedCopiedData = copiedData - .filter(d => ( - falseyValues.indexOf(d[settings.x.column]) < 0 && - !isNaN(d[settings.x.column]) && - falseyValues.indexOf(d[settings.y.column]) < 0 && - !isNaN(d[settings.y.column]) - )); - expect( - cleanedData.length - ).toEqual( - cleanedCopiedData.length - ); - }); - }); - }); - }); -} diff --git a/test/chart/consolidateData.js b/test/chart/consolidateData.js new file mode 100644 index 0000000..e69de29 diff --git a/test/chart/draw.js b/test/chart/draw.js new file mode 100644 index 0000000..e69de29 diff --git a/test/chart/rangeBand.js b/test/chart/rangeBand.js deleted file mode 100644 index b26f862..0000000 --- a/test/chart/rangeBand.js +++ /dev/null @@ -1,77 +0,0 @@ -import jsdom from 'jsdom'; -import createChart from '../../src/createChart'; -import expect from 'expect'; -import d3 from 'd3'; - -export default function testRangeBand(settings, data) { - describe('range band definitions for ordinal axes', () => { - const { JSDOM } = jsdom; - let dom, container, chart; - - //DOM setup - before(() => { - dom = new JSDOM(''); - container = dom.window.document.createElement('div'); - }); - - //Chart initialization - beforeEach(() => { - chart = createChart(container, settings).init(data, true); - }); - - afterEach(() => { - delete chart.config.range_band; - delete chart.config.x.range_band; - delete chart.config.y.range_band; - }); - - describe('x-axis range band', () => { - it('sets bar width to config.range_band if config.x.range_band is undefined', () => { - chart.config.range_band = 25; - chart.draw(); - expect(chart.config.range_band).toEqual(chart.x.rangeBand()); - }); - - it('sets bar width to config.x.range_band otherwise', () => { - chart.config.x.range_band = 20; - chart.draw(); - expect(chart.config.x.range_band).toEqual(chart.x.rangeBand()); - }); - }); - - describe('y-axis range band', () => { - it('sets bar width to config.range_band if config.y.range_band is undefined', () => { - chart.config.range_band = 25; - chart.draw(); - expect(chart.config.range_band).toEqual(chart.y.rangeBand()); - }); - - it('sets bar width to config.y.range_band otherwise', () => { - chart.config.y.range_band = 30; - chart.draw(); - expect(chart.config.y.range_band).toEqual(chart.y.rangeBand()); - }); - }); - - describe('x- and y-axis range band', () => { - it('sets bar width to config.range_band if both config.x.range_band and config.y.range_band are undefined', () => { - chart.config.range_band = 25; - chart.draw(); - expect( - chart.config.range_band === chart.x.rangeBand() && - chart.config.range_band === chart.y.rangeBand() - ).toEqual(true); - }); - - it('sets bar width independently for each axis otherwise', () => { - chart.config.x.range_band = 20; - chart.config.y.range_band = 30; - chart.draw(); - expect( - chart.config.x.range_band === chart.x.rangeBand() && - chart.config.y.range_band === chart.y.rangeBand() - ).toEqual(true); - }); - }); - }); -} diff --git a/test/chart/runTests.js b/test/chart/runTests.js index 8a887fc..2840746 100644 --- a/test/chart/runTests.js +++ b/test/chart/runTests.js @@ -1,61 +1,34 @@ -//define chart object import testCreateChart from './createChart'; -import { linear_linear as createChartSettings } from '../samples/irisSettings'; + +import createChartSettings from '../samples/irisSettings'; testCreateChart(createChartSettings); -//initialize chart by passing a data array to the init method import testInit from './init'; -import { linear_linear as initSettings } from '../samples/irisSettings'; + +import initSettings from '../samples/irisSettings'; import initData from '../samples/irisData'; testInit(initSettings, initData); -//render chart in DOM import testRendering from './rendering'; + import renderSettings from '../samples/element-settings'; import renderData from '../samples/data'; testRendering(renderSettings, renderData); -//check for required variables in data array import testCheckRequired from './checkRequired'; -import { linear_linear as checkRequiredSettings } from '../samples/irisSettings'; + +import checkRequiredSettings from '../samples/irisSettings'; import checkRequiredData from '../samples/irisData'; testCheckRequired(checkRequiredSettings, checkRequiredData); -//generate layout of chart import testLayout from './layout'; -import { linear_linear as layoutSettings } from '../samples/irisSettings'; + +import layoutSettings from '../samples/irisSettings'; import layoutData from '../samples/irisData'; testLayout(layoutSettings, layoutData); -//define color scale of chart import testSetColorScale from './setColorScale'; -import { linear_linear as setColorScaleSettings } from '../samples/irisSettings'; + +import setColorScaleSettings from '../samples/irisSettings'; import setColorScaleData from '../samples/irisData'; testSetColorScale(setColorScaleSettings, setColorScaleData); - -//transform raw data for each mark defined in chart config -import testTransformData from './transformData'; -import { linear_linear as transformDataSettings } from '../samples/irisSettings'; -import transformDataData from '../samples/irisData'; -testTransformData(transformDataSettings, transformDataData); - -//define singular domain for chart -import testSetDomain from './setDomain'; -import { linear_linear, linear_ordinal, ordinal_linear } from '../samples/irisSettings'; -import setDomainData from '../samples/irisData'; -testSetDomain({linear_linear, linear_ordinal, ordinal_linear}, setDomainData); - -//remove falsey values from data -import testCleanData from './cleanData'; -import { linear_linear as cleanDataSettings } from '../samples/irisSettings'; -import cleanDataData from '../samples/irisData'; -testCleanData(cleanDataSettings, cleanDataData); - -//test range band settings -import testRangeBand from './rangeBand'; -import { ordinal_ordinal as ordinal_ordinal_rb } from '../samples/irisSettings'; -import rangeBandData from '../samples/irisData'; -testRangeBand( - ordinal_ordinal_rb, - rangeBandData -); diff --git a/test/chart/setDomain.js b/test/chart/setDomain.js deleted file mode 100644 index 2726d92..0000000 --- a/test/chart/setDomain.js +++ /dev/null @@ -1,106 +0,0 @@ -import jsdom from 'jsdom'; -import createChart from '../../src/createChart'; -import expect from 'expect'; -import d3 from 'd3'; - -export default function testSetDomain(settings, data) { - describe('chart domains', () => { - const { JSDOM } = jsdom; - let dom, container, charts; - - //DOM setup - before(() => { - dom = new JSDOM(''); - container = dom.window.document.createElement('div'); - }); - - beforeEach(() => { - charts = { - linear_linear: createChart(container, settings.linear_linear).init(data, true), - ordinal_linear: createChart(container, settings.ordinal_linear).init(data, true), - linear_ordinal: createChart(container, settings.linear_ordinal).init(data, true) - }; - }); - - afterEach(() => { - for (const chart in chart) { - delete charts[chart].config.x.domain; - delete charts[chart].x_dom; - delete charts[chart].config.y.domain; - delete charts[chart].y_dom; - } - }); - - //linear x linear - describe('setDomain() is called for a chart with two linear axes', () => { - ['x','y'].forEach(axis => { - it('returns a non-zero-length array for the specified axis', () => { - console.log(` - testing ${charts.linear_linear[axis].type} ${axis} axis:`); - expect(charts.linear_linear[axis + '_dom'].length).toBeGreaterThan(0); - }); - - it('does not return a zero-range domain for the specified axis', () => { - const test_data = []; - data.forEach(d => { - const datum = {}; - for (const prop in d) - datum[prop] = d[prop]; - datum[charts.linear_linear[axis].column] = 0; - test_data.push(datum); - }); - charts.linear_linear.consolidateData(test_data); - expect(charts.linear_linear[axis + '_dom'][1] - charts.linear_linear[axis + '_dom'][0]).toBeGreaterThan(0); - }); - - it('gives precedence to the domain defined in the config', () => { - const domain = [-100,100]; - charts.linear_linear.config[axis].domain = domain.slice(); - charts.linear_linear.consolidateData(data); - expect(charts.linear_linear[axis + '_dom'].join(',')).toEqual(domain.join(',')); - }); - }); - }); - - //ordinal x linear - describe('setDomain() is called for a chart with an ordinal x-axis and a linear y-axis', () => { - it('returns a unique set of the ordinal axis variable as its domain', () => { - const ordinalDomain = d3 - .set(data.map(d => d[charts.ordinal_linear.config.x.column])) - .values() - .sort() - .join(', '); - expect(charts.ordinal_linear.x_dom.sort().join(', ')).toEqual(ordinalDomain); - }); - - it('sets the lower limit of the linear domain to 0', () => { - expect(charts.ordinal_linear.y_dom[0]).toEqual(0); - }); - - it('sets the upper limit of the linear domain to the maximum value of the linear axis variable', () => { - const upperLimit = d3.max(data.map(d => d[charts.ordinal_linear.config.y.column])); - expect(charts.ordinal_linear.y_dom[1]).toEqual(upperLimit); - }); - }); - - //linear x ordinal - describe('setDomain() is called for a chart with an linear x-axis and a ordinal y-axis', () => { - it('sets the lower limit of the linear domain to 0', () => { - expect(charts.linear_ordinal.x_dom[0]).toEqual(0); - }); - - it('sets the upper limit of the linear domain to the maximum value of the linear axis variable', () => { - const upperLimit = d3.max(data.map(d => d[charts.linear_ordinal.config.x.column])); - expect(charts.linear_ordinal.x_dom[1]).toEqual(upperLimit); - }); - - it('returns a unique set of the ordinal axis variable as its domain', () => { - const ordinalDomain = d3 - .set(data.map(d => d[charts.linear_ordinal.config.y.column])) - .values() - .sort() - .join(', '); - expect(charts.linear_ordinal.y_dom.sort().join(', ')).toEqual(ordinalDomain); - }); - }); - }); -} diff --git a/test/chart/transformData.js b/test/chart/transformData.js index 198b7fe..a10c668 100644 --- a/test/chart/transformData.js +++ b/test/chart/transformData.js @@ -1,94 +1,95 @@ import jsdom from 'jsdom'; import createChart from '../../src/createChart'; +import transformData from '../../src/chart/transformData'; import expect from 'expect'; +import settings from '../samples/irisSettings'; +import data from '../samples/irisData'; import d3 from 'd3'; -export default function testTransformData(settings, data) { - describe('data transformation', () => { - const { JSDOM } = jsdom; - let dom, container, chart; +describe('data transformation', () => { + const { JSDOM } = jsdom; + let dom, container, chart; - //DOM setup - before(() => { - dom = new JSDOM(''); - container = dom.window.document.createElement('div'); - }); + //DOM setup + before(() => { + dom = new JSDOM(''); + container = dom.window.document.createElement('div'); + }); - //Chart initialization - beforeEach(() => { - chart = createChart(container, settings).init(data, true); - }); + //Chart initialization + beforeEach(() => { + chart = createChart(container, settings).init(data, true); + }); - //transformData() validation - describe('transformData() is called for each item in settings.marks', () => { - settings.marks.forEach(mark => { - let transformedData, nestedData; + //transformData() validation + describe('transformData() is called for each item in settings.marks', () => { + settings.marks.forEach(mark => { + let transformedData, nestedData; - beforeEach(() => { - transformedData = chart.transformData(data, mark); // webcharts dataset - nestedData = d3 - .nest() // validation dataset - .key(d => mark.per.map(per => d[per]).join(' ')) - .rollup(d => { - return { - raw: d, - x: d3[mark.summarizeX](d, di => di[settings.x.column]), - y: d3[mark.summarizeY](d, di => di[settings.y.column]), - x_q25: d3.quantile(d.map(di => di[settings.x.column]), 0.25), - x_q75: d3.quantile(d.map(di => di[settings.x.column]), 0.75), - y_q25: d3.quantile(d.map(di => di[settings.y.column]), 0.25), - y_q75: d3.quantile(d.map(di => di[settings.y.column]), 0.75) - }; - }) - .entries(data); - }); + beforeEach(() => { + transformedData = chart.transformData(data, mark); // webcharts dataset + nestedData = d3 + .nest() // validation dataset + .key(d => mark.per.map(per => d[per]).join(' ')) + .rollup(d => { + return { + raw: d, + x: d3[mark.summarizeX](d, di => di[settings.x.column]), + y: d3[mark.summarizeY](d, di => di[settings.y.column]), + x_q25: d3.quantile(d.map(di => di[settings.x.column]), 0.25), + x_q75: d3.quantile(d.map(di => di[settings.x.column]), 0.75), + y_q25: d3.quantile(d.map(di => di[settings.y.column]), 0.25), + y_q75: d3.quantile(d.map(di => di[settings.y.column]), 0.75) + }; + }) + .entries(data); + }); - it('returns an object containing a config, a nested data array, an x-domain, and a y-domain', () => { - console.log(`\n Testing ${mark.summarizeX}:\n`); - expect(Object.keys(transformedData)).toEqual(['config','data', 'x_dom', 'y_dom']); - }); + it('returns an object containing a config, a nested data array, an x-domain, and a y-domain', () => { + console.log(`\n Testing ${mark.summarizeX}:\n`); + expect(Object.keys(transformedData)).toEqual(['config','data', 'x_dom', 'y_dom']); + }); - it('nests raw data by mark.per', () => { - expect(nestedData.length).toEqual(transformedData.data.length); - expect(nestedData.map(d => d.key)).toEqual(transformedData.data.map(d => d.key)); + it('nests raw data by mark.per', () => { + expect(nestedData.length).toEqual(transformedData.data.length); + expect(nestedData.map(d => d.key)).toEqual(transformedData.data.map(d => d.key)); - nestedData.forEach(d => { - const transformedDatum = transformedData.data.filter(di => di.key === d.key)[0]; + nestedData.forEach(d => { + const transformedDatum = transformedData.data.filter(di => di.key === d.key)[0]; - expect(d.values.raw).toEqual(transformedDatum.values.raw); - expect(d.values.x).toEqual(transformedDatum.values.x); - expect(d.values.y).toEqual(transformedDatum.values.y); - expect(d.values.x_25).toEqual(transformedDatum.values.x_25); - expect(d.values.x_75).toEqual(transformedDatum.values.x_75); - expect(d.values.y_25).toEqual(transformedDatum.values.y_25); - expect(d.values.y_75).toEqual(transformedDatum.values.y_75); - }); + expect(d.values.raw).toEqual(transformedDatum.values.raw); + expect(d.values.x).toEqual(transformedDatum.values.x); + expect(d.values.y).toEqual(transformedDatum.values.y); + expect(d.values.x_25).toEqual(transformedDatum.values.x_25); + expect(d.values.x_75).toEqual(transformedDatum.values.x_75); + expect(d.values.y_25).toEqual(transformedDatum.values.y_25); + expect(d.values.y_75).toEqual(transformedDatum.values.y_75); }); + }); - it('sets x-domain to extent of values in x-column', () => { - expect(Math.min.apply(null, nestedData.map(d => d.values.x))).toEqual( - transformedData.x_dom[0] - ); - expect(Math.max.apply(null, nestedData.map(d => d.values.x))).toEqual( - transformedData.x_dom[1] - ); - }); + it('sets x-domain to extent of values in x-column', () => { + expect(Math.min.apply(null, nestedData.map(d => d.values.x))).toEqual( + transformedData.x_dom[0] + ); + expect(Math.max.apply(null, nestedData.map(d => d.values.x))).toEqual( + transformedData.x_dom[1] + ); + }); - it('sets y-domain to extent of values in y-column', () => { - expect(Math.min.apply(null, nestedData.map(d => d.values.y))).toEqual( - transformedData.y_dom[0] - ); - expect(Math.max.apply(null, nestedData.map(d => d.values.y))).toEqual( - transformedData.y_dom[1] - ); - }); + it('sets y-domain to extent of values in y-column', () => { + expect(Math.min.apply(null, nestedData.map(d => d.values.y))).toEqual( + transformedData.y_dom[0] + ); + expect(Math.max.apply(null, nestedData.map(d => d.values.y))).toEqual( + transformedData.y_dom[1] + ); }); }); + }); - describe('chart object has marks property', () => { - it('marks property has the same length as settings.marks', () => { - expect(settings.marks.length).toEqual(chart.marks.length); - }); + describe('chart object has marks property', () => { + it('marks property has the same length as settings.marks', () => { + expect(settings.marks.length).toEqual(chart.marks.length); }); }); -} +}); diff --git a/test/multiply/multiply.js b/test/multiply/multiply.js index 7b4514b..1542c54 100644 --- a/test/multiply/multiply.js +++ b/test/multiply/multiply.js @@ -3,11 +3,10 @@ import createChart from '../../src/createChart'; import multiply from '../../src/multiply'; import expect from 'expect'; import irisData from '../samples/irisData'; -import { linear_linear as irisSettings } from '../samples/irisSettings'; -import clone from '../../src/util/clone'; -import { selectAll } from 'd3'; +import irisSettings from '../samples/irisSettings'; +import chartProto from '../../src/chart/index'; -describe('chart.multiply()', () => { +describe('chart multiply', () => { const { JSDOM } = jsdom; let dom, container, chart; @@ -30,24 +29,5 @@ describe('chart.multiply()', () => { it('multiple object should link back to master chart', () => { expect(chart.multiples[0].parent).toEqual(chart); }); - - it('a single legend should exist inside the parent node of the multiples', () => { - expect(chart.wrap.selectAll('.legend').size()).toEqual(1); - }); - - it('appears after multiples by default', () => { - const nodes = chart.wrap.node().querySelectorAll('div,ul'); - expect(nodes[nodes.length - 1]).toEqual(chart.master_legend.node()); - }); - - it('appears before multiples if legend location is set to top', () => { - const topLegendSettings = clone(irisSettings); - topLegendSettings.legend.location = 'top'; - chart = createChart(container, topLegendSettings); - multiply(chart, irisData, 'Species', null, true); - - const nodes = chart.wrap.node().querySelectorAll('div,ul'); - expect(nodes[0]).toEqual(chart.master_legend.node()); - }); }); }); diff --git a/test/samples/irisSettings.js b/test/samples/irisSettings.js index 95b05e0..8768b6e 100644 --- a/test/samples/irisSettings.js +++ b/test/samples/irisSettings.js @@ -1,4 +1,4 @@ -export const linear_linear = { +export default { x: { type: 'linear', column: 'Sepal.Length', @@ -15,6 +15,9 @@ export const linear_linear = { per: ['Sepal.Length', 'Sepal.Width'], summarizeX: 'mean', summarizeY: 'mean', + values: { + Species: ['setosa', 'versicolor', 'virginica'] + } }, { type: 'circle', @@ -38,113 +41,3 @@ export const linear_linear = { color_by: 'Species', legend: {} }; - -export const ordinal_linear = { - x: { - type: 'ordinal', - column: 'Species', - label: 'Species' - }, - y: { - type: 'linear', - column: 'Sepal.Length', - label: 'Sepal Length' - }, - marks: [ - { - type: 'bar', - per: ['Species'], - summarizeY: 'mean', - }, - { - type: 'circle', - per: ['Species'], - summarizeY: 'min' - }, - { - type: 'circle', - per: ['Species'], - summarizeY: 'median' - }, - { - type: 'circle', - per: ['Species'], - summarizeY: 'max' - }, - ], - color_by: 'Species', - legend: {}, - padding: 0, - outer_pad: 0, -}; - -export const linear_ordinal = { - x: { - type: 'linear', - column: 'Sepal.Length', - label: 'Sepal Length' - }, - y: { - type: 'ordinal', - column: 'Species', - label: 'Species' - }, - marks: [ - { - type: 'bar', - per: ['Species'], - summarizeX: 'mean', - }, - { - type: 'circle', - per: ['Species'], - summarizeX: 'min' - }, - { - type: 'circle', - per: ['Species'], - summarizeX: 'median' - }, - { - type: 'circle', - per: ['Species'], - summarizeX: 'max' - }, - ], - color_by: 'Species', - legend: {}, - padding: 0, - outer_pad: 0, -}; - -export const ordinal_ordinal = { - x: { - type: 'ordinal', - column: 'Species', - label: 'Species' - }, - y: { - type: 'ordinal', - column: 'Species', - label: 'Species' - }, - marks: [ - { - type: 'bar', - per: ['Species'], - }, - { - type: 'circle', - per: ['Species'], - }, - { - type: 'text', - per: ['Species'], - text: '$x - $y', - }, - ], - color_by: 'Species', - legend: {}, - padding: 0, - outer_pad: 0, -}; diff --git a/test/table/bindTableToDOM.js b/test/table/bindTableToDOM.js deleted file mode 100644 index 0b09339..0000000 --- a/test/table/bindTableToDOM.js +++ /dev/null @@ -1,32 +0,0 @@ -import jsdom from 'jsdom'; -import createTable from '../../src/createTable'; -import expect from 'expect'; - -export default function bindTableToDOM(settings, data) { - describe('table object in DOM', () => { - const { JSDOM } = jsdom; - let dom, container, table; - - before(() => { - dom = new JSDOM(''); - container = dom.window.document.createElement('div'); - }); - - beforeEach(() => { - table = createTable(container, settings).init(data, true); - }); - - afterEach(() => { - }); - - describe('user calls table init() method', () => { - it('binds table object to parent of table node', () => { - expect(table.wrap.datum()).toEqual(table); - }); - - it('binds table data to table node', () => { - expect(table.table.datum()).toEqual(table.data.current); - }); - }); - }); -} diff --git a/test/table/init.js b/test/table/init.js deleted file mode 100644 index 8322c47..0000000 --- a/test/table/init.js +++ /dev/null @@ -1,66 +0,0 @@ -import jsdom from 'jsdom'; -import createTable from '../../src/createTable'; -import expect from 'expect'; - -export default function testInit(settings, data) { - describe('table initialization and lifecycle', () => { - const { JSDOM } = jsdom; - let dom, container, table; - - before(() => { - dom = new JSDOM(''); - container = dom.window.document.createElement('div'); - }); - - beforeEach(() => { - table = createTable(container, settings); - - expect.spyOn(table.events, 'onInit'); - expect.spyOn(table.events, 'onLayout'); - expect.spyOn(table.events, 'onPreprocess'); - expect.spyOn(table.events, 'onDraw'); - - table.init(data, true); - }); - - afterEach(() => { - container.children[0].remove(); - table = null; - }); - - describe('user calls table init() method', () => { - it('webCharts attaches raw data', () => { - expect(table.data.raw).toEqual(data); - }); - }); - - describe('should run all .on([lifecycle]) functions when initialized with marks specified in the config', () => { - it('should call onInit', () => { - expect(table.events.onInit).toHaveBeenCalled(); - }); - it('should call onLayout', () => { - expect(table.events.onLayout).toHaveBeenCalled(); - }); - it('should call onPreprocess', () => { - expect(table.events.onPreprocess).toHaveBeenCalled(); - }); - it('should call onDraw', () => { - expect(table.events.onDraw).toHaveBeenCalled(); - }); - }); - - describe('should run repeated .on([lifecycle]) functions when .draw() is called independently', () => { - beforeEach(() => { - table.draw(); - }); - it('onPreprocess has been called twice', () => { - expect(table.events.onPreprocess).toHaveBeenCalled(); - expect(table.events.onPreprocess.calls.length).toEqual(2); - }); - it('onDraw has been called twice', () => { - expect(table.events.onDraw).toHaveBeenCalled(); - expect(table.events.onDraw.calls.length).toEqual(2); - }); - }); - }); -} diff --git a/test/table/runTests.js b/test/table/runTests.js index a0816c3..f6075f2 100644 --- a/test/table/runTests.js +++ b/test/table/runTests.js @@ -1,25 +1,16 @@ import data from '../samples/irisData'; -import testInit from './init'; -testInit( +import testDestroyTable from './destroyTable'; +testDestroyTable( { exportable: false }, - data -); + data); import testSearchTable from './searchTable'; testSearchTable( { sortable: false, searchable: true, exportable: false, pagination: false }, - data -); + data); import testSortTable from './sortTable'; testSortTable( { sortable: true, searchable: false, exportable: false, pagination: false }, - data -); - -import testDestroyTable from './destroyTable'; -testDestroyTable( - { exportable: false }, - data -); + data); diff --git a/test/testNewUnitTests.js b/test/testNewUnitTests.js deleted file mode 100644 index 480fe08..0000000 --- a/test/testNewUnitTests.js +++ /dev/null @@ -1 +0,0 @@ -import './multiply/multiply';