+ }
+
+ 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;
+
+ for (i = 0; i < notfoundIds.length; i++) {
+ if (t.id === notfoundIds[i]) {
+ tail = t.values[t.values.length - 1].index + 1;
+
+ for (j = 0; j < length; j++) {
+ t.values.push({
+ id: t.id,
+ index: tail + j,
+ x: $$.isTimeSeries() ? $$.getOtherTargetX(tail + j) : tail + j,
+ value: null
+ });
+ }
+ }
+ }
+ }); // Generate null values for new target
+
+ if ($$.data.targets.length) {
+ targets.forEach(function (t) {
+ var i,
+ missing = [];
+
+ for (i = $$.data.targets[0].values[0].index; i < tail; i++) {
+ missing.push({
+ id: t.id,
+ index: i,
+ x: $$.isTimeSeries() ? $$.getOtherTargetX(i) : i,
+ value: null
+ });
+ }
+
+ t.values.forEach(function (v) {
+ v.index += tail;
+
+ if (!$$.isTimeSeries()) {
+ v.x += tail;
+ }
+ });
+ t.values = missing.concat(t.values);
+ });
+ }
+
+ $$.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;
+ to = $$.isTimeSeries() ? $$.parseDate(args.to) : args.to;
+ baseTarget.values.forEach(function (v) {
+ if (v.x < to) {
+ length++;
+ }
+ });
+ } 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()) {
+ if (baseTarget.values.length > 1) {
+ diff = baseTarget.values[baseTarget.values.length - 1].x - baseValue.x;
+ } else {
+ diff = baseValue.x - $$.getXDomain($$.data.targets)[0];
+ }
+ } else {
+ diff = 1;
+ }
+
+ domain = [baseValue.x - diff, baseValue.x];
+ $$.updateXDomain(null, true, true, false, domain);
+ } else if (orgDataCount === 1) {
+ if ($$.isTimeSeries()) {
+ diff = (baseTarget.values[baseTarget.values.length - 1].x - baseValue.x) / 2;
+ domain = [new Date(+baseValue.x - diff), new Date(+baseValue.x + diff)];
+ $$.updateXDomain(null, true, true, false, domain);
+ }
+ } // Set targets
+
+
+ $$.updateTargets($$.data.targets); // Redraw with new targets
+
+ $$.redraw({
+ flow: {
+ index: baseValue.index,
+ length: length,
+ duration: isValue(args.duration) ? args.duration : $$.config.transition_duration,
+ done: args.done,
+ orgDataCount: orgDataCount
+ },
+ withLegend: true,
+ withTransition: orgDataCount > 1,
+ withTrimXDomain: false,
+ withUpdateXAxis: true
+ });
+ };
+
+ ChartInternal.prototype.generateFlow = function (args) {
+ var $$ = this,
+ config = $$.config,
+ d3 = $$.d3;
+ return function () {
+ var targets = args.targets,
+ flow = args.flow,
+ drawBar = args.drawBar,
+ drawLine = args.drawLine,
+ drawArea = args.drawArea,
+ cx = args.cx,
+ cy = args.cy,
+ xv = args.xv,
+ xForText = args.xForText,
+ yForText = args.yForText,
+ duration = args.duration;
+
+ var translateX,
+ scaleX = 1,
+ transform,
+ flowIndex = flow.index,
+ flowLength = flow.length,
+ flowStart = $$.getValueOnIndex($$.data.targets[0].values, flowIndex),
+ flowEnd = $$.getValueOnIndex($$.data.targets[0].values, flowIndex + flowLength),
+ orgDomain = $$.x.domain(),
+ domain,
+ durationForFlow = flow.duration || duration,
+ done = flow.done || function () {},
+ wait = $$.generateWait();
+
+ var xgrid, xgridLines, mainRegion, mainText, mainBar, mainLine, mainArea, mainCircle; // 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);
+ }
+
+ xgrid = $$.xgrid || d3.selectAll([]); // xgrid needs to be obtained after updateXGrid
+
+ xgridLines = $$.xgridLines || d3.selectAll([]);
+ mainRegion = $$.mainRegion || d3.selectAll([]);
+ mainText = $$.mainText || d3.selectAll([]);
+ mainBar = $$.mainBar || d3.selectAll([]);
+ mainLine = $$.mainLine || d3.selectAll([]);
+ mainArea = $$.mainArea || d3.selectAll([]);
+ mainCircle = $$.mainCircle || d3.selectAll([]); // generate transform to flow
+
+ if (!flow.orgDataCount) {
+ // if empty
+ if ($$.data.targets[0].values.length !== 1) {
+ translateX = $$.x(orgDomain[0]) - $$.x(domain[0]);
+ } else {
+ if ($$.isTimeSeries()) {
+ flowStart = $$.getValueOnIndex($$.data.targets[0].values, 0);
+ flowEnd = $$.getValueOnIndex($$.data.targets[0].values, $$.data.targets[0].values.length - 1);
+ translateX = $$.x(flowStart.x) - $$.x(flowEnd.x);
+ } else {
+ translateX = diffDomain(domain) / 2;
+ }
+ }
+ } else if (flow.orgDataCount === 1 || (flowStart && flowStart.x) === (flowEnd && flowEnd.x)) {
+ translateX = $$.x(orgDomain[0]) - $$.x(domain[0]);
+ } else {
+ if ($$.isTimeSeries()) {
+ translateX = $$.x(orgDomain[0]) - $$.x(domain[0]);
+ } else {
+ translateX = $$.x(flowStart.x) - $$.x(flowEnd.x);
+ }
+ }
+
+ scaleX = diffDomain(orgDomain) / diffDomain(domain);
+ transform = 'translate(' + translateX + ',0) scale(' + scaleX + ',1)';
+ $$.hideXGridFocus();
+ var flowTransition = d3.transition().ease(d3.easeLinear).duration(durationForFlow);
+ wait.add($$.xAxis($$.axes.x, flowTransition));
+ wait.add(mainBar.transition(flowTransition).attr('transform', transform));
+ wait.add(mainLine.transition(flowTransition).attr('transform', transform));
+ wait.add(mainArea.transition(flowTransition).attr('transform', transform));
+ wait.add(mainCircle.transition(flowTransition).attr('transform', transform));
+ wait.add(mainText.transition(flowTransition).attr('transform', transform));
+ wait.add(mainRegion.filter($$.isRegionOnX).transition(flowTransition).attr('transform', transform));
+ wait.add(xgrid.transition(flowTransition).attr('transform', transform));
+ wait.add(xgridLines.transition(flowTransition).attr('transform', transform));
+ wait(function () {
+ var i,
+ shapes = [],
+ texts = []; // remove flowed elements
+
+ if (flowLength) {
+ for (i = 0; i < flowLength; i++) {
+ shapes.push('.' + CLASS.shape + '-' + (flowIndex + i));
+ texts.push('.' + CLASS.text + '-' + (flowIndex + i));
+ }
+
+ $$.svg.selectAll('.' + CLASS.shapes).selectAll(shapes).remove();
+ $$.svg.selectAll('.' + CLASS.texts).selectAll(texts).remove();
+ $$.svg.select('.' + CLASS.xgrid).remove();
+ } // draw again for removing flowed elements and reverting attr
+
+
+ xgrid.attr('transform', null).attr('x1', $$.xgridAttr.x1).attr('x2', $$.xgridAttr.x2).attr('y1', $$.xgridAttr.y1).attr('y2', $$.xgridAttr.y2).style("opacity", $$.xgridAttr.opacity);
+ xgridLines.attr('transform', null);
+ xgridLines.select('line').attr("x1", config.axis_rotated ? 0 : xv).attr("x2", config.axis_rotated ? $$.width : xv);
+ xgridLines.select('text').attr("x", config.axis_rotated ? $$.width : 0).attr("y", xv);
+ mainBar.attr('transform', null).attr("d", drawBar);
+ mainLine.attr('transform', null).attr("d", drawLine);
+ mainArea.attr('transform', null).attr("d", drawArea);
+ mainCircle.attr('transform', null).attr("cx", cx).attr("cy", cy);
+ mainText.attr('transform', null).attr('x', xForText).attr('y', yForText).style('fill-opacity', $$.opacityForText.bind($$));
+ mainRegion.attr('transform', null);
+ mainRegion.filter($$.isRegionOnX).attr("x", $$.regionX.bind($$)).attr("width", $$.regionWidth.bind($$)); // callback for end of flow
+
+ done();
+ $$.flowing = false;
+ });
+ };
+ };
+
+ Chart.prototype.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);
+
+ if ($$.hasArcType()) {
+ $$.expandArc(targetIds);
+ }
+
+ $$.toggleFocusLegend(targetIds, true);
+ $$.focusedTargetIds = targetIds;
+ $$.defocusedTargetIds = $$.defocusedTargetIds.filter(function (id) {
+ return targetIds.indexOf(id) < 0;
+ });
+ };
+
+ Chart.prototype.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;
+ };
+
+ Chart.prototype.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);
+ }
+
+ if ($$.config.legend_show) {
+ $$.showLegend(targetIds.filter($$.isLegendToShow.bind($$)));
+ $$.legend.selectAll($$.selectorLegends(targetIds)).filter(function () {
+ return $$.d3.select(this).classed(CLASS.legendItemFocused);
+ }).classed(CLASS.legendItemFocused, false);
+ }
+
+ $$.focusedTargetIds = [];
+ $$.defocusedTargetIds = [];
+ };
+
+ Chart.prototype.xgrids = function (grids) {
+ var $$ = this.internal,
+ config = $$.config;
+
+ if (!grids) {
+ return config.grid_x_lines;
+ }
+
+ config.grid_x_lines = grids;
+ $$.redrawWithoutRescale();
+ return config.grid_x_lines;
+ };
+
+ Chart.prototype.xgrids.add = function (grids) {
+ var $$ = this.internal;
+ return this.xgrids($$.config.grid_x_lines.concat(grids ? grids : []));
+ };
+
+ Chart.prototype.xgrids.remove = function (params) {
+ // TODO: multiple
+ var $$ = this.internal;
+ $$.removeGridLines(params, true);
+ };
+
+ Chart.prototype.ygrids = function (grids) {
+ var $$ = this.internal,
+ config = $$.config;
+
+ if (!grids) {
+ return config.grid_y_lines;
+ }
+
+ config.grid_y_lines = grids;
+ $$.redrawWithoutRescale();
+ return config.grid_y_lines;
+ };
+
+ Chart.prototype.ygrids.add = function (grids) {
+ var $$ = this.internal;
+ return this.ygrids($$.config.grid_y_lines.concat(grids ? grids : []));
+ };
+
+ Chart.prototype.ygrids.remove = function (params) {
+ // TODO: multiple
+ var $$ = this.internal;
+ $$.removeGridLines(params, false);
+ };
+
+ Chart.prototype.groups = function (groups) {
+ var $$ = this.internal,
+ config = $$.config;
+
+ if (isUndefined(groups)) {
+ return config.data_groups;
+ }
+
+ config.data_groups = groups;
+ $$.redraw();
+ return config.data_groups;
+ };
+
+ Chart.prototype.legend = function () {};
+
+ Chart.prototype.legend.show = function (targetIds) {
+ var $$ = this.internal;
+ $$.showLegend($$.mapToTargetIds(targetIds));
+ $$.updateAndRedraw({
+ withLegend: true
+ });
+ };
+
+ Chart.prototype.legend.hide = function (targetIds) {
+ var $$ = this.internal;
+ $$.hideLegend($$.mapToTargetIds(targetIds));
+ $$.updateAndRedraw({
+ withLegend: false
+ });
+ };
+
+ Chart.prototype.load = function (args) {
+ var $$ = this.internal,
+ config = $$.config; // update xs if specified
+
+ if (args.xs) {
+ $$.addXs(args.xs);
+ } // update names if exists
+
+
+ if ('names' in args) {
+ Chart.prototype.data.names.bind(this)(args.names);
+ } // update classes if exists
+
+
+ if ('classes' in args) {
+ Object.keys(args.classes).forEach(function (id) {
+ config.data_classes[id] = args.classes[id];
+ });
+ } // update categories if exists
+
+
+ if ('categories' in args && $$.isCategorized()) {
+ config.axis_x_categories = args.categories;
+ } // update axes if exists
+
+
+ if ('axes' in args) {
+ Object.keys(args.axes).forEach(function (id) {
+ config.data_axes[id] = args.axes[id];
+ });
+ } // update colors if exists
+
+
+ if ('colors' in args) {
+ Object.keys(args.colors).forEach(function (id) {
+ config.data_colors[id] = args.colors[id];
+ });
+ } // use cache if exists
+
+
+ if ('cacheIds' in args && $$.hasCaches(args.cacheIds)) {
+ $$.load($$.getCaches(args.cacheIds), args.done);
+ return;
+ } // unload if needed
+
+
+ if ('unload' in args) {
+ // TODO: do not unload if target will load (included in url/rows/columns)
+ $$.unload($$.mapToTargetIds(typeof args.unload === 'boolean' && args.unload ? null : args.unload), function () {
+ $$.loadFromArgs(args);
+ });
+ } else {
+ $$.loadFromArgs(args);
+ }
+ };
+
+ Chart.prototype.unload = function (args) {
+ var $$ = this.internal;
+ args = args || {};
+
+ if (args instanceof Array) {
+ args = {
+ ids: args
+ };
+ } else if (typeof args === 'string') {
+ args = {
+ ids: [args]
+ };
+ }
+
+ $$.unload($$.mapToTargetIds(args.ids), function () {
+ $$.redraw({
+ withUpdateOrgXDomain: true,
+ withUpdateXDomain: true,
+ withLegend: true
+ });
+
+ if (args.done) {
+ args.done();
+ }
+ });
+ };
+
+ Chart.prototype.regions = function (regions) {
+ var $$ = this.internal,
+ config = $$.config;
+
+ if (!regions) {
+ return config.regions;
+ }
+
+ config.regions = regions;
+ $$.redrawWithoutRescale();
+ return config.regions;
+ };
+
+ Chart.prototype.regions.add = function (regions) {
+ var $$ = this.internal,
+ config = $$.config;
+
+ if (!regions) {
+ return config.regions;
+ }
+
+ config.regions = config.regions.concat(regions);
+ $$.redrawWithoutRescale();
+ return config.regions;
+ };
+
+ Chart.prototype.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']) {
+ return true;
+ }
+
+ region['class'].split(' ').forEach(function (c) {
+ if (classes.indexOf(c) >= 0) {
+ found = true;
+ }
+ });
+ return !found;
+ });
+ return config.regions;
+ };
+
+ Chart.prototype.selected = function (targetId) {
+ var $$ = this.internal,
+ d3 = $$.d3;
+ return d3.merge($$.main.selectAll('.' + CLASS.shapes + $$.getTargetSelectorSuffix(targetId)).selectAll('.' + CLASS.shape).filter(function () {
+ return d3.select(this).classed(CLASS.SELECTED);
+ }).map(function (d) {
+ return d.map(function (d) {
+ var data = d.__data__;
+ return data.data ? data.data : data;
+ });
+ }));
+ };
+
+ Chart.prototype.select = function (ids, indices, resetOther) {
+ var $$ = this.internal,
+ d3 = $$.d3,
+ config = $$.config;
+
+ if (!config.data_selection_enabled) {
+ return;
+ }
+
+ $$.main.selectAll('.' + CLASS.shapes).selectAll('.' + CLASS.shape).each(function (d, i) {
+ var shape = d3.select(this),
+ id = d.data ? d.data.id : d.id,
+ toggle = $$.getToggle(this, d).bind($$),
+ isTargetId = config.data_selection_grouped || !ids || ids.indexOf(id) >= 0,
+ isTargetIndex = !indices || indices.indexOf(i) >= 0,
+ isSelected = shape.classed(CLASS.SELECTED); // line/area selection not supported yet
+
+ if (shape.classed(CLASS.line) || shape.classed(CLASS.area)) {
+ return;
+ }
+
+ if (isTargetId && isTargetIndex) {
+ if (config.data_selection_isselectable(d) && !isSelected) {
+ toggle(true, shape.classed(CLASS.SELECTED, true), d, i);
+ }
+ } else if (isDefined(resetOther) && resetOther) {
+ if (isSelected) {
+ toggle(false, shape.classed(CLASS.SELECTED, false), d, i);
+ }
+ }
+ });
+ };
+
+ Chart.prototype.unselect = function (ids, indices) {
+ var $$ = this.internal,
+ d3 = $$.d3,
+ config = $$.config;
+
+ if (!config.data_selection_enabled) {
+ return;
+ }
+
+ $$.main.selectAll('.' + CLASS.shapes).selectAll('.' + CLASS.shape).each(function (d, i) {
+ var shape = d3.select(this),
+ id = d.data ? d.data.id : d.id,
+ toggle = $$.getToggle(this, d).bind($$),
+ isTargetId = config.data_selection_grouped || !ids || ids.indexOf(id) >= 0,
+ isTargetIndex = !indices || indices.indexOf(i) >= 0,
+ isSelected = shape.classed(CLASS.SELECTED); // line/area selection not supported yet
+
+ if (shape.classed(CLASS.line) || shape.classed(CLASS.area)) {
+ return;
+ }
+
+ if (isTargetId && isTargetIndex) {
+ if (config.data_selection_isselectable(d)) {
+ if (isSelected) {
+ toggle(false, shape.classed(CLASS.SELECTED, false), d, i);
+ }
+ }
+ }
+ });
+ };
+
+ Chart.prototype.show = function (targetIds, options) {
+ var $$ = this.internal,
+ targets;
+ targetIds = $$.mapToTargetIds(targetIds);
+ options = options || {};
+ $$.removeHiddenTargetIds(targetIds);
+ targets = $$.svg.selectAll($$.selectorTargets(targetIds));
+ targets.transition().style('display', 'initial', 'important').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
+ });
+ };
+
+ Chart.prototype.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);
+ targets.style('display', 'none');
+ });
+
+ if (options.withLegend) {
+ $$.hideLegend(targetIds);
+ }
+
+ $$.redraw({
+ withUpdateOrgXDomain: true,
+ withUpdateXDomain: true,
+ withLegend: true
+ });
+ };
+
+ Chart.prototype.toggle = function (targetIds, options) {
+ var that = this,
+ $$ = this.internal;
+ $$.mapToTargetIds(targetIds).forEach(function (targetId) {
+ $$.isTargetToShow(targetId) ? that.hide(targetId, options) : that.show(targetId, options);
+ });
+ };
+
+ Chart.prototype.tooltip = function () {};
+
+ Chart.prototype.tooltip.show = function (args) {
+ var $$ = this.internal,
+ targets,
+ data,
+ mouse = {}; // determine mouse position on the chart
+
+ if (args.mouse) {
+ mouse = args.mouse;
+ } else {
+ // determine focus data
+ if (args.data) {
+ data = args.data;
+ } else if (typeof args.x !== 'undefined') {
+ if (args.id) {
+ targets = $$.data.targets.filter(function (t) {
+ return t.id === args.id;
+ });
+ } else {
+ targets = $$.data.targets;
+ }
+
+ data = $$.filterByX(targets, args.x).slice(0, 1)[0];
+ }
+
+ mouse = data ? $$.getMousePosition(data) : null;
+ } // emulate mouse events to show
+
+
+ $$.dispatchEvent('mousemove', mouse);
+ $$.config.tooltip_onshow.call($$, data);
+ };
+
+ Chart.prototype.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);
+ };
+
+ Chart.prototype.transform = function (type, targetIds) {
+ var $$ = this.internal,
+ options = ['pie', 'donut'].indexOf(type) >= 0 ? {
+ withTransform: true
+ } : null;
+ $$.transformTo(targetIds, type, options);
+ };
+
+ ChartInternal.prototype.transformTo = function (targetIds, type, optionsForRedraw) {
+ var $$ = this,
+ withTransitionForAxis = !$$.hasArcType(),
+ options = optionsForRedraw || {
+ withTransitionForAxis: withTransitionForAxis
+ };
+ options.withTransitionForTransform = false;
+ $$.transiting = false;
+ $$.setTargetType(targetIds, type);
+ $$.updateTargets($$.data.targets); // this is needed when transforming to arc
+
+ $$.updateAndRedraw(options);
+ };
+
+ Chart.prototype.x = function (x) {
+ var $$ = this.internal;
+
+ if (arguments.length) {
+ $$.updateTargetX($$.data.targets, x);
+ $$.redraw({
+ withUpdateOrgXDomain: true,
+ withUpdateXDomain: true
+ });
+ }
+
+ return $$.data.xs;
+ };
+
+ Chart.prototype.xs = function (xs) {
+ var $$ = this.internal;
+
+ if (arguments.length) {
+ $$.updateTargetXs($$.data.targets, xs);
+ $$.redraw({
+ withUpdateOrgXDomain: true,
+ withUpdateXDomain: true
+ });
+ }
+
+ return $$.data.xs;
+ };
+
+ Chart.prototype.zoom = function (domain) {
+ var $$ = this.internal;
+
+ if (domain) {
+ if ($$.isTimeSeries()) {
+ domain = domain.map(function (x) {
+ return $$.parseDate(x);
+ });
+ }
+
+ if ($$.config.subchart_show) {
+ $$.brush.selectionAsValue(domain, true);
+ } else {
+ $$.updateXDomain(null, true, false, false, domain);
+ $$.redraw({
+ withY: $$.config.zoom_rescale,
+ withSubchart: false
+ });
+ }
+
+ $$.config.zoom_onzoom.call(this, $$.x.orgDomain());
+ return domain;
+ } else {
+ return $$.x.domain();
+ }
+ };
+
+ Chart.prototype.zoom.enable = function (enabled) {
+ var $$ = this.internal;
+ $$.config.zoom_enabled = enabled;
+ $$.updateAndRedraw();
+ };
+
+ Chart.prototype.unzoom = function () {
+ var $$ = this.internal;
+
+ if ($$.config.subchart_show) {
+ $$.brush.clear();
+ } else {
+ $$.updateXDomain(null, true, false, false, $$.subX.domain());
+ $$.redraw({
+ withY: $$.config.zoom_rescale,
+ withSubchart: false
+ });
+ }
+ };
+
+ Chart.prototype.zoom.max = function (max) {
+ var $$ = this.internal,
+ config = $$.config,
+ d3 = $$.d3;
+
+ if (max === 0 || max) {
+ config.zoom_x_max = d3.max([$$.orgXDomain[1], max]);
+ } else {
+ return config.zoom_x_max;
+ }
+ };
+
+ Chart.prototype.zoom.min = function (min) {
+ var $$ = this.internal,
+ config = $$.config,
+ d3 = $$.d3;
+
+ if (min === 0 || min) {
+ config.zoom_x_min = d3.min([$$.orgXDomain[0], min]);
+ } else {
+ return config.zoom_x_min;
+ }
+ };
+
+ Chart.prototype.zoom.range = function (range) {
+ if (arguments.length) {
+ if (isDefined(range.max)) {
+ this.domain.max(range.max);
+ }
+
+ if (isDefined(range.min)) {
+ this.domain.min(range.min);
+ }
+ } else {
+ return {
+ max: this.domain.max(),
+ min: this.domain.min()
+ };
+ }
+ };
+
+ ChartInternal.prototype.initPie = function () {
+ var $$ = this,
+ d3 = $$.d3;
+ $$.pie = d3.pie().value(function (d) {
+ return d.values.reduce(function (a, b) {
+ return a + b.value;
+ }, 0);
+ });
+ var orderFct = $$.getOrderFunction(); // we need to reverse the returned order if asc or desc to have the slice in expected order.
+
+ if (orderFct && ($$.isOrderAsc() || $$.isOrderDesc())) {
+ var defaultSort = orderFct;
+
+ orderFct = function orderFct(t1, t2) {
+ return defaultSort(t1, t2) * -1;
+ };
+ }
+
+ $$.pie.sort(orderFct || null);
+ };
+
+ ChartInternal.prototype.updateRadius = function () {
+ var $$ = this,
+ config = $$.config,
+ w = config.gauge_width || config.donut_width,
+ gaugeArcWidth = $$.filterTargetsToShow($$.data.targets).length * $$.config.gauge_arcs_minWidth;
+ $$.radiusExpanded = Math.min($$.arcWidth, $$.arcHeight) / 2 * ($$.hasType('gauge') ? 0.85 : 1);
+ $$.radius = $$.radiusExpanded * 0.95;
+ $$.innerRadiusRatio = w ? ($$.radius - w) / $$.radius : 0.6;
+ $$.innerRadius = $$.hasType('donut') || $$.hasType('gauge') ? $$.radius * $$.innerRadiusRatio : 0;
+ $$.gaugeArcWidth = w ? w : gaugeArcWidth <= $$.radius - $$.innerRadius ? $$.radius - $$.innerRadius : gaugeArcWidth <= $$.radius ? gaugeArcWidth : $$.radius;
+ };
+
+ ChartInternal.prototype.updateArc = function () {
+ var $$ = this;
+ $$.svgArc = $$.getSvgArc();
+ $$.svgArcExpanded = $$.getSvgArcExpanded();
+ $$.svgArcExpandedSub = $$.getSvgArcExpanded(0.98);
+ };
+
+ ChartInternal.prototype.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;
+ d = t;
+ d.index = index;
+ }
+
+ index++;
+ });
+
+ if (isNaN(d.startAngle)) {
+ d.startAngle = 0;
+ }
+
+ if (isNaN(d.endAngle)) {
+ d.endAngle = d.startAngle;
+ }
+
+ if ($$.isGaugeType(d.data)) {
+ gMin = config.gauge_min;
+ gMax = config.gauge_max;
+ gTic = Math.PI * (config.gauge_fullCircle ? 2 : 1) / (gMax - gMin);
+ gValue = d.value < gMin ? 0 : d.value < gMax ? d.value - gMin : gMax - gMin;
+ d.startAngle = config.gauge_startingAngle;
+ d.endAngle = d.startAngle + gTic * gValue;
+ }
+
+ return found ? d : null;
+ };
+
+ ChartInternal.prototype.getSvgArc = function () {
+ var $$ = this,
+ hasGaugeType = $$.hasType('gauge'),
+ singleArcWidth = $$.gaugeArcWidth / $$.filterTargetsToShow($$.data.targets).length,
+ arc = $$.d3.arc().outerRadius(function (d) {
+ return hasGaugeType ? $$.radius - singleArcWidth * d.index : $$.radius;
+ }).innerRadius(function (d) {
+ return hasGaugeType ? $$.radius - singleArcWidth * (d.index + 1) : $$.innerRadius;
+ }),
+ newArc = function newArc(d, withoutUpdate) {
+ var updated;
+
+ if (withoutUpdate) {
+ return arc(d);
+ } // for interpolate
+
+
+ updated = $$.updateAngle(d);
+ return updated ? arc(updated) : "M 0 0";
+ }; // TODO: extends all function
+
+
+ newArc.centroid = arc.centroid;
+ return newArc;
+ };
+
+ ChartInternal.prototype.getSvgArcExpanded = function (rate) {
+ rate = rate || 1;
+ var $$ = this,
+ hasGaugeType = $$.hasType('gauge'),
+ singleArcWidth = $$.gaugeArcWidth / $$.filterTargetsToShow($$.data.targets).length,
+ expandWidth = Math.min($$.radiusExpanded * rate - $$.radius, singleArcWidth * 0.8 - (1 - rate) * 100),
+ arc = $$.d3.arc().outerRadius(function (d) {
+ return hasGaugeType ? $$.radius - singleArcWidth * d.index + expandWidth : $$.radiusExpanded * rate;
+ }).innerRadius(function (d) {
+ return hasGaugeType ? $$.radius - singleArcWidth * (d.index + 1) : $$.innerRadius;
+ });
+ return function (d) {
+ var updated = $$.updateAngle(d);
+ return updated ? arc(updated) : "M 0 0";
+ };
+ };
+
+ ChartInternal.prototype.getArc = function (d, withoutUpdate, force) {
+ return force || this.isArcType(d.data) ? this.svgArc(d, withoutUpdate) : "M 0 0";
+ };
+
+ ChartInternal.prototype.transformForArcLabel = function (d) {
+ var $$ = this,
+ config = $$.config,
+ updated = $$.updateAngle(d),
+ c,
+ x,
+ y,
+ h,
+ ratio,
+ translate = "",
+ hasGauge = $$.hasType('gauge');
+
+ if (updated && !hasGauge) {
+ c = this.svgArc.centroid(updated);
+ x = isNaN(c[0]) ? 0 : c[0];
+ y = isNaN(c[1]) ? 0 : c[1];
+ h = Math.sqrt(x * x + y * y);
+
+ if ($$.hasType('donut') && config.donut_label_ratio) {
+ ratio = isFunction(config.donut_label_ratio) ? config.donut_label_ratio(d, $$.radius, h) : config.donut_label_ratio;
+ } else if ($$.hasType('pie') && config.pie_label_ratio) {
+ ratio = isFunction(config.pie_label_ratio) ? config.pie_label_ratio(d, $$.radius, h) : config.pie_label_ratio;
+ } else {
+ ratio = $$.radius && h ? (36 / $$.radius > 0.375 ? 1.175 - 36 / $$.radius : 0.8) * $$.radius / h : 0;
+ }
+
+ translate = "translate(" + x * ratio + ',' + y * ratio + ")";
+ } else if (updated && hasGauge && $$.filterTargetsToShow($$.data.targets).length > 1) {
+ var y1 = Math.sin(updated.endAngle - Math.PI / 2);
+ x = Math.cos(updated.endAngle - Math.PI / 2) * ($$.radiusExpanded + 25);
+ y = y1 * ($$.radiusExpanded + 15 - Math.abs(y1 * 10)) + 3;
+ translate = "translate(" + x + ',' + y + ")";
+ }
+
+ return translate;
+ };
+
+ ChartInternal.prototype.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;
+ };
+
+ ChartInternal.prototype.convertToArcData = function (d) {
+ return this.addName({
+ id: d.data.id,
+ value: d.value,
+ ratio: this.getArcRatio(d),
+ index: d.index
+ });
+ };
+
+ ChartInternal.prototype.textForArcLabel = function (d) {
+ var $$ = this,
+ updated,
+ value,
+ ratio,
+ id,
+ format;
+
+ if (!$$.shouldShowArcLabel()) {
+ return "";
+ }
+
+ updated = $$.updateAngle(d);
+ value = updated ? updated.value : null;
+ ratio = $$.getArcRatio(updated);
+ id = d.data.id;
+
+ if (!$$.hasType('gauge') && !$$.meetsArcLabelThreshold(ratio)) {
+ return "";
+ }
+
+ format = $$.getArcLabelFormat();
+ return format ? format(value, ratio, id) : $$.defaultArcValueFormat(value, ratio);
+ };
+
+ ChartInternal.prototype.textForGaugeMinMax = function (value, isMax) {
+ var $$ = this,
+ format = $$.getGaugeLabelExtents();
+ return format ? format(value, isMax) : value;
+ };
+
+ ChartInternal.prototype.expandArc = function (targetIds) {
+ var $$ = this,
+ interval; // MEMO: avoid to cancel transition
+
+ if ($$.transiting) {
+ interval = window.setInterval(function () {
+ if (!$$.transiting) {
+ window.clearInterval(interval);
+
+ if ($$.legend.selectAll('.c3-legend-item-focused').size() > 0) {
+ $$.expandArc(targetIds);
+ }
+ }
+ }, 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').transition().duration($$.expandDuration(d.data.id)).attr("d", $$.svgArcExpanded).transition().duration($$.expandDuration(d.data.id) * 2).attr("d", $$.svgArcExpandedSub).each(function (d) {
+ if ($$.isDonutType(d.data)) ;
+ });
+ });
+ };
+
+ ChartInternal.prototype.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);
+ }).attr("d", $$.svgArc);
+ $$.svg.selectAll('.' + CLASS.arc);
+ };
+
+ ChartInternal.prototype.expandDuration = function (id) {
+ var $$ = this,
+ config = $$.config;
+
+ if ($$.isDonutType(id)) {
+ return config.donut_expand_duration;
+ } else if ($$.isGaugeType(id)) {
+ return config.gauge_expand_duration;
+ } else if ($$.isPieType(id)) {
+ return config.pie_expand_duration;
+ } else {
+ return 50;
+ }
+ };
+
+ ChartInternal.prototype.shouldExpand = function (id) {
+ var $$ = this,
+ config = $$.config;
+ return $$.isDonutType(id) && config.donut_expand || $$.isGaugeType(id) && config.gauge_expand || $$.isPieType(id) && config.pie_expand;
+ };
+
+ ChartInternal.prototype.shouldShowArcLabel = function () {
+ var $$ = this,
+ config = $$.config,
+ shouldShow = true;
+
+ if ($$.hasType('donut')) {
+ shouldShow = config.donut_label_show;
+ } else if ($$.hasType('pie')) {
+ shouldShow = config.pie_label_show;
+ } // when gauge, always true
+
+
+ return shouldShow;
+ };
+
+ ChartInternal.prototype.meetsArcLabelThreshold = function (ratio) {
+ var $$ = this,
+ config = $$.config,
+ threshold = $$.hasType('donut') ? config.donut_label_threshold : config.pie_label_threshold;
+ return ratio >= threshold;
+ };
+
+ ChartInternal.prototype.getArcLabelFormat = function () {
+ var $$ = this,
+ config = $$.config,
+ format = config.pie_label_format;
+
+ if ($$.hasType('gauge')) {
+ format = config.gauge_label_format;
+ } else if ($$.hasType('donut')) {
+ format = config.donut_label_format;
+ }
+
+ return format;
+ };
+
+ ChartInternal.prototype.getGaugeLabelExtents = function () {
+ var $$ = this,
+ config = $$.config;
+ return config.gauge_label_extents;
+ };
+
+ ChartInternal.prototype.getArcTitle = function () {
+ var $$ = this;
+ return $$.hasType('donut') ? $$.config.donut_title : "";
+ };
+
+ ChartInternal.prototype.updateTargetsForArc = function (targets) {
+ var $$ = this,
+ main = $$.main,
+ mainPies,
+ mainPieEnter,
+ classChartArc = $$.classChartArc.bind($$),
+ classArcs = $$.classArcs.bind($$),
+ classFocus = $$.classFocus.bind($$);
+ mainPies = main.select('.' + CLASS.chartArcs).selectAll('.' + CLASS.chartArc).data($$.pie(targets)).attr("class", function (d) {
+ return classChartArc(d) + classFocus(d.data);
+ });
+ mainPieEnter = mainPies.enter().append("g").attr("class", classChartArc);
+ mainPieEnter.append('g').attr('class', classArcs);
+ mainPieEnter.append("text").attr("dy", $$.hasType('gauge') ? "-.1em" : ".35em").style("opacity", 0).style("text-anchor", "middle").style("pointer-events", "none"); // MEMO: can not keep same color..., but not bad to update color in redraw
+ //mainPieUpdate.exit().remove();
+ };
+
+ ChartInternal.prototype.initArc = function () {
+ var $$ = this;
+ $$.arcs = $$.main.select('.' + CLASS.chart).append("g").attr("class", CLASS.chartArcs).attr("transform", $$.getTranslate('arc'));
+ $$.arcs.append('text').attr('class', CLASS.chartArcsTitle).style("text-anchor", "middle").text($$.getArcTitle());
+ };
+
+ ChartInternal.prototype.redrawArc = function (duration, durationForExit, withTransform) {
+ var $$ = this,
+ d3 = $$.d3,
+ config = $$.config,
+ main = $$.main,
+ arcs,
+ mainArc,
+ arcLabelLines,
+ mainArcLabelLine,
+ hasGaugeType = $$.hasType('gauge');
+ arcs = main.selectAll('.' + CLASS.arcs).selectAll('.' + CLASS.arc).data($$.arcData.bind($$));
+ mainArc = arcs.enter().append('path').attr("class", $$.classArc.bind($$)).style("fill", function (d) {
+ return $$.color(d.data);
+ }).style("cursor", function (d) {
+ return config.interaction_enabled && config.data_selection_isselectable(d) ? "pointer" : null;
+ }).each(function (d) {
+ if ($$.isGaugeType(d.data)) {
+ d.startAngle = d.endAngle = config.gauge_startingAngle;
+ }
+
+ this._current = d;
+ }).merge(arcs);
+
+ if (hasGaugeType) {
+ arcLabelLines = main.selectAll('.' + CLASS.arcs).selectAll('.' + CLASS.arcLabelLine).data($$.arcData.bind($$));
+ mainArcLabelLine = arcLabelLines.enter().append('rect').attr("class", function (d) {
+ return CLASS.arcLabelLine + ' ' + CLASS.target + ' ' + CLASS.target + '-' + d.data.id;
+ }).merge(arcLabelLines);
+
+ if ($$.filterTargetsToShow($$.data.targets).length === 1) {
+ mainArcLabelLine.style("display", "none");
+ } else {
+ mainArcLabelLine.style("fill", function (d) {
+ return config.color_pattern.length > 0 ? $$.levelColor(d.data.values[0].value) : $$.color(d.data);
+ }).style("display", config.gauge_labelLine_show ? "" : "none").each(function (d) {
+ var lineLength = 0,
+ lineThickness = 2,
+ x = 0,
+ y = 0,
+ transform = "";
+
+ if ($$.hiddenTargetIds.indexOf(d.data.id) < 0) {
+ var updated = $$.updateAngle(d),
+ innerLineLength = $$.gaugeArcWidth / $$.filterTargetsToShow($$.data.targets).length * (updated.index + 1),
+ lineAngle = updated.endAngle - Math.PI / 2,
+ arcInnerRadius = $$.radius - innerLineLength,
+ linePositioningAngle = lineAngle - (arcInnerRadius === 0 ? 0 : 1 / arcInnerRadius);
+ lineLength = $$.radiusExpanded - $$.radius + innerLineLength;
+ x = Math.cos(linePositioningAngle) * arcInnerRadius;
+ y = Math.sin(linePositioningAngle) * arcInnerRadius;
+ transform = "rotate(" + lineAngle * 180 / Math.PI + ", " + x + ", " + y + ")";
+ }
+
+ d3.select(this).attr('x', x).attr('y', y).attr('width', lineLength).attr('height', lineThickness).attr('transform', transform).style("stroke-dasharray", "0, " + (lineLength + lineThickness) + ", 0");
+ });
+ }
+ }
+
+ mainArc.attr("transform", function (d) {
+ return !$$.isGaugeType(d.data) && withTransform ? "scale(0)" : "";
+ }).on('mouseover', config.interaction_enabled ? function (d) {
+ var updated, arcData;
+
+ if ($$.transiting) {
+ // skip while transiting
+ return;
+ }
+
+ updated = $$.updateAngle(d);
+
+ if (updated) {
+ arcData = $$.convertToArcData(updated); // transitions
+
+ $$.expandArc(updated.data.id);
+ $$.api.focus(updated.data.id);
+ $$.toggleFocusLegend(updated.data.id, true);
+ $$.config.data_onmouseover(arcData, this);
+ }
+ } : null).on('mousemove', config.interaction_enabled ? function (d) {
+ var updated = $$.updateAngle(d),
+ arcData,
+ selectedData;
+
+ if (updated) {
+ arcData = $$.convertToArcData(updated), selectedData = [arcData];
+ $$.showTooltip(selectedData, this);
+ }
+ } : null).on('mouseout', config.interaction_enabled ? function (d) {
+ var updated, arcData;
+
+ if ($$.transiting) {
+ // skip while transiting
+ return;
+ }
+
+ updated = $$.updateAngle(d);
+
+ if (updated) {
+ arcData = $$.convertToArcData(updated); // transitions
+
+ $$.unexpandArc(updated.data.id);
+ $$.api.revert();
+ $$.revertLegend();
+ $$.hideTooltip();
+ $$.config.data_onmouseout(arcData, this);
+ }
+ } : null).on('click', config.interaction_enabled ? function (d, i) {
+ var updated = $$.updateAngle(d),
+ arcData;
+
+ if (updated) {
+ arcData = $$.convertToArcData(updated);
+
+ if ($$.toggleShape) {
+ $$.toggleShape(this, arcData, i);
+ }
+
+ $$.config.data_onclick.call($$.api, arcData, this);
+ }
+ } : null).each(function () {
+ $$.transiting = true;
+ }).transition().duration(duration).attrTween("d", function (d) {
+ var updated = $$.updateAngle(d),
+ interpolate;
+
+ if (!updated) {
+ return function () {
+ return "M 0 0";
+ };
+ } // if (this._current === d) {
+ // this._current = {
+ // startAngle: Math.PI*2,
+ // endAngle: Math.PI*2,
+ // };
+ // }
+
+
+ if (isNaN(this._current.startAngle)) {
+ this._current.startAngle = 0;
+ }
+
+ if (isNaN(this._current.endAngle)) {
+ this._current.endAngle = this._current.startAngle;
+ }
+
+ interpolate = d3.interpolate(this._current, updated);
+ this._current = interpolate(0);
+ return function (t) {
+ var interpolated = interpolate(t);
+ interpolated.data = d.data; // data.id will be updated by interporator
+
+ return $$.getArc(interpolated, true);
+ };
+ }).attr("transform", withTransform ? "scale(1)" : "").style("fill", function (d) {
+ return $$.levelColor ? $$.levelColor(d.data.values[0].value) : $$.color(d.data.id);
+ }) // Where gauge reading color would receive customization.
+ .call($$.endall, function () {
+ $$.transiting = false;
+ });
+ arcs.exit().transition().duration(durationForExit).style('opacity', 0).remove();
+ main.selectAll('.' + CLASS.chartArc).select('text').style("opacity", 0).attr('class', function (d) {
+ return $$.isGaugeType(d.data) ? CLASS.gaugeValue : '';
+ }).text($$.textForArcLabel.bind($$)).attr("transform", $$.transformForArcLabel.bind($$)).style('font-size', function (d) {
+ return $$.isGaugeType(d.data) && $$.filterTargetsToShow($$.data.targets).length === 1 ? Math.round($$.radius / 5) + 'px' : '';
+ }).transition().duration(duration).style("opacity", function (d) {
+ return $$.isTargetToShow(d.data.id) && $$.isArcType(d.data) ? 1 : 0;
+ });
+ main.select('.' + CLASS.chartArcsTitle).style("opacity", $$.hasType('donut') || hasGaugeType ? 1 : 0);
+
+ if (hasGaugeType) {
+ var index = 0;
+ var backgroundArc = $$.arcs.select('g.' + CLASS.chartArcsBackground).selectAll('path.' + CLASS.chartArcsBackground).data($$.data.targets);
+ backgroundArc.enter().append("path").attr("class", function (d, i) {
+ return CLASS.chartArcsBackground + ' ' + CLASS.chartArcsBackground + '-' + i;
+ }).merge(backgroundArc).attr("d", function (d1) {
+ if ($$.hiddenTargetIds.indexOf(d1.id) >= 0) {
+ return "M 0 0";
+ }
+
+ var d = {
+ data: [{
+ value: config.gauge_max
+ }],
+ startAngle: config.gauge_startingAngle,
+ endAngle: -1 * config.gauge_startingAngle * (config.gauge_fullCircle ? Math.PI : 1),
+ index: index++
+ };
+ return $$.getArc(d, true, true);
+ });
+ backgroundArc.exit().remove();
+ $$.arcs.select('.' + CLASS.chartArcsGaugeUnit).attr("dy", ".75em").text(config.gauge_label_show ? config.gauge_units : '');
+ $$.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 ? $$.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 ? $$.textForGaugeMinMax(config.gauge_max, true) : '');
+ }
+ };
+
+ ChartInternal.prototype.initGauge = function () {
+ var arcs = this.arcs;
+
+ if (this.hasType('gauge')) {
+ arcs.append('g').attr("class", CLASS.chartArcsBackground);
+ arcs.append("text").attr("class", CLASS.chartArcsGaugeUnit).style("text-anchor", "middle").style("pointer-events", "none");
+ arcs.append("text").attr("class", CLASS.chartArcsGaugeMin).style("text-anchor", "middle").style("pointer-events", "none");
+ arcs.append("text").attr("class", CLASS.chartArcsGaugeMax).style("text-anchor", "middle").style("pointer-events", "none");
+ }
+ };
+
+ ChartInternal.prototype.getGaugeLabelHeight = function () {
+ return this.config.gauge_label_show ? 20 : 0;
+ };
+
+ ChartInternal.prototype.hasCaches = function (ids) {
+ for (var i = 0; i < ids.length; i++) {
+ if (!(ids[i] in this.cache)) {
+ return false;
+ }
+ }
+
+ return true;
+ };
+
+ ChartInternal.prototype.addCache = function (id, target) {
+ this.cache[id] = this.cloneTarget(target);
+ };
+
+ ChartInternal.prototype.getCaches = function (ids) {
+ var targets = [],
+ i;
+
+ for (i = 0; i < ids.length; i++) {
+ if (ids[i] in this.cache) {
+ targets.push(this.cloneTarget(this.cache[ids[i]]));
+ }
+ }
+
+ return targets;
+ };
+
+ ChartInternal.prototype.categoryName = function (i) {
+ var config = this.config;
+ return i < config.axis_x_categories.length ? config.axis_x_categories[i] : i;
+ };
+
+ ChartInternal.prototype.generateTargetClass = function (targetId) {
+ return targetId || targetId === 0 ? ('-' + targetId).replace(/\s/g, '-') : '';
+ };
+
+ ChartInternal.prototype.generateClass = function (prefix, targetId) {
+ return " " + prefix + " " + prefix + this.generateTargetClass(targetId);
+ };
+
+ ChartInternal.prototype.classText = function (d) {
+ return this.generateClass(CLASS.text, d.index);
+ };
+
+ ChartInternal.prototype.classTexts = function (d) {
+ return this.generateClass(CLASS.texts, d.id);
+ };
+
+ ChartInternal.prototype.classShape = function (d) {
+ return this.generateClass(CLASS.shape, d.index);
+ };
+
+ ChartInternal.prototype.classShapes = function (d) {
+ return this.generateClass(CLASS.shapes, d.id);
+ };
+
+ ChartInternal.prototype.classLine = function (d) {
+ return this.classShape(d) + this.generateClass(CLASS.line, d.id);
+ };
+
+ ChartInternal.prototype.classLines = function (d) {
+ return this.classShapes(d) + this.generateClass(CLASS.lines, d.id);
+ };
+
+ ChartInternal.prototype.classCircle = function (d) {
+ return this.classShape(d) + this.generateClass(CLASS.circle, d.index);
+ };
+
+ ChartInternal.prototype.classCircles = function (d) {
+ return this.classShapes(d) + this.generateClass(CLASS.circles, d.id);
+ };
+
+ ChartInternal.prototype.classBar = function (d) {
+ return this.classShape(d) + this.generateClass(CLASS.bar, d.index);
+ };
+
+ ChartInternal.prototype.classBars = function (d) {
+ return this.classShapes(d) + this.generateClass(CLASS.bars, d.id);
+ };
+
+ ChartInternal.prototype.classArc = function (d) {
+ return this.classShape(d.data) + this.generateClass(CLASS.arc, d.data.id);
+ };
+
+ ChartInternal.prototype.classArcs = function (d) {
+ return this.classShapes(d.data) + this.generateClass(CLASS.arcs, d.data.id);
+ };
+
+ ChartInternal.prototype.classArea = function (d) {
+ return this.classShape(d) + this.generateClass(CLASS.area, d.id);
+ };
+
+ ChartInternal.prototype.classAreas = function (d) {
+ return this.classShapes(d) + this.generateClass(CLASS.areas, d.id);
+ };
+
+ ChartInternal.prototype.classRegion = function (d, i) {
+ return this.generateClass(CLASS.region, i) + ' ' + ('class' in d ? d['class'] : '');
+ };
+
+ ChartInternal.prototype.classEvent = function (d) {
+ return this.generateClass(CLASS.eventRect, d.index);
+ };
+
+ ChartInternal.prototype.classTarget = function (id) {
+ var $$ = this;
+ var additionalClassSuffix = $$.config.data_classes[id],
+ additionalClass = '';
+
+ if (additionalClassSuffix) {
+ additionalClass = ' ' + CLASS.target + '-' + additionalClassSuffix;
+ }
+
+ return $$.generateClass(CLASS.target, id) + additionalClass;
+ };
+
+ ChartInternal.prototype.classFocus = function (d) {
+ return this.classFocused(d) + this.classDefocused(d);
+ };
+
+ ChartInternal.prototype.classFocused = function (d) {
+ return ' ' + (this.focusedTargetIds.indexOf(d.id) >= 0 ? CLASS.focused : '');
+ };
+
+ ChartInternal.prototype.classDefocused = function (d) {
+ return ' ' + (this.defocusedTargetIds.indexOf(d.id) >= 0 ? CLASS.defocused : '');
+ };
+
+ ChartInternal.prototype.classChartText = function (d) {
+ return CLASS.chartText + this.classTarget(d.id);
+ };
+
+ ChartInternal.prototype.classChartLine = function (d) {
+ return CLASS.chartLine + this.classTarget(d.id);
+ };
+
+ ChartInternal.prototype.classChartBar = function (d) {
+ return CLASS.chartBar + this.classTarget(d.id);
+ };
+
+ ChartInternal.prototype.classChartArc = function (d) {
+ return CLASS.chartArc + this.classTarget(d.data.id);
+ };
+
+ ChartInternal.prototype.getTargetSelectorSuffix = function (targetId) {
+ return this.generateTargetClass(targetId).replace(/([?!@#$%^&*()_=+,.<>'":;\[\]\/|~`{}\\])/g, '\\$1');
+ };
+
+ ChartInternal.prototype.selectorTarget = function (id, prefix) {
+ return (prefix || '') + '.' + CLASS.target + this.getTargetSelectorSuffix(id);
+ };
+
+ ChartInternal.prototype.selectorTargets = function (ids, prefix) {
+ var $$ = this;
+ ids = ids || [];
+ return ids.length ? ids.map(function (id) {
+ return $$.selectorTarget(id, prefix);
+ }) : null;
+ };
+
+ ChartInternal.prototype.selectorLegend = function (id) {
+ return '.' + CLASS.legendItem + this.getTargetSelectorSuffix(id);
+ };
+
+ ChartInternal.prototype.selectorLegends = function (ids) {
+ var $$ = this;
+ return ids && ids.length ? ids.map(function (id) {
+ return $$.selectorLegend(id);
+ }) : null;
+ };
+
+ ChartInternal.prototype.getClipPath = function (id) {
+ var isIE9 = window.navigator.appVersion.toLowerCase().indexOf("msie 9.") >= 0;
+ return "url(" + (isIE9 ? "" : document.URL.split('#')[0]) + "#" + id + ")";
+ };
+
+ ChartInternal.prototype.appendClip = function (parent, id) {
+ return parent.append("clipPath").attr("id", id).append("rect");
+ };
+
+ ChartInternal.prototype.getAxisClipX = function (forHorizontal) {
+ // axis line width + padding for left
+ var left = Math.max(30, this.margin.left);
+ return forHorizontal ? -(1 + left) : -(left - 1);
+ };
+
+ ChartInternal.prototype.getAxisClipY = function (forHorizontal) {
+ return forHorizontal ? -20 : -this.margin.top;
+ };
+
+ ChartInternal.prototype.getXAxisClipX = function () {
+ var $$ = this;
+ return $$.getAxisClipX(!$$.config.axis_rotated);
+ };
+
+ ChartInternal.prototype.getXAxisClipY = function () {
+ var $$ = this;
+ return $$.getAxisClipY(!$$.config.axis_rotated);
+ };
+
+ ChartInternal.prototype.getYAxisClipX = function () {
+ var $$ = this;
+ return $$.config.axis_y_inner ? -1 : $$.getAxisClipX($$.config.axis_rotated);
+ };
+
+ ChartInternal.prototype.getYAxisClipY = function () {
+ var $$ = this;
+ return $$.getAxisClipY($$.config.axis_rotated);
+ };
+
+ ChartInternal.prototype.getAxisClipWidth = function (forHorizontal) {
+ var $$ = this,
+ left = Math.max(30, $$.margin.left),
+ right = Math.max(30, $$.margin.right); // width + axis line width + padding for left/right
+
+ return forHorizontal ? $$.width + 2 + left + right : $$.margin.left + 20;
+ };
+
+ ChartInternal.prototype.getAxisClipHeight = function (forHorizontal) {
+ // less than 20 is not enough to show the axis label 'outer' without legend
+ return (forHorizontal ? this.margin.bottom : this.margin.top + this.height) + 20;
+ };
+
+ ChartInternal.prototype.getXAxisClipWidth = function () {
+ var $$ = this;
+ return $$.getAxisClipWidth(!$$.config.axis_rotated);
+ };
+
+ ChartInternal.prototype.getXAxisClipHeight = function () {
+ var $$ = this;
+ return $$.getAxisClipHeight(!$$.config.axis_rotated);
+ };
+
+ ChartInternal.prototype.getYAxisClipWidth = function () {
+ var $$ = this;
+ return $$.getAxisClipWidth($$.config.axis_rotated) + ($$.config.axis_y_inner ? 20 : 0);
+ };
+
+ ChartInternal.prototype.getYAxisClipHeight = function () {
+ var $$ = this;
+ return $$.getAxisClipHeight($$.config.axis_rotated);
+ };
+
+ ChartInternal.prototype.generateColor = function () {
+ var $$ = this,
+ config = $$.config,
+ d3 = $$.d3,
+ colors = config.data_colors,
+ pattern = notEmpty(config.color_pattern) ? config.color_pattern : d3.schemeCategory10,
+ 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);
+ } // if specified, choose that color
+ else if (colors[id]) {
+ color = colors[id];
+ } // if not specified, choose from pattern
+ else {
+ if (ids.indexOf(id) < 0) {
+ ids.push(id);
+ }
+
+ color = pattern[ids.indexOf(id) % pattern.length];
+ colors[id] = color;
+ }
+
+ return callback instanceof Function ? callback(color, d) : color;
+ };
+ };
+
+ ChartInternal.prototype.generateLevelColor = function () {
+ var $$ = this,
+ config = $$.config,
+ colors = config.color_pattern,
+ threshold = config.color_threshold,
+ asValue = threshold.unit === 'value',
+ values = threshold.values && threshold.values.length ? threshold.values : [],
+ max = threshold.max || 100;
+ return notEmpty(config.color_threshold) ? function (value) {
+ var i,
+ v,
+ color = colors[colors.length - 1];
+
+ for (i = 0; i < values.length; i++) {
+ v = asValue ? value : value * 100 / max;
+
+ if (v < values[i]) {
+ color = colors[i];
+ break;