diff --git a/Gruntfile.coffee b/Gruntfile.coffee index f6dc622c1..aa376eb8c 100644 --- a/Gruntfile.coffee +++ b/Gruntfile.coffee @@ -39,6 +39,7 @@ module.exports = (grunt) -> 'src/type.js', 'src/grid.js', 'src/tooltip.js', + 'src/ranges.js', 'src/legend.js', 'src/title.js', 'src/axis.js', diff --git a/c3.js b/c3.js index 46053b67d..54c5505fa 100644 --- a/c3.js +++ b/c3.js @@ -18,7 +18,7 @@ if (Object.create) { derived.prototype = Object.create(base.prototype); } else { - var f = function f() {}; + var f = function f() { }; f.prototype = base.prototype; derived.prototype = new f(); } @@ -293,10 +293,27 @@ $$.initGrid(); // Define g for chart area - main.append('g') + var mainChartArea = main.append('g'); + mainChartArea .attr("clip-path", $$.clipPath) .attr('class', CLASS.chart); + mainChartArea + .append('g') + .attr('class', 'c3-reference-vertical-range ng-hide') + .append('rect') + .attr('height', $$.height+"px") + .attr('width', $$.width+"px") + .attr('fill', 'rgba(0,0,255,0.2)'); + + mainChartArea + .append('g') + .attr('class', 'c3-reference-horizontal-range ng-hide') + .append('rect') + .attr('height', $$.height+"px") + .attr('width', $$.width+"px") + .attr('fill', 'rgba(0,0,255,0.2)'); + // Grid lines if (config.grid_lines_front) { $$.initGridLines(); } @@ -337,6 +354,8 @@ }); } + if ($$.initRanges) { $$.initRanges(); } + // Bind resize event $$.bindResize(); @@ -461,7 +480,7 @@ c3_chart_internal_fn.showTargets = function () { var $$ = this; $$.svg.selectAll('.' + CLASS.target).filter(function (d) { return $$.isTargetToShow(d.id); }) - .transition().duration($$.config.transition_duration) + .transition().duration($$.config.transition_duration) .style("opacity", 1); }; @@ -584,7 +603,7 @@ .attr("x", $$.width / 2) .attr("y", $$.height / 2) .text(config.data_empty_label_text) - .transition() + .transition() .style('opacity', targetsToShow.length ? 0 : 1); // grid @@ -678,14 +697,14 @@ waitForDraw.add(t); }); }) - .call(waitForDraw, function () { - if (flow) { - flow(); - } - if (config.onrendered) { - config.onrendered.call($$); - } - }); + .call(waitForDraw, function () { + if (flow) { + flow(); + } + if (config.onrendered) { + config.onrendered.call($$); + } + }); } else { $$.redrawBar(drawBar); @@ -704,6 +723,7 @@ $$.mapToIds($$.data.targets).forEach(function (id) { $$.withoutFadeIn[id] = true; }); + $$.resizeRanges(); }; c3_chart_internal_fn.updateAndRedraw = function (options) { @@ -826,7 +846,7 @@ if (transitions && transitions.axisX) { xAxis = transitions.axisX; } else { - xAxis = $$.main.select('.' + CLASS.axisX); + xAxis = $$.main.select('.' + CLASS.axisX); if (withTransition) { xAxis = xAxis.transition(); } } if (transitions && transitions.axisY) { @@ -905,7 +925,7 @@ window.console.error("MutationObserver not defined."); return; } - observer= new MutationObserver(function (mutations) { + observer = new MutationObserver(function (mutations) { mutations.forEach(function (mutation) { if (mutation.type === 'childList' && mutation.previousSibling) { observer.disconnect(); @@ -931,7 +951,7 @@ } }); }); - observer.observe(selection.node(), {attributes: true, childList: true, characterData: true}); + observer.observe(selection.node(), { attributes: true, childList: true, characterData: true }); }; c3_chart_internal_fn.bindResize = function () { @@ -1188,7 +1208,7 @@ axis_y_label: {}, axis_y_tick_format: undefined, axis_y_tick_outer: true, - axis_y_tick_values: null, + axis_y_tick_values: null, axis_y_tick_rotate: 0, axis_y_tick_count: undefined, axis_y_tick_time_value: undefined, @@ -1251,6 +1271,7 @@ gauge_min: 0, gauge_max: 100, gauge_startingAngle: -1 * Math.PI/2, + gauge_label_extents: undefined, gauge_units: undefined, gauge_width: undefined, gauge_expand: {}, @@ -1292,16 +1313,18 @@ left: 0 }, title_position: 'top-center', + data_starterRangeIndex: undefined, + data_ranges: undefined, }; - + Object.keys(this.additionalConfig).forEach(function (key) { config[key] = this.additionalConfig[key]; }, this); - + return config; }; c3_chart_internal_fn.additionalConfig = {}; - + c3_chart_internal_fn.loadConfig = function (config) { var this_config = this.config, target, keys, read; function find() { @@ -1404,12 +1427,12 @@ $$.xAxisTickValues = $$.axis.getXAxisTickValues(); $$.yAxisTickValues = $$.axis.getYAxisTickValues(); $$.y2AxisTickValues = $$.axis.getY2AxisTickValues(); - + $$.xAxis = $$.axis.getXAxis($$.x, $$.xOrient, $$.xAxisTickFormat, $$.xAxisTickValues, config.axis_x_tick_outer); $$.subXAxis = $$.axis.getXAxis($$.subX, $$.subXOrient, $$.xAxisTickFormat, $$.xAxisTickValues, config.axis_x_tick_outer); $$.yAxis = $$.axis.getYAxis($$.y, $$.yOrient, config.axis_y_tick_format, $$.yAxisTickValues, config.axis_y_tick_outer); $$.y2Axis = $$.axis.getYAxis($$.y2, $$.y2Orient, config.axis_y2_tick_format, $$.y2AxisTickValues, config.axis_y2_tick_outer); - + // Set initialized scales to brush and zoom if (!forInit) { if ($$.brush) { $$.brush.scale($$.subX); } @@ -1496,11 +1519,11 @@ isInverted = axisId === 'y2' ? config.axis_y2_inverted : config.axis_y_inverted, showHorizontalDataLabel = $$.hasDataLabel() && config.axis_rotated, showVerticalDataLabel = $$.hasDataLabel() && !config.axis_rotated; - + // MEMO: avoid inverting domain unexpectedly yDomainMin = isValue(yMin) ? yMin : isValue(yMax) ? (yDomainMin < yMax ? yDomainMin : yMax - 10) : yDomainMin; yDomainMax = isValue(yMax) ? yMax : isValue(yMin) ? (yMin < yDomainMax ? yDomainMax : yMin + 10) : yDomainMax; - + if (yTargets.length === 0) { // use current domain if target of axisId is none return axisId === 'y2' ? $$.y2.domain() : $$.y.domain(); } @@ -1515,21 +1538,21 @@ } isAllPositive = yDomainMin >= 0 && yDomainMax >= 0; isAllNegative = yDomainMin <= 0 && yDomainMax <= 0; - + // Cancel zerobased if axis_*_min / axis_*_max specified if ((isValue(yMin) && isAllPositive) || (isValue(yMax) && isAllNegative)) { isZeroBased = false; } - + // Bar/Area chart should be 0-based if all positive|negative if (isZeroBased) { if (isAllPositive) { yDomainMin = 0; } if (isAllNegative) { yDomainMax = 0; } } - + domainLength = Math.abs(yDomainMax - yDomainMin); padding = padding_top = padding_bottom = domainLength * 0.1; - + if (typeof center !== 'undefined') { yDomainAbs = Math.max(Math.abs(yDomainMin), Math.abs(yDomainMax)); yDomainMax = center + yDomainAbs; @@ -1623,7 +1646,7 @@ }; c3_chart_internal_fn.updateXDomain = function (targets, withUpdateXDomain, withUpdateOrgXDomain, withTrim, domain) { var $$ = this, config = $$.config; - + if (withUpdateOrgXDomain) { $$.x.domain(domain ? domain : $$.d3.extent($$.getXDomain(targets))); $$.orgXDomain = $$.x.domain(); @@ -1635,10 +1658,10 @@ $$.x.domain(domain ? domain : (!$$.brush || $$.brush.empty()) ? $$.orgXDomain : $$.brush.extent()); if (config.zoom_enabled) { $$.zoom.scale($$.x).updateScaleExtent(); } } - + // Trim domain when too big by zoom mousemove event if (withTrim) { $$.x.domain($$.trimXDomain($$.x.orgDomain())); } - + return $$.x.domain(); }; c3_chart_internal_fn.trimXDomain = function (domain) { @@ -1950,21 +1973,21 @@ } return sames; }; - + c3_chart_internal_fn.findClosestFromTargets = function (targets, pos) { var $$ = this, candidates; - + // map to array of closest points of each target candidates = targets.map(function (target) { return $$.findClosest(target.values, pos); }); - + // decide closest point and return return $$.findClosest(candidates, pos); }; c3_chart_internal_fn.findClosest = function (values, pos) { var $$ = this, minDist = $$.config.point_sensitivity, closest; - + // find mouseovering bar values.filter(function (v) { return v && $$.isBarType(v.id); }).forEach(function (v) { var shape = $$.main.select('.' + CLASS.bars + $$.getTargetSelectorSuffix(v.id) + ' .' + CLASS.bar + '-' + v.index).node(); @@ -1972,7 +1995,7 @@ closest = v; } }); - + // find closest point from non-bar values.filter(function (v) { return v && !$$.isBarType(v.id); }).forEach(function (v) { var d = $$.dist(v, pos); @@ -1981,7 +2004,7 @@ closest = v; } }); - + return closest; }; c3_chart_internal_fn.dist = function (data, pos) { @@ -1994,15 +2017,15 @@ }; c3_chart_internal_fn.convertValuesToStep = function (values) { var converted = [].concat(values), i; - + if (!this.isCategorized()) { return values; } - + for (i = values.length + 1; 0 < i; i--) { converted[i] = converted[i - 1]; } - + converted[0] = { x: converted[0].x - 1, value: converted[0].value, @@ -2013,7 +2036,7 @@ value: converted[values.length].value, id: converted[values.length].id }; - + return converted; }; c3_chart_internal_fn.updateDataAttributes = function (name, attrs) { @@ -2148,11 +2171,11 @@ ids = $$.d3.keys(data[0]).filter($$.isNotX, $$), xs = $$.d3.keys(data[0]).filter($$.isX, $$), targets; - + // save x for update data by load when custom x and c3.x API ids.forEach(function (id) { var xKey = $$.getXKey(id); - + if ($$.isCustomX() || $$.isTimeSeries()) { // if included in input data if (xs.indexOf(xKey) >= 0) { @@ -2175,15 +2198,15 @@ $$.data.xs[id] = data.map(function (d, i) { return i; }); } }); - - + + // check x is defined ids.forEach(function (id) { if (!$$.data.xs[id]) { throw new Error('x is not defined for id = "' + id + '".'); } }); - + // convert to target targets = ids.map(function (id, index) { var convertedId = config.data_idConverter(id); @@ -2204,10 +2227,10 @@ config.axis_x_categories.push(rawX); } } else { - x = config.axis_x_categories.indexOf(rawX); + x = config.axis_x_categories.indexOf(rawX); if (x === -1) { x = $$.generateTargetX(rawX, id, i); - } + } } // mark as x = undefined if value is undefined and filter to remove after mapped if (isUndefined(d[id]) || $$.data.xs[id].length <= i) { @@ -2217,7 +2240,7 @@ }).filter(function (v) { return isDefined(v.x); }) }; }); - + // finish targets targets.forEach(function (t) { var i; @@ -2239,21 +2262,21 @@ return v1 - v2; }); }); - + // cache information about values $$.hasNegativeValue = $$.hasNegativeValueInTargets(targets); $$.hasPositiveValue = $$.hasPositiveValueInTargets(targets); - + // set target types if (config.data_type) { $$.setTargetType($$.mapToIds(targets).filter(function (id) { return ! (id in config.data_types); }), config.data_type); } - + // cache as original id keyed targets.forEach(function (d) { $$.addCache(d.id_org, d); }); - + return targets; }; @@ -2283,13 +2306,13 @@ }); $$.data.targets = $$.data.targets.concat(targets); // add remained } - + // Set targets $$.updateTargets($$.data.targets); - + // Redraw with new targets $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true, withLegend: true}); - + if (args.done) { args.done(); } }; c3_chart_internal_fn.loadFromArgs = function (args) { @@ -2361,19 +2384,19 @@ var $$ = this, config = $$.config, eventRectUpdate, maxDataCountTarget, isMultipleX = $$.isMultipleX(); - + // rects for mouseover var eventRects = $$.main.select('.' + CLASS.eventRects) .style('cursor', config.zoom_enabled ? config.axis_rotated ? 'ns-resize' : 'ew-resize' : null) .classed(CLASS.eventRectsMultiple, isMultipleX) .classed(CLASS.eventRectsSingle, !isMultipleX); - + // clear old rects eventRects.selectAll('.' + CLASS.eventRect).remove(); - + // open as public variable $$.eventRect = eventRects.selectAll('.' + CLASS.eventRect); - + if (isMultipleX) { eventRectUpdate = $$.eventRect.data([0]); // enter : only one rect will be added @@ -2399,10 +2422,10 @@ c3_chart_internal_fn.updateEventRect = function (eventRectUpdate) { var $$ = this, config = $$.config, x, y, w, h, rectW, rectX; - + // set update selection if null eventRectUpdate = eventRectUpdate || $$.eventRect.data(function (d) { return d; }); - + if ($$.isMultipleX()) { // TODO: rotated not supported yet x = 0; @@ -2412,34 +2435,34 @@ } else { if (($$.isCustomX() || $$.isTimeSeries()) && !$$.isCategorized()) { - + // update index for x that is used by prevX and nextX $$.updateXs(); - + rectW = function (d) { var prevX = $$.getPrevX(d.index), nextX = $$.getNextX(d.index); - + // if there this is a single data point make the eventRect full width (or height) if (prevX === null && nextX === null) { return config.axis_rotated ? $$.height : $$.width; } - + if (prevX === null) { prevX = $$.x.domain()[0]; } if (nextX === null) { nextX = $$.x.domain()[1]; } - + return Math.max(0, ($$.x(nextX) - $$.x(prevX)) / 2); }; rectX = function (d) { var prevX = $$.getPrevX(d.index), nextX = $$.getNextX(d.index), thisX = $$.data.xs[d.id][d.index]; - + // if there this is a single data point position the eventRect at 0 if (prevX === null && nextX === null) { return 0; } - + if (prevX === null) { prevX = $$.x.domain()[0]; } - + return ($$.x(thisX) + $$.x(prevX)) / 2; }; } else { @@ -2453,7 +2476,7 @@ w = config.axis_rotated ? $$.width : rectW; h = config.axis_rotated ? rectW : $$.height; } - + eventRectUpdate .attr('class', $$.classEvent.bind($$)) .attr("x", x) @@ -2468,14 +2491,14 @@ .style("cursor", config.data_selection_enabled && config.data_selection_grouped ? "pointer" : null) .on('mouseover', function (d) { var index = d.index; - + if ($$.dragging || $$.flowing) { return; } // do nothing while dragging/flowing if ($$.hasArcType()) { return; } - + // Expand shapes for selection if (config.point_focus_expand_enabled) { $$.expandCircles(index, null, true); } $$.expandBars(index, null, true); - + // Call event handler $$.main.selectAll('.' + CLASS.shape + '-' + index).each(function (d) { config.data_onmouseover.call($$.api, d); @@ -2498,28 +2521,28 @@ .on('mousemove', function (d) { var selectedData, index = d.index, eventRect = $$.svg.select('.' + CLASS.eventRect + '-' + index); - + if ($$.dragging || $$.flowing) { return; } // do nothing while dragging/flowing if ($$.hasArcType()) { return; } - + if ($$.isStepType(d) && $$.config.line_step_type === 'step-after' && d3.mouse(this)[0] < $$.x($$.getXValue(d.id, index))) { index -= 1; } - + // Show tooltip selectedData = $$.filterTargetsToShow($$.data.targets).map(function (t) { return $$.addName($$.getValueOnIndex(t.values, index)); }); - + if (config.tooltip_grouped) { $$.showTooltip(selectedData, this); $$.showXGridFocus(selectedData); } - + if (config.tooltip_grouped && (!config.data_selection_enabled || config.data_selection_grouped)) { return; } - + $$.main.selectAll('.' + CLASS.shape + '-' + index) .each(function () { d3.select(this).classed(CLASS.EXPANDED, true); @@ -2576,10 +2599,10 @@ ) : function () {} ); }; - + c3_chart_internal_fn.generateEventRectsForMultipleXs = function (eventRectEnter) { var $$ = this, d3 = $$.d3, config = $$.config; - + function mouseout() { $$.svg.select('.' + CLASS.eventRect).style('cursor', null); $$.hideXGridFocus(); @@ -2587,7 +2610,7 @@ $$.unexpandCircles(); $$.unexpandBars(); } - + eventRectEnter.append('rect') .attr('x', 0) .attr('y', 0) @@ -2602,44 +2625,44 @@ .on('mousemove', function () { var targetsToShow = $$.filterTargetsToShow($$.data.targets); var mouse, closest, sameXData, selectedData; - + if ($$.dragging) { return; } // do nothing when dragging if ($$.hasArcType(targetsToShow)) { return; } - + mouse = d3.mouse(this); closest = $$.findClosestFromTargets(targetsToShow, mouse); - + if ($$.mouseover && (!closest || closest.id !== $$.mouseover.id)) { config.data_onmouseout.call($$.api, $$.mouseover); $$.mouseover = undefined; } - + if (! closest) { mouseout(); return; } - + if ($$.isScatterType(closest) || !config.tooltip_grouped) { sameXData = [closest]; } else { sameXData = $$.filterByX(targetsToShow, closest.x); } - + // show tooltip when cursor is close to some point selectedData = sameXData.map(function (d) { return $$.addName(d); }); $$.showTooltip(selectedData, this); - + // expand points if (config.point_focus_expand_enabled) { $$.expandCircles(closest.index, closest.id, true); } $$.expandBars(closest.index, closest.id, true); - + // Show xgrid focus line $$.showXGridFocus(selectedData); - + // Show cursor as pointer if point is close to mouse position if ($$.isBarType(closest.id) || $$.dist(closest, mouse) < config.point_sensitivity) { $$.svg.select('.' + CLASS.eventRect).style('cursor', 'pointer'); @@ -2653,7 +2676,7 @@ var targetsToShow = $$.filterTargetsToShow($$.data.targets); var mouse, closest; if ($$.hasArcType(targetsToShow)) { return; } - + mouse = d3.mouse(this); closest = $$.findClosestFromTargets(targetsToShow, mouse); if (! closest) { return; } @@ -2684,7 +2707,7 @@ x = box.left + (mouse ? mouse[0] : 0), y = box.top + (mouse ? mouse[1] : 0), event = document.createEvent("MouseEvents"); - + event.initMouseEvent(type, true, true, window, 0, x, y, x, y, false, false, false, false, 0, null); eventRect.dispatchEvent(event); @@ -2737,7 +2760,7 @@ return ceil10($$.getAxisWidthByAxisId('y2')) + legendWidthOnRight; } }; - + c3_chart_internal_fn.getParentRectValue = function (key) { var parent = this.selectChart.node(), v; while (parent && parent.tagName !== 'BODY') { @@ -2764,8 +2787,8 @@ var h = this.selectChart.style('height'); return h.indexOf('px') > 0 ? +h.replace('px', '') : 0; }; - - + + c3_chart_internal_fn.getSvgLeft = function (withoutRecompute) { var $$ = this, config = $$.config, hasLeftAxisRect = config.axis_rotated || (!config.axis_rotated && !config.axis_y_inner), @@ -2777,8 +2800,8 @@ svgLeft = svgRect.right - chartRect.left - (hasArc ? 0 : $$.getCurrentPaddingLeft(withoutRecompute)); return svgLeft > 0 ? svgLeft : 0; }; - - + + c3_chart_internal_fn.getAxisWidthByAxisId = function (id, withoutRecompute) { var $$ = this, position = $$.axis.getLabelPositionById(id); return $$.axis.getMaxTickWidth(id, withoutRecompute) + (position.isInner ? 20 : 40); @@ -2801,7 +2824,7 @@ } return h + ($$.axis.getLabelPositionById(axisId).isInner ? 0 : 10) + (axisId === 'y2' ? -10 : 0); }; - + c3_chart_internal_fn.getEventRectWidth = function () { return Math.max(0, this.xAxis.tickInterval()); }; @@ -2881,8 +2904,8 @@ } return isWithin; }; - - + + c3_chart_internal_fn.getInterpolate = function (d) { var $$ = this, interpolation = $$.isInterpolationType($$.config.spline_interpolation_type) ? $$.config.spline_interpolation_type : 'cardinal'; @@ -2962,7 +2985,7 @@ yValue = function (d, i) { return config.data_groups.length > 0 ? getPoints(d, i)[0][1] : yScaleGetter.call($$, d.id)(d.value); }; - + line = config.axis_rotated ? line.x(yValue).y(xValue) : line.x(xValue).y(yValue); if (!config.line_connectNull) { line = line.defined(function (d) { return d.value != null; }); } return function (d) { @@ -3009,8 +3032,8 @@ ]; }; }; - - + + c3_chart_internal_fn.lineWithRegions = function (d, x, y, _regions) { var $$ = this, config = $$.config, prev = -1, i, j, @@ -3019,7 +3042,7 @@ xOffset = $$.isCategorized() ? 0.5 : 0, xValue, yValue, regions = []; - + function isWithinRegions(x, regions) { var i; for (i = 0; i < regions.length; i++) { @@ -3027,7 +3050,7 @@ } return false; } - + // Check start/end of regions if (isDefined(_regions)) { for (i = 0; i < _regions.length; i++) { @@ -3044,11 +3067,11 @@ } } } - + // Set scales xValue = config.axis_rotated ? function (d) { return y(d.value); } : function (d) { return x(d.x); }; yValue = config.axis_rotated ? function (d) { return x(d.x); } : function (d) { return y(d.value); }; - + // Define svg generator function for region function generateM(points) { return 'M' + points[0][0] + ' ' + points[0][1] + ' ' + points[1][0] + ' ' + points[1][1]; @@ -3077,10 +3100,10 @@ return generateM(points); }; } - + // Generate for (i = 0; i < d.length; i++) { - + // Draw as normal if (isUndefined(regions) || ! isWithinRegions(d[i].x, regions)) { s += " " + xValue(d[i]) + " " + yValue(d[i]); @@ -3089,24 +3112,24 @@ else { xp = $$.getScale(d[i - 1].x + xOffset, d[i].x + xOffset, $$.isTimeSeries()); yp = $$.getScale(d[i - 1].value, d[i].value); - + dx = x(d[i].x) - x(d[i - 1].x); dy = y(d[i].value) - y(d[i - 1].value); dd = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2)); diff = 2 / dd; diffx2 = diff * 2; - + for (j = diff; j <= 1; j += diffx2) { s += sWithRegion(d[i - 1], d[i], j, diff); } } prev = d[i].x; } - + return s; }; - - + + c3_chart_internal_fn.updateArea = function (durationForExit) { var $$ = this, d3 = $$.d3; $$.mainArea = $$.main.selectAll('.' + CLASS.areas).selectAll('.' + CLASS.area) @@ -3140,12 +3163,12 @@ value1 = function (d, i) { return config.data_groups.length > 0 ? getPoints(d, i)[1][1] : yScaleGetter.call($$, d.id)(d.value); }; - + area = config.axis_rotated ? area.x0(value0).x1(value1).y(xValue) : area.x(xValue).y0(config.area_above ? 0 : value0).y1(value1); if (!config.line_connectNull) { area = area.defined(function (d) { return d.value !== null; }); } - + return function (d) { var values = config.line_connectNull ? $$.filterRemoveNull(d.values) : d.values, x0 = 0, y0 = 0, path; @@ -3189,8 +3212,8 @@ ]; }; }; - - + + c3_chart_internal_fn.updateCircle = function () { var $$ = this; $$.mainCircle = $$.main.selectAll('.' + CLASS.circles).selectAll('.' + CLASS.circle) @@ -3297,7 +3320,7 @@ mainBarEnter.append('g') .attr("class", classBars) .style("cursor", function (d) { return config.data_selection_isselectable(d) ? "pointer" : null; }); - + }; c3_chart_internal_fn.updateBar = function (durationForExit) { var $$ = this, @@ -3349,17 +3372,17 @@ return function (d, i) { // 4 points that make a bar var points = getPoints(d, i); - + // switch points if axis is rotated, not applicable for sub chart var indexX = config.axis_rotated ? 1 : 0; var indexY = config.axis_rotated ? 0 : 1; - + var path = 'M ' + points[0][indexX] + ',' + points[0][indexY] + ' ' + 'L' + points[1][indexX] + ',' + points[1][indexY] + ' ' + 'L' + points[2][indexX] + ',' + points[2][indexY] + ' ' + 'L' + points[3][indexX] + ',' + points[3][indexY] + ' ' + 'z'; - + return path; }; }; @@ -3651,7 +3674,7 @@ var $$ = this, config = $$.config, d3 = $$.d3, xgridData = $$.generateGridData(config.grid_x_type, $$.x), tickOffset = $$.isCategorized() ? $$.xAxis.tickOffset() : 0; - + $$.xgridAttr = config.axis_rotated ? { 'x1': 0, 'x2': $$.width, @@ -3663,7 +3686,7 @@ 'y1': 0, 'y2': $$.height }; - + $$.xgrid = $$.main.select('.' + CLASS.xgrids).selectAll('.' + CLASS.xgrid) .data(xgridData); $$.xgrid.enter().append('line').attr("class", CLASS.xgrid); @@ -3673,7 +3696,7 @@ } $$.xgrid.exit().remove(); }; - + c3_chart_internal_fn.updateYGrid = function () { var $$ = this, config = $$.config, gridValues = $$.yAxis.tickValues() || $$.y.ticks(config.grid_y_ticks); @@ -3688,7 +3711,7 @@ $$.ygrid.exit().remove(); $$.smoothLines($$.ygrid, 'grid'); }; - + c3_chart_internal_fn.gridTextAnchor = function (d) { return d.position ? d.position : "end"; }; @@ -3704,10 +3727,10 @@ c3_chart_internal_fn.updateGrid = function (duration) { var $$ = this, main = $$.main, config = $$.config, xgridLine, ygridLine, yv; - + // hide if arc type $$.grid.style('visibility', $$.hasArcType() ? 'hidden' : 'visible'); - + main.select('line.' + CLASS.xgridFocus).style("visibility", "hidden"); if (config.grid_x_show) { $$.updateXGrid(); @@ -3731,7 +3754,7 @@ $$.xgridLines.exit().transition().duration(duration) .style("opacity", 0) .remove(); - + // Y-Grid if (config.grid_y_show) { $$.updateYGrid(); @@ -3892,7 +3915,7 @@ valueFormat = config.tooltip_format_value || defaultValueFormat, text, i, title, value, name, bgcolor, orderAsc = $$.isOrderAsc(); - + if (config.data_groups.length === 0) { d.sort(function(a, b){ var v1 = a ? a.value : null, v2 = b ? b.value : null; @@ -3911,22 +3934,22 @@ return orderAsc ? v1 - v2 : v2 - v1; }); } - + for (i = 0; i < d.length; i++) { if (! (d[i] && (d[i].value || d[i].value === 0))) { continue; } - + if (! text) { title = sanitise(titleFormat ? titleFormat(d[i].x) : d[i].x); text = "" + (title || title === 0 ? "" : ""); } - + value = sanitise(valueFormat(d[i].value, d[i].ratio, d[i].id, d[i].index, d)); if (value !== undefined) { // Skip elements when their name is set to null if (d[i].name === null) { continue; } name = sanitise(nameFormat(d[i].name, d[i].ratio, d[i].id, d[i].index)); bgcolor = $$.levelColor ? $$.levelColor(d[i].value) : color(d[i].id); - + text += ""; text += ""; text += ""; @@ -3957,7 +3980,7 @@ chartRight = svgLeft + $$.currentWidth - $$.getCurrentPaddingRight(); tooltipTop = mouse[1] + 15; } - + if (tooltipRight > chartRight) { // 20 is needed for Firefox to keep tooltip width tooltipLeft -= tooltipRight - chartRight + 20; @@ -3981,11 +4004,11 @@ return; } $$.tooltip.html(config.tooltip_contents.call($$, selectedData, $$.axis.getXAxisTickFormat(), $$.getYFormat(forArc), $$.color)).style("display", "block"); - + // Get tooltip dimensions tWidth = $$.tooltip.property('offsetWidth'); tHeight = $$.tooltip.property('offsetHeight'); - + position = positionFunction.call(this, dataToShow, tWidth, tHeight, element); // Set tooltip $$.tooltip @@ -3996,6 +4019,262 @@ this.tooltip.style("display", "none"); }; + c3_chart_internal_fn.initRanges = function () { + var $$ = this; + var verticalRange = $$.selectChart.append("div").attr('class', 'slider-vertical ng-hide').attr('id', "slider-distance").style('height', $$.height + 'px'); + var divVertical = verticalRange.append("div"); + divVertical.append("div").attr('class', 'inverse-down').style('height', '0%'); + divVertical.append("div").attr('class', 'inverse-up').style('height', '0%'); + divVertical.append("div").attr('class', 'range').style('top', '0%').style('bottom', '0%'); + divVertical.append("span").attr('class', 'thumb thumb-down').style('bottom', '0%'); + divVertical.append("span").attr('class', 'thumb thumb-up').style('bottom', $$.height - 15 + 'px'); + var downInput = verticalRange.append("input"); + var upInput = verticalRange.append("input"); + downInput.attr("id", 'down').attr('class', 'down').style('-webkit-appearance', 'slider-vertical').attr("value", $$.y.domain()[0]).attr('min', $$.y.domain()[0]).attr('max', $$.y.domain()[1]).attr('step', '0.1').attr('type', 'range').on('input', function () { + var parent = $$.selectChart.select('.slider-vertical'); + var up = parent.select('#up'); + var divVertical = parent.select('div'); + + this.value = Math.min(this.value, up.attr('value') - 0.1); + parent.select('input#down').attr('value', this.value); + $$.verticalStartValue = this.value; + + var results = $$.calculateHorizontalRangePosition(this.min, this.max); + + divVertical.select('.inverse-down').style('height', results.realHeight + 'px'); + divVertical.select('.range').style('bottom', results.realHeight + 'px'); + divVertical.select('span.thumb-down').style('bottom', results.buttonDown + 'px'); + + $$.updateReferenceRange('.' + CLASS.REFERENCE_HORIZONTAL_RANGE, 'translate(0px, ' + results.translate + 'px)', results.totalHeight + 'px', null); + }); + upInput.attr("id", 'up').attr('class', 'up').style('-webkit-appearance', 'slider-vertical').attr("value", $$.y.domain()[1]).attr('min', $$.y.domain()[0]).attr('max', $$.y.domain()[1]).attr('step', '0.1').attr('type', 'range').on('input', function () { + var parent = $$.selectChart.select('.slider-vertical'); + var down = parent.select('#down'); + var divVertical = parent.select('div'); + + this.value = Math.max(this.value, down.attr('value') - -0.1); + parent.select('input#up').attr('value', this.value); + $$.verticalEndValue = this.value; + + var results = $$.calculateHorizontalRangePosition(this.min, this.max); + + divVertical.select('.inverse-up').style('height', results.translate + 'px'); + divVertical.select('.range').style('top', results.translate + 'px'); + divVertical.select('span.thumb-up').style('bottom', results.buttonUp + 'px'); + + $$.updateReferenceRange('.' + CLASS.REFERENCE_HORIZONTAL_RANGE, 'translate(0px, ' + results.translate + 'px)', results.totalHeight + 'px', null); + }); + + $$.horizontalRange = $$.d3.select('[graph-id="' + $$.config.bindto.replace('#', '') + '"] .slider-horizontal').style('width', $$.width + 'px').style('left', $$.margin.left + 'px').style('position', 'relative'); + $$.horizontalRange.selectAll('input').remove(); + $$.horizontalRange.selectAll('div').remove(); + var divHorizontal = $$.horizontalRange.append("div"); + divHorizontal.append("div").attr('class', 'inverse-left').style('width', '0%'); + divHorizontal.append("div").attr('class', 'inverse-right').style('width', '0%'); + divHorizontal.append("div").attr('class', 'range').style('right', '0%').style('left', '0%'); + divHorizontal.append("span").attr('class', 'thumb thumb-left').style('left', '0%'); + divHorizontal.append("span").attr('class', 'thumb thumb-right').style('left', $$.width - 15 + 'px'); + + var leftInput = $$.horizontalRange.append("input"); + var rightInput = $$.horizontalRange.append("input"); + leftInput.attr("id", 'left').attr("class", 'left').attr("value", $$.x.domain()[0]).attr('min', $$.x.domain()[0]).attr('max', $$.x.domain()[1]-1).attr('step', '0.1').attr('type', 'range').on('input', function () { + var parent = $$.d3.select('[graph-id="' + $$.config.bindto.replace('#', '') + '"] .slider-horizontal'); + var right = parent.select('#right'); + var divHorizontal = parent.select('div'); + + this.value = Math.min(this.value, right.attr('value') - 0.1); + parent.select('input#left').attr('value', this.value); + $$.horizontalStartValue = this.value; + + var results = $$.calculateVerticalRangePosition(this.min, this.max); + + divHorizontal.select('.range').style('left', results.translate + 'px'); + divHorizontal.select('.inverse-left').style('width', results.translate + 'px'); + divHorizontal.select('span.thumb-left').style('left', results.buttonLeft + 'px'); + + $$.updateReferenceRange('.' + CLASS.REFERENCE_VERTICAL_RANGE, 'translate(' + results.translate + 'px)', null, results.totalWidth + 'px'); + }); + rightInput.attr("id", 'right').attr("class", 'right').attr("value", $$.x.domain()[1]).attr('min', $$.x.domain()[0]).attr('max', $$.x.domain()[1]-1).attr('step', '0.1').attr('type', 'range').on('input', function () { + var parent = $$.d3.select('[graph-id="' + $$.config.bindto.replace('#', '') + '"] .slider-horizontal'); + var left = parent.select('#left'); + var divHorizontal = parent.select('div'); + + this.value = Math.max(this.value, left.attr('value') - -0.1); + parent.select('input#right').attr('value', this.value); + $$.horizontalEndValue = this.value; + + var results = $$.calculateVerticalRangePosition(this.min, this.max); + + divHorizontal.select('.inverse-right').style('width', results.rightValue + 'px'); + divHorizontal.select('.range').style('right', results.rightValue + 'px'); + divHorizontal.select('span.thumb-right').style('left', results.buttonRight + 'px'); + + $$.updateReferenceRange('.' + CLASS.REFERENCE_VERTICAL_RANGE, 'translate(' + results.translate + 'px)', null, results.totalWidth + 'px'); + }); + }; + + c3_chart_internal_fn.calculateHorizontalRangePosition = function (min, max) { + var $$ = this; + var factorEnd = max - min; + var yToPercentEnd = ($$.verticalEndValue - $$.y.domain()[0]) * 100 / factorEnd; + var resultEnd = $$.height * yToPercentEnd / 100; + + var factorStart = max - min; + var yToPercentStart = ($$.verticalStartValue - $$.y.domain()[0]) * 100 / factorStart; + var resultStart = $$.height * yToPercentStart / 100; + + var paddingValueUpButton = 15 * yToPercentEnd / 100; + var paddingValueDownButton = 15 * yToPercentStart / 100; + + return { + translate: $$.height - resultEnd, + buttonUp: resultEnd - paddingValueUpButton, + buttonDown: resultStart - paddingValueDownButton, + totalHeight: resultEnd - resultStart, + realHeight: resultStart, + }; + }; + + c3_chart_internal_fn.calculateVerticalRangePosition = function (min, max) { + var $$ = this; + var factorEnd = max - min; + var xToPercentEnd = ($$.horizontalEndValue - min) * 100 / factorEnd; + var resultEnd = $$.width * xToPercentEnd / 100; + + var factorStart = max - min; + var xToPercentStart = ($$.horizontalStartValue - min) * 100 / factorStart; + var resultStart = $$.width * xToPercentStart / 100; + + var paddingValueRightButton = 15 * xToPercentEnd / 100; + var paddingValueLeftButton = 15 * xToPercentStart / 100; + + return { + rightValue: $$.width - resultEnd, + buttonRight: resultEnd - paddingValueRightButton, + buttonLeft: resultStart - paddingValueLeftButton, + translate: resultStart, + totalWidth: resultEnd - resultStart + }; + }; + c3_chart_internal_fn.resizeRanges = function () { + var $$ = this; + + + var verticalRange = $$.selectChart.select("#slider-distance"); + verticalRange.style('height', $$.height + 'px'); + $$.horizontalRange = $$.d3 + .select('[graph-id="' + $$.config.bindto.replace('#', '') + '"] .slider-horizontal') + .style('width', $$.width + 'px') + .style('left', $$.margin.left + 'px'); + + + $$.setStartValuesRanges(); + }; + + c3_chart_internal_fn.setStartValuesRanges = function () { + var $$ = this; + var config = $$.config; + var starter = config.data_starterRangeIndex; + $$.updateRange(starter); + }; + + c3_chart_internal_fn.updateRange = function (index) { + var $$ = this; + var config = $$.config; + var range = config.data_ranges[index]; + if(!range){ + $$.updateVerticalRange($$.y.domain()[1], $$.y.domain()[0]); + $$.updateHorizontalRange($$.x.domain()[1]-1, $$.x.domain()[0]); + } else { + $$.updateVerticalRange(range.verticalEndValue, range.verticalStartValue); + $$.updateHorizontalRange(range.horizontalEndValue, range.horizontalStartValue); + } + }; + + c3_chart_internal_fn.updateHorizontalRange = function (horizontalEndValue, horizontalStartValue) { + var $$ = this; + $$.horizontalEndValue = horizontalEndValue; + $$.horizontalStartValue = horizontalStartValue; + + var max = $$.x.domain()[1] - 1; + var min = $$.x.domain()[0]; + var horizontalSlider = $$.d3.select('[graph-id="' + $$.config.bindto.replace('#', '') + '"] .slider-horizontal'); + var divHorizontal = horizontalSlider.select("div"); + + var results = $$.calculateVerticalRangePosition(min, max); + + horizontalSlider.select('input#right').attr('value', horizontalEndValue); + horizontalSlider.select('input#left').attr('value', horizontalStartValue); + + divHorizontal.select('.inverse-right').style('width', results.rightValue + 'px'); + divHorizontal.select('.range').style('right', results.rightValue + 'px'); + divHorizontal.select('span.thumb-right').style('left', results.buttonRight + 'px'); + + divHorizontal.select('.range').style('left', results.translate + 'px'); + divHorizontal.select('.inverse-left').style('width', results.translate + 'px'); + divHorizontal.select('span.thumb-left').style('left', results.buttonLeft + 'px'); + + $$.updateReferenceRange('.' + CLASS.REFERENCE_VERTICAL_RANGE, 'translate(' + results.translate + 'px)', null, results.totalWidth + 'px'); + }; + + c3_chart_internal_fn.updateVerticalRange = function (verticalEndValue, verticalStartValue) { + var $$ = this; + $$.verticalStartValue = verticalStartValue; + $$.verticalEndValue = verticalEndValue; + var max = $$.y.domain()[1]; + var min = $$.y.domain()[0]; + var verticalSlider = $$.selectChart.select("#slider-distance"); + + var divVertical = verticalSlider.select("div"); + + var results = $$.calculateHorizontalRangePosition(min, max); + + divVertical.select('.inverse-down').style('height', results.realHeight + 'px'); + divVertical.select('.range').style('bottom', results.realHeight + 'px'); + divVertical.select('span.thumb-down').style('bottom', results.buttonDown + 'px'); + + divVertical.select('.inverse-up').style('height', results.translate + 'px'); + divVertical.select('.range').style('top', results.translate + 'px'); + divVertical.select('span.thumb-up').style('bottom', results.buttonUp + 'px'); + + $$.updateReferenceRange('.' + CLASS.REFERENCE_HORIZONTAL_RANGE, 'translate(0px, ' + results.translate + 'px)', results.totalHeight + 'px', null); + }; + + c3_chart_internal_fn.updateReferenceRange = function (htmlClass, translate, height, width) { + var $$ = this; + $$.selectChart.select(htmlClass + ' rect').style('transform', translate); + if (height != null) { + $$.selectChart.select(htmlClass + ' rect').style('height', height); + } else if (width != null) { + $$.selectChart.select(htmlClass + ' rect').style('width', width); + } + }; + + c3_chart_internal_fn.setReferenceRange = function (index) { + this.updateRange(index); + }; + + c3_chart_internal_fn.setVerticalRange = function (firstValue, secondValue) { + var endValue = Math.max(firstValue, secondValue); + var startValue = Math.min(firstValue, secondValue); + + this.updateVerticalRange(endValue, startValue); + }; + + c3_chart_internal_fn.setHorizontalRange = function (firstValue, secondValue) { + var endValue = Math.max(firstValue, secondValue); + var startValue = Math.min(firstValue, secondValue); + + this.updateHorizontalRange(endValue, startValue); + }; + + c3_chart_internal_fn.setRangeVisible = function (visible) { + var divs = this.d3.selectAll('[graph-id="' + this.config.bindto.replace('#', '') + '"] .slider-vertical, .slider-horizontal, .c3-reference-vertical-range, .c3-reference-horizontal-range'); + divs.each(function () { + this.classList.toggle("ng-hide", !visible); + }); + }; + c3_chart_internal_fn.initLegend = function () { var $$ = this; $$.legendItemTextBox = {}; @@ -4019,7 +4298,7 @@ top: $$.isLegendTop ? $$.getCurrentPaddingTop() + config.legend_inset_y + 5.5 : $$.currentHeight - legendHeight - $$.getCurrentPaddingBottom() - config.legend_inset_y, left: $$.isLegendLeft ? $$.getCurrentPaddingLeft() + config.legend_inset_x + 0.5 : $$.currentWidth - legendWidth - $$.getCurrentPaddingRight() - config.legend_inset_x + 0.5 }; - + $$.margin3 = { top: $$.isLegendRight ? 0 : $$.isLegendInset ? insetLegendPosition.top : $$.currentHeight - legendHeight, right: NaN, @@ -4116,23 +4395,23 @@ var l, totalLength = 0, offsets = {}, widths = {}, heights = {}, margins = [0], steps = {}, step = 0; var withTransition, withTransitionForTransform; var texts, rects, tiles, background; - + // Skip elements when their name is set to null targetIds = targetIds.filter(function(id) { return !isDefined(config.data_names[id]) || config.data_names[id] !== null; }); - + options = options || {}; withTransition = getOption(options, "withTransition", true); withTransitionForTransform = getOption(options, "withTransitionForTransform", true); - + function getTextBox(textElement, id) { if (!$$.legendItemTextBox[id]) { $$.legendItemTextBox[id] = $$.getTextRect(textElement.textContent, CLASS.legendItem, textElement); } return $$.legendItemTextBox[id]; } - + function updatePositions(textElement, id, index) { var reset = index === 0, isLast = index === targetIds.length - 1, box = getTextBox(textElement, id), @@ -4141,7 +4420,7 @@ itemLength = $$.isLegendRight || $$.isLegendInset ? itemHeight : itemWidth, areaLength = $$.isLegendRight || $$.isLegendInset ? $$.getLegendHeight() : $$.getLegendWidth(), margin, maxLength; - + // MEMO: care about condifion of step, totalLength function updateValues(id, withoutStep) { if (!withoutStep) { @@ -4157,26 +4436,26 @@ offsets[id] = totalLength; totalLength += itemLength; } - + if (reset) { totalLength = 0; step = 0; maxWidth = 0; maxHeight = 0; } - + if (config.legend_show && !$$.isLegendToShow(id)) { widths[id] = heights[id] = steps[id] = offsets[id] = 0; return; } - + widths[id] = itemWidth; heights[id] = itemHeight; - + if (!maxWidth || itemWidth >= maxWidth) { maxWidth = itemWidth; } if (!maxHeight || itemHeight >= maxHeight) { maxHeight = itemHeight; } maxLength = $$.isLegendRight || $$.isLegendInset ? maxHeight : maxWidth; - + if (config.legend_equally) { Object.keys(widths).forEach(function (id) { widths[id] = maxWidth; }); Object.keys(heights).forEach(function (id) { heights[id] = maxHeight; }); @@ -4193,12 +4472,12 @@ updateValues(id); } } - + if ($$.isLegendInset) { step = config.legend_inset_step ? config.legend_inset_step : targetIds.length; $$.updateLegendStep(step); } - + if ($$.isLegendRight) { xForLegend = function (id) { return maxWidth * steps[id]; }; yForLegend = function (id) { return margins[steps[id]] + offsets[id]; }; @@ -4216,7 +4495,7 @@ x1ForLegendTile = function (id, i) { return xForLegend(id, i) - 2; }; x2ForLegendTile = function (id, i) { return xForLegend(id, i) - 2 + config.legend_item_tile_width; }; yForLegendTile = function (id, i) { return yForLegend(id, i) + 4; }; - + // Define g for legend area l = $$.legend.selectAll('.' + CLASS.legendItem) .data(targetIds) @@ -4277,7 +4556,7 @@ .attr('x2', $$.isLegendRight || $$.isLegendInset ? x2ForLegendTile : -200) .attr('y2', $$.isLegendRight || $$.isLegendInset ? -200 : yForLegendTile) .attr('stroke-width', config.legend_item_tile_height); - + // Set background for inset legend background = $$.legend.select('.' + CLASS.legendBackground + ' rect'); if ($$.isLegendInset && maxWidth > 0 && background.size() === 0) { @@ -4285,7 +4564,7 @@ .attr("class", CLASS.legendBackground) .append('rect'); } - + texts = $$.legend.selectAll('text') .data(targetIds) .text(function (id) { return isDefined(config.data_names[id]) ? config.data_names[id] : id; }) // MEMO: needed for update @@ -4293,7 +4572,7 @@ (withTransition ? texts.transition() : texts) .attr('x', xForLegendText) .attr('y', yForLegendText); - + rects = $$.legend.selectAll('rect.' + CLASS.legendItemEvent) .data(targetIds); (withTransition ? rects.transition() : rects) @@ -4301,7 +4580,7 @@ .attr('height', function (id) { return heights[id]; }) .attr('x', xForLegendRect) .attr('y', yForLegendRect); - + tiles = $$.legend.selectAll('line.' + CLASS.legendItemTile) .data(targetIds); (withTransition ? tiles.transition() : tiles) @@ -4310,17 +4589,17 @@ .attr('y1', yForLegendTile) .attr('x2', x2ForLegendTile) .attr('y2', yForLegendTile); - + if (background) { (withTransition ? background.transition() : background) .attr('height', $$.getLegendHeight() - 12) .attr('width', maxWidth * (step + 1) + 10); } - + // toggle legend state $$.legend.selectAll('.' + CLASS.legendItem) .classed(CLASS.legendItemHidden, function (id) { return !$$.isTargetToShow(id); }); - + // Update all to reflect change of legend $$.updateLegendItemWidth(maxWidth); $$.updateLegendItemHeight(maxHeight); @@ -4369,11 +4648,11 @@ function Axis(owner) { API.call(this, owner); } - + inherit(API, Axis); - + Axis.prototype.init = function init() { - + var $$ = this.owner, config = $$.config, main = $$.main; $$.axes.x = main.append("g") .attr("class", CLASS.axis + ' ' + CLASS.axisX) @@ -4393,7 +4672,7 @@ .attr("class", CLASS.axisYLabel) .attr("transform", config.axis_rotated ? "" : "rotate(-90)") .style("text-anchor", this.textAnchorForYAxisLabel.bind(this)); - + $$.axes.y2 = main.append("g") .attr("class", CLASS.axis + ' ' + CLASS.axisY2) // clip-path? @@ -4415,11 +4694,11 @@ withoutTransition: withoutTransition, }, axis = c3_axis($$.d3, axisParams).scale(scale).orient(orient); - + if ($$.isTimeSeries() && tickValues && typeof tickValues !== "function") { tickValues = tickValues.map(function (v) { return $$.parseDate(v); }); } - + // Set tick axis.tickFormat(tickFormat).tickValues(tickValues); if ($$.isCategorized()) { @@ -4428,7 +4707,7 @@ config.axis_x_tick_culling = false; } } - + return axis; }; Axis.prototype.updateXAxisTickValues = function updateXAxisTickValues(targets, axis) { @@ -4665,7 +4944,7 @@ $$.currentMaxTickWidths[id] = maxWidth <= 0 ? $$.currentMaxTickWidths[id] : maxWidth; return $$.currentMaxTickWidths[id]; }; - + Axis.prototype.updateLabels = function updateLabels(withTransition) { var $$ = this.owner; var axisXLabel = $$.main.select('.' + CLASS.axisX + ' .' + CLASS.axisXLabel), @@ -4818,7 +5097,7 @@ $$.pie.sort(null); } }; - + c3_chart_internal_fn.updateRadius = function () { var $$ = this, config = $$.config, w = config.gauge_width || config.donut_width; @@ -4827,23 +5106,23 @@ $$.innerRadiusRatio = w ? ($$.radius - w) / $$.radius : 0.6; $$.innerRadius = $$.hasType('donut') || $$.hasType('gauge') ? $$.radius * $$.innerRadiusRatio : 0; }; - + c3_chart_internal_fn.updateArc = function () { var $$ = this; $$.svgArc = $$.getSvgArc(); $$.svgArcExpanded = $$.getSvgArcExpanded(); $$.svgArcExpandedSub = $$.getSvgArcExpanded(0.98); }; - + c3_chart_internal_fn.updateAngle = function (d) { var $$ = this, config = $$.config, found = false, index = 0, gMin, gMax, gTic, gValue; - + if (!config) { return null; } - + $$.pie($$.filterTargetsToShow($$.data.targets)).forEach(function (t) { if (! found && t.data.id === d.data.id) { found = true; @@ -4868,7 +5147,7 @@ } return found ? d : null; }; - + c3_chart_internal_fn.getSvgArc = function () { var $$ = this, arc = $$.d3.svg.arc().outerRadius($$.radius).innerRadius($$.innerRadius), @@ -4882,7 +5161,7 @@ newArc.centroid = arc.centroid; return newArc; }; - + c3_chart_internal_fn.getSvgArcExpanded = function (rate) { var $$ = this, arc = $$.d3.svg.arc().outerRadius($$.radiusExpanded * (rate ? rate : 1)).innerRadius($$.innerRadius); @@ -4891,12 +5170,12 @@ return updated ? arc(updated) : "M 0 0"; }; }; - + c3_chart_internal_fn.getArc = function (d, withoutUpdate, force) { return force || this.isArcType(d.data) ? this.svgArc(d, withoutUpdate) : "M 0 0"; }; - - + + c3_chart_internal_fn.transformForArcLabel = function (d) { var $$ = this, config = $$.config, updated = $$.updateAngle(d), c, x, y, h, ratio, translate = ""; @@ -4916,14 +5195,14 @@ } return translate; }; - + c3_chart_internal_fn.getArcRatio = function (d) { var $$ = this, config = $$.config, whole = Math.PI * ($$.hasType('gauge') && !config.gauge_fullCircle ? 1 : 2); return d ? (d.endAngle - d.startAngle) / whole : null; }; - + c3_chart_internal_fn.convertToArcData = function (d) { return this.addName({ id: d.data.id, @@ -4932,7 +5211,7 @@ index: d.index }); }; - + c3_chart_internal_fn.textForArcLabel = function (d) { var $$ = this, updated, value, ratio, id, format; @@ -4945,10 +5224,17 @@ format = $$.getArcLabelFormat(); return format ? format(value, ratio, id) : $$.defaultArcValueFormat(value, ratio); }; - + + c3_chart_internal_fn.textForGaugeMinMax = function (value, isMax) { + var $$ = this, + format = $$.getGaugeLabelExtents(); + + return format ? format(value, isMax) : value; + }; + c3_chart_internal_fn.expandArc = function (targetIds) { var $$ = this, interval; - + // MEMO: avoid to cancel transition if ($$.transiting) { interval = window.setInterval(function () { @@ -4961,9 +5247,9 @@ }, 10); return; } - + targetIds = $$.mapToTargetIds(targetIds); - + $$.svg.selectAll($$.selectorTargets(targetIds, '.' + CLASS.chartArc)).each(function (d) { if (! $$.shouldExpand(d.data.id)) { return; } $$.d3.select(this).selectAll('path') @@ -4978,14 +5264,14 @@ }); }); }; - + c3_chart_internal_fn.unexpandArc = function (targetIds) { var $$ = this; - + if ($$.transiting) { return; } - + targetIds = $$.mapToTargetIds(targetIds); - + $$.svg.selectAll($$.selectorTargets(targetIds, '.' + CLASS.chartArc)).selectAll('path') .transition().duration(function(d) { return $$.expandDuration(d.data.id); @@ -4994,10 +5280,10 @@ $$.svg.selectAll('.' + CLASS.arc) .style("opacity", 1); }; - + c3_chart_internal_fn.expandDuration = function (id) { var $$ = this, config = $$.config; - + if ($$.isDonutType(id)) { return config.donut_expand_duration; } else if ($$.isGaugeType(id)) { @@ -5007,16 +5293,16 @@ } else { return 50; } - + }; - + c3_chart_internal_fn.shouldExpand = function (id) { var $$ = this, config = $$.config; return ($$.isDonutType(id) && config.donut_expand) || ($$.isGaugeType(id) && config.gauge_expand) || ($$.isPieType(id) && config.pie_expand); }; - + c3_chart_internal_fn.shouldShowArcLabel = function () { var $$ = this, config = $$.config, shouldShow = true; if ($$.hasType('donut')) { @@ -5027,13 +5313,13 @@ // when gauge, always true return shouldShow; }; - + c3_chart_internal_fn.meetsArcLabelThreshold = function (ratio) { var $$ = this, config = $$.config, threshold = $$.hasType('donut') ? config.donut_label_threshold : config.pie_label_threshold; return ratio >= threshold; }; - + c3_chart_internal_fn.getArcLabelFormat = function () { var $$ = this, config = $$.config, format = config.pie_label_format; @@ -5044,12 +5330,17 @@ } return format; }; - + + c3_chart_internal_fn.getGaugeLabelExtents = function () { + var $$ = this, config = $$.config; + return config.gauge_label_extents; + }; + c3_chart_internal_fn.getArcTitle = function () { var $$ = this; return $$.hasType('donut') ? $$.config.donut_title : ""; }; - + c3_chart_internal_fn.updateTargetsForArc = function (targets) { var $$ = this, main = $$.main, mainPieUpdate, mainPieEnter, @@ -5071,7 +5362,7 @@ // MEMO: can not keep same color..., but not bad to update color in redraw //mainPieUpdate.exit().remove(); }; - + c3_chart_internal_fn.initArc = function () { var $$ = this; $$.arcs = $$.main.select('.' + CLASS.chart).append("g") @@ -5082,7 +5373,7 @@ .style("text-anchor", "middle") .text($$.getArcTitle()); }; - + c3_chart_internal_fn.redrawArc = function (duration, durationForExit, withTransform) { var $$ = this, d3 = $$.d3, config = $$.config, main = $$.main, mainArc; @@ -5199,7 +5490,7 @@ .style("opacity", function (d) { return $$.isTargetToShow(d.data.id) && $$.isArcType(d.data) ? 1 : 0; }); main.select('.' + CLASS.chartArcsTitle) .style("opacity", $$.hasType('donut') || $$.hasType('gauge') ? 1 : 0); - + if ($$.hasType('gauge')) { $$.arcs.select('.' + CLASS.chartArcsBackground) .attr("d", function () { @@ -5216,11 +5507,11 @@ $$.arcs.select('.' + CLASS.chartArcsGaugeMin) .attr("dx", -1 * ($$.innerRadius + (($$.radius - $$.innerRadius) / (config.gauge_fullCircle ? 1 : 2))) + "px") .attr("dy", "1.2em") - .text(config.gauge_label_show ? config.gauge_min : ''); + .text(config.gauge_label_show ? $$.textForGaugeMinMax(config.gauge_min, false) : ''); $$.arcs.select('.' + CLASS.chartArcsGaugeMax) .attr("dx", $$.innerRadius + (($$.radius - $$.innerRadius) / (config.gauge_fullCircle ? 1 : 2)) + "px") .attr("dy", "1.2em") - .text(config.gauge_label_show ? config.gauge_max : ''); + .text(config.gauge_label_show ? $$.textForGaugeMinMax(config.gauge_max, true) : ''); } }; c3_chart_internal_fn.initGauge = function () { @@ -5254,10 +5545,10 @@ }; c3_chart_internal_fn.updateRegion = function (duration) { var $$ = this, config = $$.config; - + // hide if arc type $$.region.style('visibility', $$.hasArcType() ? 'hidden' : 'visible'); - + $$.mainRegion = $$.main.select('.' + CLASS.regions).selectAll('.' + CLASS.region) .data(config.regions); $$.mainRegion.enter().append('g') @@ -5338,12 +5629,12 @@ c3_chart_internal_fn.drag = function (mouse) { var $$ = this, config = $$.config, main = $$.main, d3 = $$.d3; var sx, sy, mx, my, minX, maxX, minY, maxY; - + if ($$.hasArcType()) { return; } if (! config.data_selection_enabled) { return; } // do nothing if not selectable if (config.zoom_enabled && ! $$.zoom.altDomain) { return; } // skip if zoomable because of conflict drag dehavior if (!config.data_selection_multiple) { return; } // skip when single selection because drag is used for multiple selection - + sx = $$.dragStart[0]; sy = $$.dragStart[1]; mx = mouse[0]; @@ -5352,7 +5643,7 @@ maxX = Math.max(sx, mx); minY = (config.data_selection_grouped) ? $$.margin.top : Math.min(sy, my); maxY = (config.data_selection_grouped) ? $$.height : Math.max(sy, my); - + main.select('.' + CLASS.dragarea) .attr('x', minX) .attr('y', minY) @@ -5392,7 +5683,7 @@ } }); }; - + c3_chart_internal_fn.dragstart = function (mouse) { var $$ = this, config = $$.config; if ($$.hasArcType()) { return; } @@ -5403,7 +5694,7 @@ .style('opacity', 0.1); $$.dragging = true; }; - + c3_chart_internal_fn.dragend = function () { var $$ = this, config = $$.config; if ($$.hasArcType()) { return; } @@ -5484,7 +5775,7 @@ var $$ = this, d3 = $$.d3, config = $$.config, shape = d3.select(that), isSelected = shape.classed(CLASS.SELECTED), toggle = $$.getToggle(that, d).bind($$); - + if (config.data_selection_enabled && config.data_selection_isselectable(d)) { if (!config.data_selection_multiple) { $$.main.selectAll('.' + CLASS.shapes + (config.data_selection_grouped ? $$.getTargetSelectorSuffix(d.id) : "")).selectAll('.' + CLASS.shape).each(function (d, i) { @@ -5512,28 +5803,28 @@ var $$ = this, config = $$.config, context = $$.context = $$.svg.append("g").attr("transform", $$.getTranslate('context')), visibility = config.subchart_show ? 'visible' : 'hidden'; - + context.style('visibility', visibility); - + // Define g for chart area context.append('g') .attr("clip-path", $$.clipPathForSubchart) .attr('class', CLASS.chart); - + // Define g for bar chart area context.select('.' + CLASS.chart).append("g") .attr("class", CLASS.chartBars); - + // Define g for line chart area context.select('.' + CLASS.chart).append("g") .attr("class", CLASS.chartLines); - + // Add extent rect for Brush context.append("g") .attr("clip-path", $$.clipPath) .attr("class", CLASS.brush) .call($$.brush); - + // ATTENTION: This must be called AFTER chart added // Add Axis $$.axes.subx = context.append("g") @@ -5550,7 +5841,7 @@ classChartLine = $$.classChartLine.bind($$), classLines = $$.classLines.bind($$), classAreas = $$.classAreas.bind($$); - + if (config.subchart_show) { //-- Bar --// contextBarUpdate = context.select('.' + CLASS.chartBars).selectAll('.' + CLASS.chartBar) @@ -5562,7 +5853,7 @@ // Bars for each data contextBarEnter.append('g') .attr("class", classBars); - + //-- Line --// contextLineUpdate = context.select('.' + CLASS.chartLines).selectAll('.' + CLASS.chartLine) .data(targets) @@ -5576,7 +5867,7 @@ // Area contextLineEnter.append("g") .attr("class", classAreas); - + //-- Brush --// context.selectAll('.' + CLASS.brush + ' rect') .attr(config.axis_rotated ? "width" : "height", config.axis_rotated ? $$.width2 : $$.height2); @@ -5642,9 +5933,9 @@ c3_chart_internal_fn.redrawSubchart = function (withSubchart, transitions, duration, durationForExit, areaIndices, barIndices, lineIndices) { var $$ = this, d3 = $$.d3, config = $$.config, drawAreaOnSub, drawBarOnSub, drawLineOnSub; - + $$.context.style('visibility', config.subchart_show ? 'visible' : 'hidden'); - + // subchart if (config.subchart_show) { // reflect main chart to extent on subchart if zoomed @@ -5653,7 +5944,7 @@ } // update subchart elements if needed if (withSubchart) { - + // extent rect if (!$$.brush.empty()) { $$.brush.extent($$.x.orgDomain()).update(); @@ -5662,11 +5953,11 @@ drawAreaOnSub = $$.generateDrawArea(areaIndices, true); drawBarOnSub = $$.generateDrawBar(barIndices, true); drawLineOnSub = $$.generateDrawLine(lineIndices, true); - + $$.updateBarForSubchart(duration); $$.updateLineForSubchart(duration); $$.updateAreaForSubchart(duration); - + $$.redrawBarForSubchart(drawBarOnSub, duration, duration); $$.redrawLineForSubchart(drawLineOnSub, duration, duration); $$.redrawAreaForSubchart(drawAreaOnSub, duration, duration); @@ -5706,7 +5997,7 @@ c3_chart_internal_fn.initZoom = function () { var $$ = this, d3 = $$.d3, config = $$.config, startEvent; - + $$.zoom = d3.behavior.zoom() .on("zoomstart", function () { startEvent = d3.event.sourceEvent; @@ -5786,10 +6077,10 @@ pattern = notEmpty(config.color_pattern) ? config.color_pattern : d3.scale.category10().range(), callback = config.data_color, ids = []; - + return function (d) { var id = d.id || (d.data && d.data.id) || d, color; - + // if callback function is provided if (colors[id] instanceof Function) { color = colors[id](d); @@ -5962,7 +6253,9 @@ dragarea: 'c3-dragarea', EXPANDED: '_expanded_', SELECTED: '_selected_', - INCLUDED: '_included_' + INCLUDED: '_included_', + REFERENCE_VERTICAL_RANGE: 'c3-reference-vertical-range', + REFERENCE_HORIZONTAL_RANGE: 'c3-reference-horizontal-range', }; c3_chart_internal_fn.generateClass = function (prefix, targetId) { return " " + prefix + " " + prefix + this.getTargetSelectorSuffix(targetId); @@ -6115,10 +6408,10 @@ c3_chart_fn.focus = function (targetIds) { var $$ = this.internal, candidates; - + targetIds = $$.mapToTargetIds(targetIds); candidates = $$.svg.selectAll($$.selectorTargets(targetIds.filter($$.isTargetToShow, $$))), - + this.revert(); this.defocus(); candidates.classed(CLASS.focused, true).classed(CLASS.defocused, false); @@ -6126,37 +6419,37 @@ $$.expandArc(targetIds); } $$.toggleFocusLegend(targetIds, true); - + $$.focusedTargetIds = targetIds; $$.defocusedTargetIds = $$.defocusedTargetIds.filter(function (id) { return targetIds.indexOf(id) < 0; }); }; - + c3_chart_fn.defocus = function (targetIds) { var $$ = this.internal, candidates; - + targetIds = $$.mapToTargetIds(targetIds); candidates = $$.svg.selectAll($$.selectorTargets(targetIds.filter($$.isTargetToShow, $$))), - + candidates.classed(CLASS.focused, false).classed(CLASS.defocused, true); if ($$.hasArcType()) { $$.unexpandArc(targetIds); } $$.toggleFocusLegend(targetIds, false); - + $$.focusedTargetIds = $$.focusedTargetIds.filter(function (id) { return targetIds.indexOf(id) < 0; }); $$.defocusedTargetIds = targetIds; }; - + c3_chart_fn.revert = function (targetIds) { var $$ = this.internal, candidates; - + targetIds = $$.mapToTargetIds(targetIds); candidates = $$.svg.selectAll($$.selectorTargets(targetIds)); // should be for all targets - + candidates.classed(CLASS.focused, false).classed(CLASS.defocused, false); if ($$.hasArcType()) { $$.unexpandArc(targetIds); @@ -6169,55 +6462,55 @@ }) .classed(CLASS.legendItemFocused, false); } - + $$.focusedTargetIds = []; $$.defocusedTargetIds = []; }; c3_chart_fn.show = function (targetIds, options) { var $$ = this.internal, targets; - + targetIds = $$.mapToTargetIds(targetIds); options = options || {}; - + $$.removeHiddenTargetIds(targetIds); targets = $$.svg.selectAll($$.selectorTargets(targetIds)); - + targets.transition() .style('opacity', 1, 'important') .call($$.endall, function () { targets.style('opacity', null).style('opacity', 1); }); - + if (options.withLegend) { $$.showLegend(targetIds); } - + $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true, withLegend: true}); }; - + c3_chart_fn.hide = function (targetIds, options) { var $$ = this.internal, targets; - + targetIds = $$.mapToTargetIds(targetIds); options = options || {}; - + $$.addHiddenTargetIds(targetIds); targets = $$.svg.selectAll($$.selectorTargets(targetIds)); - + targets.transition() .style('opacity', 0, 'important') .call($$.endall, function () { targets.style('opacity', null).style('opacity', 0); }); - + if (options.withLegend) { $$.hideLegend(targetIds); } - + $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true, withLegend: true}); }; - + c3_chart_fn.toggle = function (targetIds, options) { var that = this, $$ = this.internal; $$.mapToTargetIds(targetIds).forEach(function (targetId) { @@ -6247,7 +6540,7 @@ $$.brush.clear().update(); $$.redraw({withUpdateXDomain: true}); }; - + c3_chart_fn.zoom.max = function (max) { var $$ = this.internal, config = $$.config, d3 = $$.d3; if (max === 0 || max) { @@ -6257,7 +6550,7 @@ return config.zoom_x_max; } }; - + c3_chart_fn.zoom.min = function (min) { var $$ = this.internal, config = $$.config, d3 = $$.d3; if (min === 0 || min) { @@ -6267,7 +6560,7 @@ return config.zoom_x_min; } }; - + c3_chart_fn.zoom.range = function (range) { if (arguments.length) { if (isDefined(range.max)) { this.domain.max(range.max); } @@ -6327,7 +6620,7 @@ $$.loadFromArgs(args); } }; - + c3_chart_fn.unload = function (args) { var $$ = this.internal; args = args || {}; @@ -6346,7 +6639,7 @@ var $$ = this.internal, targets, data, notfoundIds = [], orgDataCount = $$.getMaxDataCount(), dataCount, domain, baseTarget, baseValue, length = 0, tail = 0, diff, to; - + if (args.json) { data = $$.convertJsonToData(args.json, args.keys); } @@ -6360,19 +6653,19 @@ return; } targets = $$.convertDataToTargets(data, true); - + // Update/Add data $$.data.targets.forEach(function (t) { var found = false, i, j; for (i = 0; i < targets.length; i++) { if (t.id === targets[i].id) { found = true; - + if (t.values[t.values.length - 1]) { tail = t.values[t.values.length - 1].index + 1; } length = targets[i].values.length; - + for (j = 0; j < length; j++) { targets[i].values[j].index = tail + j; if (!$$.isTimeSeries()) { @@ -6380,14 +6673,14 @@ } } t.values = t.values.concat(targets[i].values); - + targets.splice(i, 1); break; } } if (!found) { notfoundIds.push(t.id); } }); - + // Append null for not found targets $$.data.targets.forEach(function (t) { var i, j; @@ -6405,7 +6698,7 @@ } } }); - + // Generate null values for new target if ($$.data.targets.length) { targets.forEach(function (t) { @@ -6428,12 +6721,12 @@ }); } $$.data.targets = $$.data.targets.concat(targets); // add remained - + // check data count because behavior needs to change when it's only one dataCount = $$.getMaxDataCount(); baseTarget = $$.data.targets[0]; baseValue = baseTarget.values[0]; - + // Update length to flow if needed if (isDefined(args.to)) { length = 0; @@ -6444,7 +6737,7 @@ } else if (isDefined(args.length)) { length = args.length; } - + // If only one data, update the domain to flow from left edge of the chart if (!orgDataCount) { if ($$.isTimeSeries()) { @@ -6465,10 +6758,10 @@ $$.updateXDomain(null, true, true, false, domain); } } - + // Set targets $$.updateTargets($$.data.targets); - + // Redraw with new targets $$.redraw({ flow: { @@ -6484,10 +6777,10 @@ withUpdateXAxis: true, }); }; - + c3_chart_internal_fn.generateFlow = function (args) { var $$ = this, config = $$.config, d3 = $$.d3; - + return function () { var targets = args.targets, flow = args.flow, @@ -6500,7 +6793,7 @@ xForText = args.xForText, yForText = args.yForText, duration = args.duration; - + var translateX, scaleX = 1, transform, flowIndex = flow.index, flowLength = flow.length, @@ -6510,7 +6803,7 @@ durationForFlow = flow.duration || duration, done = flow.done || function () {}, wait = $$.generateWait(); - + var xgrid = $$.xgrid || d3.selectAll([]), xgridLines = $$.xgridLines || d3.selectAll([]), mainRegion = $$.mainRegion || d3.selectAll([]), @@ -6519,20 +6812,20 @@ mainLine = $$.mainLine || d3.selectAll([]), mainArea = $$.mainArea || d3.selectAll([]), mainCircle = $$.mainCircle || d3.selectAll([]); - + // set flag $$.flowing = true; - + // remove head data after rendered $$.data.targets.forEach(function (d) { d.values.splice(0, flowLength); }); - + // update x domain to generate axis elements for flow domain = $$.updateXDomain(targets, true, true); // update elements related to x scale if ($$.updateXGrid) { $$.updateXGrid(true); } - + // generate transform to flow if (!flow.orgDataCount) { // if empty if ($$.data.targets[0].values.length !== 1) { @@ -6557,9 +6850,9 @@ } scaleX = (diffDomain(orgDomain) / diffDomain(domain)); transform = 'translate(' + translateX + ',0) scale(' + scaleX + ',1)'; - + $$.hideXGridFocus(); - + d3.transition().ease('linear').duration(durationForFlow).each(function () { wait.add($$.axes.x.transition().call($$.xAxis)); wait.add(mainBar.transition().attr('transform', transform)); @@ -6573,7 +6866,7 @@ }) .call(wait, function () { var i, shapes = [], texts = [], eventRects = []; - + // remove flowed elements if (flowLength) { for (i = 0; i < flowLength; i++) { @@ -6586,7 +6879,7 @@ $$.svg.selectAll('.' + CLASS.eventRects).selectAll(eventRects).remove(); $$.svg.select('.' + CLASS.xgrid).remove(); } - + // draw again for removing flowed elements and reverting attr xgrid .attr('transform', null) @@ -6622,14 +6915,14 @@ mainRegion.select('rect').filter($$.isRegionOnX) .attr("x", $$.regionX.bind($$)) .attr("width", $$.regionWidth.bind($$)); - + if (config.interaction_enabled) { $$.redrawEventRect(); } - + // callback for end of flow done(); - + $$.flowing = false; }); }; @@ -6695,7 +6988,7 @@ options = ['pie', 'donut'].indexOf(type) >= 0 ? {withTransform: true} : null; $$.transformTo(targetIds, type, options); }; - + c3_chart_internal_fn.transformTo = function (targetIds, type, optionsForRedraw) { var $$ = this, withTransitionForAxis = !$$.hasArcType(), @@ -6730,7 +7023,7 @@ var $$ = this.internal; $$.removeGridLines(params, true); }; - + c3_chart_fn.ygrids = function (grids) { var $$ = this.internal, config = $$.config; if (! grids) { return config.grid_y_lines; } @@ -6764,16 +7057,16 @@ c3_chart_fn.regions.remove = function (options) { var $$ = this.internal, config = $$.config, duration, classes, regions; - + options = options || {}; duration = $$.getOption(options, "duration", config.transition_duration); classes = $$.getOption(options, "classes", [CLASS.region]); - + regions = $$.main.select('.' + CLASS.regions).selectAll(classes.map(function (c) { return '.' + c; })); (duration ? regions.transition().duration(duration) : regions) .style('opacity', 0) .remove(); - + config.regions = config.regions.filter(function (region) { var found = false; if (!region['class']) { @@ -6784,7 +7077,7 @@ }); return !found; }); - + return config.regions; }; @@ -6934,21 +7227,21 @@ config.size_height = size ? size.height : null; this.flush(); }; - + c3_chart_fn.flush = function () { var $$ = this.internal; $$.updateAndRedraw({withLegend: true, withTransition: false, withTransitionForTransform: false}); }; - + c3_chart_fn.destroy = function () { var $$ = this.internal; - + window.clearInterval($$.intervalForObserveInserted); - + if ($$.resizeTimeout !== undefined) { window.clearTimeout($$.resizeTimeout); } - + if (window.detachEvent) { window.detachEvent('onresize', $$.resizeFunction); } else if (window.removeEventListener) { @@ -6960,26 +7253,26 @@ wrapper.remove($$.resizeFunction); } } - + $$.selectChart.classed('c3', false).html(""); - + // MEMO: this is needed because the reference of some elements will not be released, then memory leak will happen. Object.keys($$).forEach(function (key) { $$[key] = null; }); - + return null; }; c3_chart_fn.tooltip = function () {}; c3_chart_fn.tooltip.show = function (args) { var $$ = this.internal, index, mouse; - + // determine mouse position on the chart if (args.mouse) { mouse = args.mouse; } - + // determine focus data if (args.data) { if ($$.isMultipleX()) { @@ -6997,17 +7290,17 @@ else if (typeof args.index !== 'undefined') { index = args.index; } - + // emulate mouse events to show $$.dispatchEvent('mouseover', index, mouse); $$.dispatchEvent('mousemove', index, mouse); - + $$.config.tooltip_onshow.call($$, args.data); }; c3_chart_fn.tooltip.hide = function () { // TODO: get target data by checking the state of focus this.internal.dispatchEvent('mouseout', 0); - + this.internal.config.tooltip_onhide.call(this); }; @@ -7018,12 +7311,12 @@ var tickTextCharSize; function c3_axis(d3, params) { var scale = d3.scale.linear(), orient = "bottom", innerTickSize = 6, outerTickSize, tickPadding = 3, tickValues = null, tickFormat, tickArguments; - + var tickOffset = 0, tickCulling = true, tickCentered; - + params = params || {}; outerTickSize = params.withOuterTick ? 6 : 0; - + function axisX(selection, x) { selection.attr("transform", function (d) { return "translate(" + Math.ceil(x(d) + tickOffset) + ", 0)"; @@ -7091,9 +7384,9 @@ function axis(g) { g.each(function () { var g = axis.g = d3.select(this); - + var scale0 = this.__chart__ || scale, scale1 = this.__chart__ = copyScale(); - + var ticks = tickValues ? tickValues : generateTicks(scale1), tick = g.selectAll(".tick").data(ticks, scale1), tickEnter = tick.enter().insert("g", ".domain").attr("class", "tick").style("opacity", 1e-6), @@ -7101,18 +7394,18 @@ tickExit = tick.exit().remove(), tickUpdate = transitionise(tick).style("opacity", 1), tickTransform, tickX, tickY; - + var range = scale.rangeExtent ? scale.rangeExtent() : scaleExtent(scale.range()), path = g.selectAll(".domain").data([ 0 ]), pathUpdate = (path.enter().append("path").attr("class", "domain"), transitionise(path)); tickEnter.append("line"); tickEnter.append("text"); - + var lineEnter = tickEnter.select("line"), lineUpdate = tickUpdate.select("line"), textEnter = tickEnter.select("text"), textUpdate = tickUpdate.select("text"); - + if (params.isCategory) { tickOffset = Math.ceil((scale1(1) - scale1(0)) / 2); tickX = tickCentered ? 0 : tickOffset; @@ -7120,24 +7413,24 @@ } else { tickOffset = tickX = 0; } - + var text, tspan, sizeFor1Char = getSizeFor1Char(g.select('.tick')), counts = []; var tickLength = Math.max(innerTickSize, 0) + tickPadding, isVertical = orient === 'left' || orient === 'right'; - + // this should be called only when category axis function splitTickText(d, maxWidth) { var tickText = textFormatted(d), subtext, spaceIndex, textWidth, splitted = []; - + if (Object.prototype.toString.call(tickText) === "[object Array]") { return tickText; } - + if (!maxWidth || maxWidth <= 0) { maxWidth = isVertical ? 95 : params.isCategory ? (Math.ceil(scale1(ticks[1]) - scale1(ticks[0])) - 12) : 110; } - + function split(splitted, text) { spaceIndex = undefined; for (var i = 1; i < text.length; i++) { @@ -7156,10 +7449,10 @@ } return splitted.concat(text); } - + return split(splitted, tickText + ""); } - + function tspanDy(d, i) { var dy = sizeFor1Char.h; if (i === 0) { @@ -7171,12 +7464,12 @@ } return dy; } - + function tickSize(d) { var tickPosition = scale(d) + (tickCentered ? 0 : tickOffset); return range[0] < tickPosition && tickPosition < range[1] ? innerTickSize : 0; } - + text = tick.select("text"); tspan = text.selectAll('tspan') .data(function (d, i) { @@ -7189,9 +7482,9 @@ tspan.enter().append('tspan'); tspan.exit().remove(); tspan.text(function (d) { return d.splitted; }); - + var rotate = params.tickTextRotate; - + function textAnchorForText(rotate) { if (!rotate) { return 'middle'; @@ -7216,7 +7509,7 @@ } return 11.5 - 2.5 * (rotate / 15) * (rotate > 0 ? 1 : -1); } - + switch (orient) { case "bottom": { @@ -7352,11 +7645,11 @@ }; /* jshint ignore:start */ - + // PhantomJS doesn't have support for Function.prototype.bind, which has caused confusion. Use // this polyfill to avoid the confusion. // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind#Polyfill - + if (!Function.prototype.bind) { Function.prototype.bind = function(oThis) { if (typeof this !== 'function') { @@ -7364,21 +7657,21 @@ // internal IsCallable function throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); } - + var aArgs = Array.prototype.slice.call(arguments, 1), fToBind = this, fNOP = function() {}, fBound = function() { return fToBind.apply(this instanceof fNOP ? this : oThis, aArgs.concat(Array.prototype.slice.call(arguments))); }; - + fNOP.prototype = this.prototype; fBound.prototype = new fNOP(); - + return fBound; }; } - + //SVGPathSeg API polyfill //https://github.com/progers/pathseg // @@ -7386,7 +7679,7 @@ //SVG2 (https://lists.w3.org/Archives/Public/www-svg/2015Jun/0044.html), including the latest spec //changes which were implemented in Firefox 43 and Chrome 46. //Chrome 48 removes these APIs, so this polyfill is required. - + (function() { "use strict"; if (!("SVGPathSeg" in window)) { // Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-InterfaceSVGPathSeg @@ -7395,7 +7688,7 @@ this.pathSegTypeAsLetter = typeAsLetter; this._owningPathSegList = owningPathSegList; } - + SVGPathSeg.PATHSEG_UNKNOWN = 0; SVGPathSeg.PATHSEG_CLOSEPATH = 1; SVGPathSeg.PATHSEG_MOVETO_ABS = 2; @@ -7416,13 +7709,13 @@ SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL = 17; SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS = 18; SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL = 19; - + // Notify owning PathSegList on any changes so they can be synchronized back to the path element. SVGPathSeg.prototype._segmentChanged = function() { if (this._owningPathSegList) this._owningPathSegList.segmentChanged(this); } - + window.SVGPathSegClosePath = function(owningPathSegList) { SVGPathSeg.call(this, SVGPathSeg.PATHSEG_CLOSEPATH, "z", owningPathSegList); } @@ -7430,7 +7723,7 @@ SVGPathSegClosePath.prototype.toString = function() { return "[object SVGPathSegClosePath]"; } SVGPathSegClosePath.prototype._asPathString = function() { return this.pathSegTypeAsLetter; } SVGPathSegClosePath.prototype.clone = function() { return new SVGPathSegClosePath(undefined); } - + window.SVGPathSegMovetoAbs = function(owningPathSegList, x, y) { SVGPathSeg.call(this, SVGPathSeg.PATHSEG_MOVETO_ABS, "M", owningPathSegList); this._x = x; @@ -7442,7 +7735,7 @@ SVGPathSegMovetoAbs.prototype.clone = function() { return new SVGPathSegMovetoAbs(undefined, this._x, this._y); } Object.defineProperty(SVGPathSegMovetoAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); Object.defineProperty(SVGPathSegMovetoAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); - + window.SVGPathSegMovetoRel = function(owningPathSegList, x, y) { SVGPathSeg.call(this, SVGPathSeg.PATHSEG_MOVETO_REL, "m", owningPathSegList); this._x = x; @@ -7454,7 +7747,7 @@ SVGPathSegMovetoRel.prototype.clone = function() { return new SVGPathSegMovetoRel(undefined, this._x, this._y); } Object.defineProperty(SVGPathSegMovetoRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); Object.defineProperty(SVGPathSegMovetoRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); - + window.SVGPathSegLinetoAbs = function(owningPathSegList, x, y) { SVGPathSeg.call(this, SVGPathSeg.PATHSEG_LINETO_ABS, "L", owningPathSegList); this._x = x; @@ -7466,7 +7759,7 @@ SVGPathSegLinetoAbs.prototype.clone = function() { return new SVGPathSegLinetoAbs(undefined, this._x, this._y); } Object.defineProperty(SVGPathSegLinetoAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); Object.defineProperty(SVGPathSegLinetoAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); - + window.SVGPathSegLinetoRel = function(owningPathSegList, x, y) { SVGPathSeg.call(this, SVGPathSeg.PATHSEG_LINETO_REL, "l", owningPathSegList); this._x = x; @@ -7478,7 +7771,7 @@ SVGPathSegLinetoRel.prototype.clone = function() { return new SVGPathSegLinetoRel(undefined, this._x, this._y); } Object.defineProperty(SVGPathSegLinetoRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); Object.defineProperty(SVGPathSegLinetoRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); - + window.SVGPathSegCurvetoCubicAbs = function(owningPathSegList, x, y, x1, y1, x2, y2) { SVGPathSeg.call(this, SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS, "C", owningPathSegList); this._x = x; @@ -7498,7 +7791,7 @@ Object.defineProperty(SVGPathSegCurvetoCubicAbs.prototype, "y1", { get: function() { return this._y1; }, set: function(y1) { this._y1 = y1; this._segmentChanged(); }, enumerable: true }); Object.defineProperty(SVGPathSegCurvetoCubicAbs.prototype, "x2", { get: function() { return this._x2; }, set: function(x2) { this._x2 = x2; this._segmentChanged(); }, enumerable: true }); Object.defineProperty(SVGPathSegCurvetoCubicAbs.prototype, "y2", { get: function() { return this._y2; }, set: function(y2) { this._y2 = y2; this._segmentChanged(); }, enumerable: true }); - + window.SVGPathSegCurvetoCubicRel = function(owningPathSegList, x, y, x1, y1, x2, y2) { SVGPathSeg.call(this, SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL, "c", owningPathSegList); this._x = x; @@ -7518,7 +7811,7 @@ Object.defineProperty(SVGPathSegCurvetoCubicRel.prototype, "y1", { get: function() { return this._y1; }, set: function(y1) { this._y1 = y1; this._segmentChanged(); }, enumerable: true }); Object.defineProperty(SVGPathSegCurvetoCubicRel.prototype, "x2", { get: function() { return this._x2; }, set: function(x2) { this._x2 = x2; this._segmentChanged(); }, enumerable: true }); Object.defineProperty(SVGPathSegCurvetoCubicRel.prototype, "y2", { get: function() { return this._y2; }, set: function(y2) { this._y2 = y2; this._segmentChanged(); }, enumerable: true }); - + window.SVGPathSegCurvetoQuadraticAbs = function(owningPathSegList, x, y, x1, y1) { SVGPathSeg.call(this, SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS, "Q", owningPathSegList); this._x = x; @@ -7534,7 +7827,7 @@ Object.defineProperty(SVGPathSegCurvetoQuadraticAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); Object.defineProperty(SVGPathSegCurvetoQuadraticAbs.prototype, "x1", { get: function() { return this._x1; }, set: function(x1) { this._x1 = x1; this._segmentChanged(); }, enumerable: true }); Object.defineProperty(SVGPathSegCurvetoQuadraticAbs.prototype, "y1", { get: function() { return this._y1; }, set: function(y1) { this._y1 = y1; this._segmentChanged(); }, enumerable: true }); - + window.SVGPathSegCurvetoQuadraticRel = function(owningPathSegList, x, y, x1, y1) { SVGPathSeg.call(this, SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL, "q", owningPathSegList); this._x = x; @@ -7550,7 +7843,7 @@ Object.defineProperty(SVGPathSegCurvetoQuadraticRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); Object.defineProperty(SVGPathSegCurvetoQuadraticRel.prototype, "x1", { get: function() { return this._x1; }, set: function(x1) { this._x1 = x1; this._segmentChanged(); }, enumerable: true }); Object.defineProperty(SVGPathSegCurvetoQuadraticRel.prototype, "y1", { get: function() { return this._y1; }, set: function(y1) { this._y1 = y1; this._segmentChanged(); }, enumerable: true }); - + window.SVGPathSegArcAbs = function(owningPathSegList, x, y, r1, r2, angle, largeArcFlag, sweepFlag) { SVGPathSeg.call(this, SVGPathSeg.PATHSEG_ARC_ABS, "A", owningPathSegList); this._x = x; @@ -7572,7 +7865,7 @@ Object.defineProperty(SVGPathSegArcAbs.prototype, "angle", { get: function() { return this._angle; }, set: function(angle) { this._angle = angle; this._segmentChanged(); }, enumerable: true }); Object.defineProperty(SVGPathSegArcAbs.prototype, "largeArcFlag", { get: function() { return this._largeArcFlag; }, set: function(largeArcFlag) { this._largeArcFlag = largeArcFlag; this._segmentChanged(); }, enumerable: true }); Object.defineProperty(SVGPathSegArcAbs.prototype, "sweepFlag", { get: function() { return this._sweepFlag; }, set: function(sweepFlag) { this._sweepFlag = sweepFlag; this._segmentChanged(); }, enumerable: true }); - + window.SVGPathSegArcRel = function(owningPathSegList, x, y, r1, r2, angle, largeArcFlag, sweepFlag) { SVGPathSeg.call(this, SVGPathSeg.PATHSEG_ARC_REL, "a", owningPathSegList); this._x = x; @@ -7594,7 +7887,7 @@ Object.defineProperty(SVGPathSegArcRel.prototype, "angle", { get: function() { return this._angle; }, set: function(angle) { this._angle = angle; this._segmentChanged(); }, enumerable: true }); Object.defineProperty(SVGPathSegArcRel.prototype, "largeArcFlag", { get: function() { return this._largeArcFlag; }, set: function(largeArcFlag) { this._largeArcFlag = largeArcFlag; this._segmentChanged(); }, enumerable: true }); Object.defineProperty(SVGPathSegArcRel.prototype, "sweepFlag", { get: function() { return this._sweepFlag; }, set: function(sweepFlag) { this._sweepFlag = sweepFlag; this._segmentChanged(); }, enumerable: true }); - + window.SVGPathSegLinetoHorizontalAbs = function(owningPathSegList, x) { SVGPathSeg.call(this, SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS, "H", owningPathSegList); this._x = x; @@ -7604,7 +7897,7 @@ SVGPathSegLinetoHorizontalAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x; } SVGPathSegLinetoHorizontalAbs.prototype.clone = function() { return new SVGPathSegLinetoHorizontalAbs(undefined, this._x); } Object.defineProperty(SVGPathSegLinetoHorizontalAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); - + window.SVGPathSegLinetoHorizontalRel = function(owningPathSegList, x) { SVGPathSeg.call(this, SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL, "h", owningPathSegList); this._x = x; @@ -7614,7 +7907,7 @@ SVGPathSegLinetoHorizontalRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x; } SVGPathSegLinetoHorizontalRel.prototype.clone = function() { return new SVGPathSegLinetoHorizontalRel(undefined, this._x); } Object.defineProperty(SVGPathSegLinetoHorizontalRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); - + window.SVGPathSegLinetoVerticalAbs = function(owningPathSegList, y) { SVGPathSeg.call(this, SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS, "V", owningPathSegList); this._y = y; @@ -7624,7 +7917,7 @@ SVGPathSegLinetoVerticalAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._y; } SVGPathSegLinetoVerticalAbs.prototype.clone = function() { return new SVGPathSegLinetoVerticalAbs(undefined, this._y); } Object.defineProperty(SVGPathSegLinetoVerticalAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); - + window.SVGPathSegLinetoVerticalRel = function(owningPathSegList, y) { SVGPathSeg.call(this, SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL, "v", owningPathSegList); this._y = y; @@ -7634,7 +7927,7 @@ SVGPathSegLinetoVerticalRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._y; } SVGPathSegLinetoVerticalRel.prototype.clone = function() { return new SVGPathSegLinetoVerticalRel(undefined, this._y); } Object.defineProperty(SVGPathSegLinetoVerticalRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); - + window.SVGPathSegCurvetoCubicSmoothAbs = function(owningPathSegList, x, y, x2, y2) { SVGPathSeg.call(this, SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS, "S", owningPathSegList); this._x = x; @@ -7650,7 +7943,7 @@ Object.defineProperty(SVGPathSegCurvetoCubicSmoothAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); Object.defineProperty(SVGPathSegCurvetoCubicSmoothAbs.prototype, "x2", { get: function() { return this._x2; }, set: function(x2) { this._x2 = x2; this._segmentChanged(); }, enumerable: true }); Object.defineProperty(SVGPathSegCurvetoCubicSmoothAbs.prototype, "y2", { get: function() { return this._y2; }, set: function(y2) { this._y2 = y2; this._segmentChanged(); }, enumerable: true }); - + window.SVGPathSegCurvetoCubicSmoothRel = function(owningPathSegList, x, y, x2, y2) { SVGPathSeg.call(this, SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL, "s", owningPathSegList); this._x = x; @@ -7666,7 +7959,7 @@ Object.defineProperty(SVGPathSegCurvetoCubicSmoothRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); Object.defineProperty(SVGPathSegCurvetoCubicSmoothRel.prototype, "x2", { get: function() { return this._x2; }, set: function(x2) { this._x2 = x2; this._segmentChanged(); }, enumerable: true }); Object.defineProperty(SVGPathSegCurvetoCubicSmoothRel.prototype, "y2", { get: function() { return this._y2; }, set: function(y2) { this._y2 = y2; this._segmentChanged(); }, enumerable: true }); - + window.SVGPathSegCurvetoQuadraticSmoothAbs = function(owningPathSegList, x, y) { SVGPathSeg.call(this, SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS, "T", owningPathSegList); this._x = x; @@ -7678,7 +7971,7 @@ SVGPathSegCurvetoQuadraticSmoothAbs.prototype.clone = function() { return new SVGPathSegCurvetoQuadraticSmoothAbs(undefined, this._x, this._y); } Object.defineProperty(SVGPathSegCurvetoQuadraticSmoothAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); Object.defineProperty(SVGPathSegCurvetoQuadraticSmoothAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); - + window.SVGPathSegCurvetoQuadraticSmoothRel = function(owningPathSegList, x, y) { SVGPathSeg.call(this, SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL, "t", owningPathSegList); this._x = x; @@ -7690,7 +7983,7 @@ SVGPathSegCurvetoQuadraticSmoothRel.prototype.clone = function() { return new SVGPathSegCurvetoQuadraticSmoothRel(undefined, this._x, this._y); } Object.defineProperty(SVGPathSegCurvetoQuadraticSmoothRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true }); Object.defineProperty(SVGPathSegCurvetoQuadraticSmoothRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true }); - + // Add createSVGPathSeg* functions to SVGPathElement. // Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-InterfaceSVGPathElement. SVGPathElement.prototype.createSVGPathSegClosePath = function() { return new SVGPathSegClosePath(undefined); } @@ -7713,19 +8006,19 @@ SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticSmoothAbs = function(x, y) { return new SVGPathSegCurvetoQuadraticSmoothAbs(undefined, x, y); } SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticSmoothRel = function(x, y) { return new SVGPathSegCurvetoQuadraticSmoothRel(undefined, x, y); } } - + if (!("SVGPathSegList" in window)) { // Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-InterfaceSVGPathSegList window.SVGPathSegList = function(pathElement) { this._pathElement = pathElement; this._list = this._parsePath(this._pathElement.getAttribute("d")); - + // Use a MutationObserver to catch changes to the path's "d" attribute. this._mutationObserverConfig = { "attributes": true, "attributeFilter": ["d"] }; this._pathElementMutationObserver = new MutationObserver(this._updateListFromPathMutations.bind(this)); this._pathElementMutationObserver.observe(this._pathElement, this._mutationObserverConfig); } - + Object.defineProperty(SVGPathSegList.prototype, "numberOfItems", { get: function() { this._checkPathSynchronizedToList(); @@ -7733,7 +8026,7 @@ }, enumerable: true }); - + // Add the pathSegList accessors to SVGPathElement. // Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-InterfaceSVGAnimatedPathData Object.defineProperty(SVGPathElement.prototype, "pathSegList", { @@ -7748,14 +8041,14 @@ Object.defineProperty(SVGPathElement.prototype, "normalizedPathSegList", { get: function() { return this.pathSegList; }, enumerable: true }); Object.defineProperty(SVGPathElement.prototype, "animatedPathSegList", { get: function() { return this.pathSegList; }, enumerable: true }); Object.defineProperty(SVGPathElement.prototype, "animatedNormalizedPathSegList", { get: function() { return this.pathSegList; }, enumerable: true }); - + // Process any pending mutations to the path element and update the list as needed. // This should be the first call of all public functions and is needed because // MutationObservers are not synchronous so we can have pending asynchronous mutations. SVGPathSegList.prototype._checkPathSynchronizedToList = function() { this._updateListFromPathMutations(this._pathElementMutationObserver.takeRecords()); } - + SVGPathSegList.prototype._updateListFromPathMutations = function(mutationRecords) { if (!this._pathElement) return; @@ -7767,53 +8060,53 @@ if (hasPathMutations) this._list = this._parsePath(this._pathElement.getAttribute("d")); } - + // Serialize the list and update the path's 'd' attribute. SVGPathSegList.prototype._writeListToPath = function() { this._pathElementMutationObserver.disconnect(); this._pathElement.setAttribute("d", SVGPathSegList._pathSegArrayAsString(this._list)); this._pathElementMutationObserver.observe(this._pathElement, this._mutationObserverConfig); } - + // When a path segment changes the list needs to be synchronized back to the path element. SVGPathSegList.prototype.segmentChanged = function(pathSeg) { this._writeListToPath(); } - + SVGPathSegList.prototype.clear = function() { this._checkPathSynchronizedToList(); - + this._list.forEach(function(pathSeg) { pathSeg._owningPathSegList = null; }); this._list = []; this._writeListToPath(); } - + SVGPathSegList.prototype.initialize = function(newItem) { this._checkPathSynchronizedToList(); - + this._list = [newItem]; newItem._owningPathSegList = this; this._writeListToPath(); return newItem; } - + SVGPathSegList.prototype._checkValidIndex = function(index) { if (isNaN(index) || index < 0 || index >= this.numberOfItems) throw "INDEX_SIZE_ERR"; } - + SVGPathSegList.prototype.getItem = function(index) { this._checkPathSynchronizedToList(); - + this._checkValidIndex(index); return this._list[index]; } - + SVGPathSegList.prototype.insertItemBefore = function(newItem, index) { this._checkPathSynchronizedToList(); - + // Spec: If the index is greater than or equal to numberOfItems, then the new item is appended to the end of the list. if (index > this.numberOfItems) index = this.numberOfItems; @@ -7826,10 +8119,10 @@ this._writeListToPath(); return newItem; } - + SVGPathSegList.prototype.replaceItem = function(newItem, index) { this._checkPathSynchronizedToList(); - + if (newItem._owningPathSegList) { // SVG2 spec says to make a copy. newItem = newItem.clone(); @@ -7840,20 +8133,20 @@ this._writeListToPath(); return newItem; } - + SVGPathSegList.prototype.removeItem = function(index) { this._checkPathSynchronizedToList(); - + this._checkValidIndex(index); var item = this._list[index]; this._list.splice(index, 1); this._writeListToPath(); return item; } - + SVGPathSegList.prototype.appendItem = function(newItem) { this._checkPathSynchronizedToList(); - + if (newItem._owningPathSegList) { // SVG2 spec says to make a copy. newItem = newItem.clone(); @@ -7864,7 +8157,7 @@ this._writeListToPath(); return newItem; } - + SVGPathSegList._pathSegArrayAsString = function(pathSegArray) { var string = ""; var first = true; @@ -7878,42 +8171,42 @@ }); return string; } - + // This closely follows SVGPathParser::parsePath from Source/core/svg/SVGPathParser.cpp. SVGPathSegList.prototype._parsePath = function(string) { if (!string || string.length == 0) return []; - + var owningPathSegList = this; - + var Builder = function() { this.pathSegList = []; } - + Builder.prototype.appendSegment = function(pathSeg) { this.pathSegList.push(pathSeg); } - + var Source = function(string) { this._string = string; this._currentIndex = 0; this._endIndex = this._string.length; this._previousCommand = SVGPathSeg.PATHSEG_UNKNOWN; - + this._skipOptionalSpaces(); } - + Source.prototype._isCurrentSpace = function() { var character = this._string[this._currentIndex]; return character <= " " && (character == " " || character == "\n" || character == "\t" || character == "\r" || character == "\f"); } - + Source.prototype._skipOptionalSpaces = function() { while (this._currentIndex < this._endIndex && this._isCurrentSpace()) this._currentIndex++; return this._currentIndex < this._endIndex; } - + Source.prototype._skipOptionalSpacesOrDelimiter = function() { if (this._currentIndex < this._endIndex && !this._isCurrentSpace() && this._string.charAt(this._currentIndex) != ",") return false; @@ -7925,16 +8218,16 @@ } return this._currentIndex < this._endIndex; } - + Source.prototype.hasMoreData = function() { return this._currentIndex < this._endIndex; } - + Source.prototype.peekSegmentType = function() { var lookahead = this._string[this._currentIndex]; return this._pathSegTypeFromChar(lookahead); } - + Source.prototype._pathSegTypeFromChar = function(lookahead) { switch (lookahead) { case "Z": @@ -7980,7 +8273,7 @@ return SVGPathSeg.PATHSEG_UNKNOWN; } } - + Source.prototype._nextCommandHelper = function(lookahead, previousCommand) { // Check for remaining coordinates in the current command. if ((lookahead == "+" || lookahead == "-" || lookahead == "." || (lookahead >= "0" && lookahead <= "9")) && previousCommand != SVGPathSeg.PATHSEG_CLOSEPATH) { @@ -7992,7 +8285,7 @@ } return SVGPathSeg.PATHSEG_UNKNOWN; } - + Source.prototype.initialCommandIsMoveTo = function() { // If the path is empty it is still valid, so return true. if (!this.hasMoreData()) @@ -8001,7 +8294,7 @@ // Path must start with moveTo. return command == SVGPathSeg.PATHSEG_MOVETO_ABS || command == SVGPathSeg.PATHSEG_MOVETO_REL; } - + // Parse a number from an SVG path. This very closely follows genericParseNumber(...) from Source/core/svg/SVGParserUtilities.cpp. // Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-PathDataBNF Source.prototype._parseNumber = function() { @@ -8011,11 +8304,11 @@ var decimal = 0; var sign = 1; var expsign = 1; - + var startIndex = this._currentIndex; - + this._skipOptionalSpaces(); - + // Read the sign. if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) == "+") this._currentIndex++; @@ -8023,16 +8316,16 @@ this._currentIndex++; sign = -1; } - + if (this._currentIndex == this._endIndex || ((this._string.charAt(this._currentIndex) < "0" || this._string.charAt(this._currentIndex) > "9") && this._string.charAt(this._currentIndex) != ".")) // The first character of a number must be one of [0-9+-.]. return undefined; - + // Read the integer part, build right-to-left. var startIntPartIndex = this._currentIndex; while (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) >= "0" && this._string.charAt(this._currentIndex) <= "9") this._currentIndex++; // Advance to first non-digit. - + if (this._currentIndex != startIntPartIndex) { var scanIntPartIndex = this._currentIndex - 1; var multiplier = 1; @@ -8041,22 +8334,22 @@ multiplier *= 10; } } - + // Read the decimals. if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) == ".") { this._currentIndex++; - + // There must be a least one digit following the . if (this._currentIndex >= this._endIndex || this._string.charAt(this._currentIndex) < "0" || this._string.charAt(this._currentIndex) > "9") return undefined; while (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) >= "0" && this._string.charAt(this._currentIndex) <= "9") decimal += (this._string.charAt(this._currentIndex++) - "0") * (frac *= 0.1); } - + // Read the exponent part. if (this._currentIndex != startIndex && this._currentIndex + 1 < this._endIndex && (this._string.charAt(this._currentIndex) == "e" || this._string.charAt(this._currentIndex) == "E") && (this._string.charAt(this._currentIndex + 1) != "x" && this._string.charAt(this._currentIndex + 1) != "m")) { this._currentIndex++; - + // Read the sign of the exponent. if (this._string.charAt(this._currentIndex) == "+") { this._currentIndex++; @@ -8064,32 +8357,32 @@ this._currentIndex++; expsign = -1; } - + // There must be an exponent. if (this._currentIndex >= this._endIndex || this._string.charAt(this._currentIndex) < "0" || this._string.charAt(this._currentIndex) > "9") return undefined; - + while (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) >= "0" && this._string.charAt(this._currentIndex) <= "9") { exponent *= 10; exponent += (this._string.charAt(this._currentIndex) - "0"); this._currentIndex++; } } - + var number = integer + decimal; number *= sign; - + if (exponent) number *= Math.pow(10, expsign * exponent); - + if (startIndex == this._currentIndex) return undefined; - + this._skipOptionalSpacesOrDelimiter(); - + return number; } - + Source.prototype._parseArcFlag = function() { if (this._currentIndex >= this._endIndex) return undefined; @@ -8101,11 +8394,11 @@ flag = true; else return undefined; - + this._skipOptionalSpacesOrDelimiter(); return flag; } - + Source.prototype.parseSegment = function() { var lookahead = this._string[this._currentIndex]; var command = this._pathSegTypeFromChar(lookahead); @@ -8119,9 +8412,9 @@ } else { this._currentIndex++; } - + this._previousCommand = command; - + switch (command) { case SVGPathSeg.PATHSEG_MOVETO_REL: return new SVGPathSegMovetoRel(owningPathSegList, this._parseNumber(), this._parseNumber()); @@ -8174,10 +8467,10 @@ throw "Unknown path seg type." } } - + var builder = new Builder(); var source = new Source(string); - + if (!source.initialCommandIsMoveTo()) return []; while (source.hasMoreData()) { @@ -8186,12 +8479,12 @@ return []; builder.appendSegment(pathSeg); } - + return builder.pathSegList; } } }()); - + /* jshint ignore:end */ if (typeof define === 'function' && define.amd) { diff --git a/package.json b/package.json index 0b5a178fb..4415de210 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,8 @@ "scripts": { "lint": "grunt lint", "test": "karma start karma.conf.js", - "codecov": "cat coverage/*/lcov.info | codecov" + "codecov": "cat coverage/*/lcov.info | codecov", + "build": "grunt build" }, "repository": { "type": "git", diff --git a/src/class.js b/src/class.js index 66171a750..1e3c3f7f9 100644 --- a/src/class.js +++ b/src/class.js @@ -73,7 +73,9 @@ var CLASS = c3_chart_internal_fn.CLASS = { dragarea: 'c3-dragarea', EXPANDED: '_expanded_', SELECTED: '_selected_', - INCLUDED: '_included_' + INCLUDED: '_included_', + REFERENCE_VERTICAL_RANGE: 'c3-reference-vertical-range', + REFERENCE_HORIZONTAL_RANGE: 'c3-reference-horizontal-range', }; c3_chart_internal_fn.generateClass = function (prefix, targetId) { return " " + prefix + " " + prefix + this.getTargetSelectorSuffix(targetId); diff --git a/src/config.js b/src/config.js index c127be516..13ac7b325 100644 --- a/src/config.js +++ b/src/config.js @@ -121,7 +121,7 @@ c3_chart_internal_fn.getDefaultConfig = function () { axis_y_label: {}, axis_y_tick_format: undefined, axis_y_tick_outer: true, - axis_y_tick_values: null, + axis_y_tick_values: null, axis_y_tick_rotate: 0, axis_y_tick_count: undefined, axis_y_tick_time_value: undefined, @@ -226,6 +226,8 @@ c3_chart_internal_fn.getDefaultConfig = function () { left: 0 }, title_position: 'top-center', + data_starterRangeIndex: undefined, + data_ranges: undefined, }; Object.keys(this.additionalConfig).forEach(function (key) { diff --git a/src/core.js b/src/core.js index 7a933d546..d354cbcca 100644 --- a/src/core.js +++ b/src/core.js @@ -13,7 +13,7 @@ function inherit(base, derived) { if (Object.create) { derived.prototype = Object.create(base.prototype); } else { - var f = function f() {}; + var f = function f() { }; f.prototype = base.prototype; derived.prototype = new f(); } @@ -288,10 +288,27 @@ c3_chart_internal_fn.initWithData = function (data) { $$.initGrid(); // Define g for chart area - main.append('g') + var mainChartArea = main.append('g'); + mainChartArea .attr("clip-path", $$.clipPath) .attr('class', CLASS.chart); + mainChartArea + .append('g') + .attr('class', 'c3-reference-vertical-range ng-hide') + .append('rect') + .attr('height', $$.height+"px") + .attr('width', $$.width+"px") + .attr('fill', 'rgba(0,0,255,0.2)'); + + mainChartArea + .append('g') + .attr('class', 'c3-reference-horizontal-range ng-hide') + .append('rect') + .attr('height', $$.height+"px") + .attr('width', $$.width+"px") + .attr('fill', 'rgba(0,0,255,0.2)'); + // Grid lines if (config.grid_lines_front) { $$.initGridLines(); } @@ -332,6 +349,8 @@ c3_chart_internal_fn.initWithData = function (data) { }); } + if ($$.initRanges) { $$.initRanges(); } + // Bind resize event $$.bindResize(); @@ -456,7 +475,7 @@ c3_chart_internal_fn.updateTargets = function (targets) { c3_chart_internal_fn.showTargets = function () { var $$ = this; $$.svg.selectAll('.' + CLASS.target).filter(function (d) { return $$.isTargetToShow(d.id); }) - .transition().duration($$.config.transition_duration) + .transition().duration($$.config.transition_duration) .style("opacity", 1); }; @@ -579,7 +598,7 @@ c3_chart_internal_fn.redraw = function (options, transitions) { .attr("x", $$.width / 2) .attr("y", $$.height / 2) .text(config.data_empty_label_text) - .transition() + .transition() .style('opacity', targetsToShow.length ? 0 : 1); // grid @@ -673,14 +692,14 @@ c3_chart_internal_fn.redraw = function (options, transitions) { waitForDraw.add(t); }); }) - .call(waitForDraw, function () { - if (flow) { - flow(); - } - if (config.onrendered) { - config.onrendered.call($$); - } - }); + .call(waitForDraw, function () { + if (flow) { + flow(); + } + if (config.onrendered) { + config.onrendered.call($$); + } + }); } else { $$.redrawBar(drawBar); @@ -699,6 +718,7 @@ c3_chart_internal_fn.redraw = function (options, transitions) { $$.mapToIds($$.data.targets).forEach(function (id) { $$.withoutFadeIn[id] = true; }); + $$.resizeRanges(); }; c3_chart_internal_fn.updateAndRedraw = function (options) { @@ -821,7 +841,7 @@ c3_chart_internal_fn.transformMain = function (withTransition, transitions) { if (transitions && transitions.axisX) { xAxis = transitions.axisX; } else { - xAxis = $$.main.select('.' + CLASS.axisX); + xAxis = $$.main.select('.' + CLASS.axisX); if (withTransition) { xAxis = xAxis.transition(); } } if (transitions && transitions.axisY) { @@ -900,7 +920,7 @@ c3_chart_internal_fn.observeInserted = function (selection) { window.console.error("MutationObserver not defined."); return; } - observer= new MutationObserver(function (mutations) { + observer = new MutationObserver(function (mutations) { mutations.forEach(function (mutation) { if (mutation.type === 'childList' && mutation.previousSibling) { observer.disconnect(); @@ -926,7 +946,7 @@ c3_chart_internal_fn.observeInserted = function (selection) { } }); }); - observer.observe(selection.node(), {attributes: true, childList: true, characterData: true}); + observer.observe(selection.node(), { attributes: true, childList: true, characterData: true }); }; c3_chart_internal_fn.bindResize = function () { diff --git a/src/ranges.js b/src/ranges.js new file mode 100644 index 000000000..d90bdc9e8 --- /dev/null +++ b/src/ranges.js @@ -0,0 +1,255 @@ +c3_chart_internal_fn.initRanges = function () { + var $$ = this; + var verticalRange = $$.selectChart.append("div").attr('class', 'slider-vertical ng-hide').attr('id', "slider-distance").style('height', $$.height + 'px'); + var divVertical = verticalRange.append("div"); + divVertical.append("div").attr('class', 'inverse-down').style('height', '0%'); + divVertical.append("div").attr('class', 'inverse-up').style('height', '0%'); + divVertical.append("div").attr('class', 'range').style('top', '0%').style('bottom', '0%'); + divVertical.append("span").attr('class', 'thumb thumb-down').style('bottom', '0%'); + divVertical.append("span").attr('class', 'thumb thumb-up').style('bottom', $$.height - 15 + 'px'); + var downInput = verticalRange.append("input"); + var upInput = verticalRange.append("input"); + downInput.attr("id", 'down').attr('class', 'down').style('-webkit-appearance', 'slider-vertical').attr("value", $$.y.domain()[0]).attr('min', $$.y.domain()[0]).attr('max', $$.y.domain()[1]).attr('step', '0.1').attr('type', 'range').on('input', function () { + var parent = $$.selectChart.select('.slider-vertical'); + var up = parent.select('#up'); + var divVertical = parent.select('div'); + + this.value = Math.min(this.value, up.attr('value') - 0.1); + parent.select('input#down').attr('value', this.value); + $$.verticalStartValue = this.value; + + var results = $$.calculateHorizontalRangePosition(this.min, this.max); + + divVertical.select('.inverse-down').style('height', results.realHeight + 'px'); + divVertical.select('.range').style('bottom', results.realHeight + 'px'); + divVertical.select('span.thumb-down').style('bottom', results.buttonDown + 'px'); + + $$.updateReferenceRange('.' + CLASS.REFERENCE_HORIZONTAL_RANGE, 'translate(0px, ' + results.translate + 'px)', results.totalHeight + 'px', null); + }); + upInput.attr("id", 'up').attr('class', 'up').style('-webkit-appearance', 'slider-vertical').attr("value", $$.y.domain()[1]).attr('min', $$.y.domain()[0]).attr('max', $$.y.domain()[1]).attr('step', '0.1').attr('type', 'range').on('input', function () { + var parent = $$.selectChart.select('.slider-vertical'); + var down = parent.select('#down'); + var divVertical = parent.select('div'); + + this.value = Math.max(this.value, down.attr('value') - -0.1); + parent.select('input#up').attr('value', this.value); + $$.verticalEndValue = this.value; + + var results = $$.calculateHorizontalRangePosition(this.min, this.max); + + divVertical.select('.inverse-up').style('height', results.translate + 'px'); + divVertical.select('.range').style('top', results.translate + 'px'); + divVertical.select('span.thumb-up').style('bottom', results.buttonUp + 'px'); + + $$.updateReferenceRange('.' + CLASS.REFERENCE_HORIZONTAL_RANGE, 'translate(0px, ' + results.translate + 'px)', results.totalHeight + 'px', null); + }); + + $$.horizontalRange = $$.d3.select('[graph-id="' + $$.config.bindto.replace('#', '') + '"] .slider-horizontal').style('width', $$.width + 'px').style('left', $$.margin.left + 'px').style('position', 'relative'); + $$.horizontalRange.selectAll('input').remove(); + $$.horizontalRange.selectAll('div').remove(); + var divHorizontal = $$.horizontalRange.append("div"); + divHorizontal.append("div").attr('class', 'inverse-left').style('width', '0%'); + divHorizontal.append("div").attr('class', 'inverse-right').style('width', '0%'); + divHorizontal.append("div").attr('class', 'range').style('right', '0%').style('left', '0%'); + divHorizontal.append("span").attr('class', 'thumb thumb-left').style('left', '0%'); + divHorizontal.append("span").attr('class', 'thumb thumb-right').style('left', $$.width - 15 + 'px'); + + var leftInput = $$.horizontalRange.append("input"); + var rightInput = $$.horizontalRange.append("input"); + leftInput.attr("id", 'left').attr("class", 'left').attr("value", $$.x.domain()[0]).attr('min', $$.x.domain()[0]).attr('max', $$.x.domain()[1]-1).attr('step', '0.1').attr('type', 'range').on('input', function () { + var parent = $$.d3.select('[graph-id="' + $$.config.bindto.replace('#', '') + '"] .slider-horizontal'); + var right = parent.select('#right'); + var divHorizontal = parent.select('div'); + + this.value = Math.min(this.value, right.attr('value') - 0.1); + parent.select('input#left').attr('value', this.value); + $$.horizontalStartValue = this.value; + + var results = $$.calculateVerticalRangePosition(this.min, this.max); + + divHorizontal.select('.range').style('left', results.translate + 'px'); + divHorizontal.select('.inverse-left').style('width', results.translate + 'px'); + divHorizontal.select('span.thumb-left').style('left', results.buttonLeft + 'px'); + + $$.updateReferenceRange('.' + CLASS.REFERENCE_VERTICAL_RANGE, 'translate(' + results.translate + 'px)', null, results.totalWidth + 'px'); + }); + rightInput.attr("id", 'right').attr("class", 'right').attr("value", $$.x.domain()[1]).attr('min', $$.x.domain()[0]).attr('max', $$.x.domain()[1]-1).attr('step', '0.1').attr('type', 'range').on('input', function () { + var parent = $$.d3.select('[graph-id="' + $$.config.bindto.replace('#', '') + '"] .slider-horizontal'); + var left = parent.select('#left'); + var divHorizontal = parent.select('div'); + + this.value = Math.max(this.value, left.attr('value') - -0.1); + parent.select('input#right').attr('value', this.value); + $$.horizontalEndValue = this.value; + + var results = $$.calculateVerticalRangePosition(this.min, this.max); + + divHorizontal.select('.inverse-right').style('width', results.rightValue + 'px'); + divHorizontal.select('.range').style('right', results.rightValue + 'px'); + divHorizontal.select('span.thumb-right').style('left', results.buttonRight + 'px'); + + $$.updateReferenceRange('.' + CLASS.REFERENCE_VERTICAL_RANGE, 'translate(' + results.translate + 'px)', null, results.totalWidth + 'px'); + }); +}; + +c3_chart_internal_fn.calculateHorizontalRangePosition = function (min, max) { + var $$ = this; + var factorEnd = max - min; + var yToPercentEnd = ($$.verticalEndValue - $$.y.domain()[0]) * 100 / factorEnd; + var resultEnd = $$.height * yToPercentEnd / 100; + + var factorStart = max - min; + var yToPercentStart = ($$.verticalStartValue - $$.y.domain()[0]) * 100 / factorStart; + var resultStart = $$.height * yToPercentStart / 100; + + var paddingValueUpButton = 15 * yToPercentEnd / 100; + var paddingValueDownButton = 15 * yToPercentStart / 100; + + return { + translate: $$.height - resultEnd, + buttonUp: resultEnd - paddingValueUpButton, + buttonDown: resultStart - paddingValueDownButton, + totalHeight: resultEnd - resultStart, + realHeight: resultStart, + }; +}; + +c3_chart_internal_fn.calculateVerticalRangePosition = function (min, max) { + var $$ = this; + var factorEnd = max - min; + var xToPercentEnd = ($$.horizontalEndValue - min) * 100 / factorEnd; + var resultEnd = $$.width * xToPercentEnd / 100; + + var factorStart = max - min; + var xToPercentStart = ($$.horizontalStartValue - min) * 100 / factorStart; + var resultStart = $$.width * xToPercentStart / 100; + + var paddingValueRightButton = 15 * xToPercentEnd / 100; + var paddingValueLeftButton = 15 * xToPercentStart / 100; + + return { + rightValue: $$.width - resultEnd, + buttonRight: resultEnd - paddingValueRightButton, + buttonLeft: resultStart - paddingValueLeftButton, + translate: resultStart, + totalWidth: resultEnd - resultStart + }; +}; +c3_chart_internal_fn.resizeRanges = function () { + var $$ = this; + + + var verticalRange = $$.selectChart.select("#slider-distance"); + verticalRange.style('height', $$.height + 'px'); + $$.horizontalRange = $$.d3 + .select('[graph-id="' + $$.config.bindto.replace('#', '') + '"] .slider-horizontal') + .style('width', $$.width + 'px') + .style('left', $$.margin.left + 'px'); + + + $$.setStartValuesRanges(); +}; + +c3_chart_internal_fn.setStartValuesRanges = function () { + var $$ = this; + var config = $$.config; + var starter = config.data_starterRangeIndex; + $$.updateRange(starter); +}; + +c3_chart_internal_fn.updateRange = function (index) { + var $$ = this; + var config = $$.config; + var range = config.data_ranges[index]; + if(!range){ + $$.updateVerticalRange($$.y.domain()[1], $$.y.domain()[0]); + $$.updateHorizontalRange($$.x.domain()[1]-1, $$.x.domain()[0]); + } else { + $$.updateVerticalRange(range.verticalEndValue, range.verticalStartValue); + $$.updateHorizontalRange(range.horizontalEndValue, range.horizontalStartValue); + } +}; + +c3_chart_internal_fn.updateHorizontalRange = function (horizontalEndValue, horizontalStartValue) { + var $$ = this; + $$.horizontalEndValue = horizontalEndValue; + $$.horizontalStartValue = horizontalStartValue; + + var max = $$.x.domain()[1] - 1; + var min = $$.x.domain()[0]; + var horizontalSlider = $$.d3.select('[graph-id="' + $$.config.bindto.replace('#', '') + '"] .slider-horizontal'); + var divHorizontal = horizontalSlider.select("div"); + + var results = $$.calculateVerticalRangePosition(min, max); + + horizontalSlider.select('input#right').attr('value', horizontalEndValue); + horizontalSlider.select('input#left').attr('value', horizontalStartValue); + + divHorizontal.select('.inverse-right').style('width', results.rightValue + 'px'); + divHorizontal.select('.range').style('right', results.rightValue + 'px'); + divHorizontal.select('span.thumb-right').style('left', results.buttonRight + 'px'); + + divHorizontal.select('.range').style('left', results.translate + 'px'); + divHorizontal.select('.inverse-left').style('width', results.translate + 'px'); + divHorizontal.select('span.thumb-left').style('left', results.buttonLeft + 'px'); + + $$.updateReferenceRange('.' + CLASS.REFERENCE_VERTICAL_RANGE, 'translate(' + results.translate + 'px)', null, results.totalWidth + 'px'); +}; + +c3_chart_internal_fn.updateVerticalRange = function (verticalEndValue, verticalStartValue) { + var $$ = this; + $$.verticalStartValue = verticalStartValue; + $$.verticalEndValue = verticalEndValue; + var max = $$.y.domain()[1]; + var min = $$.y.domain()[0]; + var verticalSlider = $$.selectChart.select("#slider-distance"); + + var divVertical = verticalSlider.select("div"); + + var results = $$.calculateHorizontalRangePosition(min, max); + + divVertical.select('.inverse-down').style('height', results.realHeight + 'px'); + divVertical.select('.range').style('bottom', results.realHeight + 'px'); + divVertical.select('span.thumb-down').style('bottom', results.buttonDown + 'px'); + + divVertical.select('.inverse-up').style('height', results.translate + 'px'); + divVertical.select('.range').style('top', results.translate + 'px'); + divVertical.select('span.thumb-up').style('bottom', results.buttonUp + 'px'); + + $$.updateReferenceRange('.' + CLASS.REFERENCE_HORIZONTAL_RANGE, 'translate(0px, ' + results.translate + 'px)', results.totalHeight + 'px', null); +}; + +c3_chart_internal_fn.updateReferenceRange = function (htmlClass, translate, height, width) { + var $$ = this; + $$.selectChart.select(htmlClass + ' rect').style('transform', translate); + if (height != null) { + $$.selectChart.select(htmlClass + ' rect').style('height', height); + } else if (width != null) { + $$.selectChart.select(htmlClass + ' rect').style('width', width); + } +}; + +c3_chart_internal_fn.setReferenceRange = function (index) { + this.updateRange(index); +}; + +c3_chart_internal_fn.setVerticalRange = function (firstValue, secondValue) { + var endValue = Math.max(firstValue, secondValue); + var startValue = Math.min(firstValue, secondValue); + + this.updateVerticalRange(endValue, startValue); +}; + +c3_chart_internal_fn.setHorizontalRange = function (firstValue, secondValue) { + var endValue = Math.max(firstValue, secondValue); + var startValue = Math.min(firstValue, secondValue); + + this.updateHorizontalRange(endValue, startValue); +}; + +c3_chart_internal_fn.setRangeVisible = function (visible) { + var divs = this.d3.selectAll('[graph-id="' + this.config.bindto.replace('#', '') + '"] .slider-vertical, .slider-horizontal, .c3-reference-vertical-range, .c3-reference-horizontal-range'); + divs.each(function () { + this.classList.toggle("ng-hide", !visible); + }); +};
" + title + "
" + name + "" + value + "