import { ChartInternal } from './core' import { isValue, isDefined, diffDomain, notEmpty } from './util' ChartInternal.prototype.getYDomainMin = function(targets) { var $$ = this, config = $$.config, ids = $$.mapToIds(targets), ys = $$.getValuesAsIdKeyed(targets), j, k, baseId, idsInGroup, id, hasNegativeValue if (config.data_groups.length > 0) { hasNegativeValue = $$.hasNegativeValueInTargets(targets) for (j = 0; j < config.data_groups.length; j++) { // Determine baseId idsInGroup = config.data_groups[j].filter(function(id) { return ids.indexOf(id) >= 0 }) if (idsInGroup.length === 0) { continue } baseId = idsInGroup[0] // Consider negative values if (hasNegativeValue && ys[baseId]) { ys[baseId].forEach(function(v, i) { ys[baseId][i] = v < 0 ? v : 0 }) } // Compute min for (k = 1; k < idsInGroup.length; k++) { id = idsInGroup[k] if (!ys[id]) { continue } ys[id].forEach(function(v, i) { if ( $$.axis.getId(id) === $$.axis.getId(baseId) && ys[baseId] && !(hasNegativeValue && +v > 0) ) { ys[baseId][i] += +v } }) } } } return $$.d3.min( Object.keys(ys).map(function(key) { return $$.d3.min(ys[key]) }) ) } ChartInternal.prototype.getYDomainMax = function(targets) { var $$ = this, config = $$.config, ids = $$.mapToIds(targets), ys = $$.getValuesAsIdKeyed(targets), j, k, baseId, idsInGroup, id, hasPositiveValue if (config.data_groups.length > 0) { hasPositiveValue = $$.hasPositiveValueInTargets(targets) for (j = 0; j < config.data_groups.length; j++) { // Determine baseId idsInGroup = config.data_groups[j].filter(function(id) { return ids.indexOf(id) >= 0 }) if (idsInGroup.length === 0) { continue } baseId = idsInGroup[0] // Consider positive values if (hasPositiveValue && ys[baseId]) { ys[baseId].forEach(function(v, i) { ys[baseId][i] = v > 0 ? v : 0 }) } // Compute max for (k = 1; k < idsInGroup.length; k++) { id = idsInGroup[k] if (!ys[id]) { continue } ys[id].forEach(function(v, i) { if ( $$.axis.getId(id) === $$.axis.getId(baseId) && ys[baseId] && !(hasPositiveValue && +v < 0) ) { ys[baseId][i] += +v } }) } } } return $$.d3.max( Object.keys(ys).map(function(key) { return $$.d3.max(ys[key]) }) ) } ChartInternal.prototype.getYDomain = function(targets, axisId, xDomain) { var $$ = this, config = $$.config if ($$.isAxisNormalized(axisId)) { return [0, 100] } var targetsByAxisId = targets.filter(function(t) { return $$.axis.getId(t.id) === axisId }), yTargets = xDomain ? $$.filterByXDomain(targetsByAxisId, xDomain) : targetsByAxisId, yMin = axisId === 'y2' ? config.axis_y2_min : config.axis_y_min, yMax = axisId === 'y2' ? config.axis_y2_max : config.axis_y_max, yDomainMin = $$.getYDomainMin(yTargets), yDomainMax = $$.getYDomainMax(yTargets), domain, domainLength, padding_top, padding_bottom, center = axisId === 'y2' ? config.axis_y2_center : config.axis_y_center, yDomainAbs, lengths, diff, ratio, isAllPositive, isAllNegative, isZeroBased = ($$.hasType('bar', yTargets) && config.bar_zerobased) || ($$.hasType('area', yTargets) && config.area_zerobased), 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() } if (isNaN(yDomainMin)) { // set minimum to zero when not number yDomainMin = 0 } if (isNaN(yDomainMax)) { // set maximum to have same value as yDomainMin yDomainMax = yDomainMin } if (yDomainMin === yDomainMax) { yDomainMin < 0 ? (yDomainMax = 0) : (yDomainMin = 0) } 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_top = padding_bottom = domainLength * 0.1 if (typeof center !== 'undefined') { yDomainAbs = Math.max(Math.abs(yDomainMin), Math.abs(yDomainMax)) yDomainMax = center + yDomainAbs yDomainMin = center - yDomainAbs } // add padding for data label if (showHorizontalDataLabel) { lengths = $$.getDataLabelLength(yDomainMin, yDomainMax, 'width') diff = diffDomain($$.y.range()) ratio = [lengths[0] / diff, lengths[1] / diff] padding_top += domainLength * (ratio[1] / (1 - ratio[0] - ratio[1])) padding_bottom += domainLength * (ratio[0] / (1 - ratio[0] - ratio[1])) } else if (showVerticalDataLabel) { lengths = $$.getDataLabelLength(yDomainMin, yDomainMax, 'height') const pixelsToAxisPadding = $$.getY( config[`axis_${axisId}_type`], // input domain as pixels [0, config.axis_rotated ? $$.width : $$.height], // output range as axis padding [0, domainLength] ) padding_top += pixelsToAxisPadding(lengths[1]) padding_bottom += pixelsToAxisPadding(lengths[0]) } if (axisId === 'y' && notEmpty(config.axis_y_padding)) { padding_top = $$.axis.getPadding( config.axis_y_padding, 'top', padding_top, domainLength ) padding_bottom = $$.axis.getPadding( config.axis_y_padding, 'bottom', padding_bottom, domainLength ) } if (axisId === 'y2' && notEmpty(config.axis_y2_padding)) { padding_top = $$.axis.getPadding( config.axis_y2_padding, 'top', padding_top, domainLength ) padding_bottom = $$.axis.getPadding( config.axis_y2_padding, 'bottom', padding_bottom, domainLength ) } // Bar/Area chart should be 0-based if all positive|negative if (isZeroBased) { if (isAllPositive) { padding_bottom = yDomainMin } if (isAllNegative) { padding_top = -yDomainMax } } domain = [yDomainMin - padding_bottom, yDomainMax + padding_top] return isInverted ? domain.reverse() : domain } ChartInternal.prototype.getXDomainMin = function(targets) { var $$ = this, config = $$.config return isDefined(config.axis_x_min) ? $$.isTimeSeries() ? this.parseDate(config.axis_x_min) : config.axis_x_min : $$.d3.min(targets, function(t) { return $$.d3.min(t.values, function(v) { return v.x }) }) } ChartInternal.prototype.getXDomainMax = function(targets) { var $$ = this, config = $$.config return isDefined(config.axis_x_max) ? $$.isTimeSeries() ? this.parseDate(config.axis_x_max) : config.axis_x_max : $$.d3.max(targets, function(t) { return $$.d3.max(t.values, function(v) { return v.x }) }) } ChartInternal.prototype.getXDomainPadding = function(domain) { var $$ = this, config = $$.config, diff = domain[1] - domain[0], maxDataCount, padding, paddingLeft, paddingRight if ($$.isCategorized()) { padding = 0 } else if ($$.hasType('bar')) { maxDataCount = $$.getMaxDataCount() padding = maxDataCount > 1 ? diff / (maxDataCount - 1) / 2 : 0.5 } else { padding = diff * 0.01 } if ( typeof config.axis_x_padding === 'object' && notEmpty(config.axis_x_padding) ) { paddingLeft = isValue(config.axis_x_padding.left) ? config.axis_x_padding.left : padding paddingRight = isValue(config.axis_x_padding.right) ? config.axis_x_padding.right : padding } else if (typeof config.axis_x_padding === 'number') { paddingLeft = paddingRight = config.axis_x_padding } else { paddingLeft = paddingRight = padding } return { left: paddingLeft, right: paddingRight } } ChartInternal.prototype.getXDomain = function(targets) { var $$ = this, xDomain = [$$.getXDomainMin(targets), $$.getXDomainMax(targets)], firstX = xDomain[0], lastX = xDomain[1], padding = $$.getXDomainPadding(xDomain), min: Date | number = 0, max: Date | number = 0 // show center of x domain if min and max are the same if (firstX - lastX === 0 && !$$.isCategorized()) { if ($$.isTimeSeries()) { firstX = new Date(firstX.getTime() * 0.5) lastX = new Date(lastX.getTime() * 1.5) } else { firstX = firstX === 0 ? 1 : firstX * 0.5 lastX = lastX === 0 ? -1 : lastX * 1.5 } } if (firstX || firstX === 0) { min = $$.isTimeSeries() ? new Date(firstX.getTime() - padding.left) : firstX - padding.left } if (lastX || lastX === 0) { max = $$.isTimeSeries() ? new Date(lastX.getTime() + padding.right) : lastX + padding.right } return [min, max] } ChartInternal.prototype.updateXDomain = function( targets, withUpdateXDomain, withUpdateOrgXDomain, withTrim, domain ) { var $$ = this, config = $$.config if (withUpdateOrgXDomain) { $$.x.domain(domain ? domain : $$.d3.extent($$.getXDomain(targets))) $$.orgXDomain = $$.x.domain() if (config.zoom_enabled) { $$.zoom.update() } $$.subX.domain($$.x.domain()) if ($$.brush) { $$.brush.updateScale($$.subX) } } if (withUpdateXDomain) { $$.x.domain( domain ? domain : !$$.brush || $$.brush.empty() ? $$.orgXDomain : $$.brush.selectionAsValue() ) } // Trim domain when too big by zoom mousemove event if (withTrim) { $$.x.domain($$.trimXDomain($$.x.orgDomain())) } return $$.x.domain() } ChartInternal.prototype.trimXDomain = function(domain) { var zoomDomain = this.getZoomDomain(), min = zoomDomain[0], max = zoomDomain[1] if (domain[0] <= min) { domain[1] = +domain[1] + (min - domain[0]) domain[0] = min } if (max <= domain[1]) { domain[0] = +domain[0] - (domain[1] - max) domain[1] = max } return domain }