UNPKG

dimple-js

Version:

Dimple is an object-oriented API allowing you to create flexible axis-based charts using [d3.js](http://d3js.org "d3.js").

256 lines (245 loc) 13.5 kB
// Copyright: 2015 AlignAlytics // License: "https://github.com/PMSI-AlignAlytics/dimple/blob/master/MIT-LICENSE.txt" // Source: /src/objects/axis/methods/_update.js this._update = function (refactor) { var distinctCats = [], ticks, step, remainder, origin, tickCount = this.ticks || 10, getOrderedCategories = function (self, axPos, oppPos) { var category = self.categoryFields[0], axisData = self._getAxisData(), sortBy = category, desc = false, isDate = true, currentValue = null, i, definitions; // Check whether this field is a date for (i = 0; i < axisData.length; i += 1) { currentValue = self._parseDate(axisData[i][category]); if (currentValue !== null && currentValue !== undefined && isNaN(currentValue)) { isDate = false; break; } } if (!isDate) { // Find the first series which connects this axis to another self.chart.series.forEach(function (s) { if (s[axPos] === self && s[oppPos]._hasMeasure()) { sortBy = s[oppPos].measure; desc = true; } }, this); } definitions = self._orderRules.concat({ ordering : sortBy, desc : desc }); return dimple._getOrderedList(axisData, category, definitions); }; // If the axis is a percentage type axis the bounds must be between -1 and 1. Sometimes // binary rounding means it can fall outside that bound so tidy up here this._min = (this.showPercent && this._min < -1 ? -1 : this._min); this._max = (this.showPercent && this._max > 1 ? 1 : this._max); // Override or round the min or max this._min = (this.overrideMin !== null ? this.overrideMin : this._min); this._max = (this.overrideMax !== null ? this.overrideMax : this._max); // If this is an x axis if (this.position === "x" && (this._scale === null || refactor)) { if (this._hasTimeField()) { this._scale = d3.time.scale() // Previously used rangeRound which causes problems with the area chart (Issue #79) .range([this.chart._xPixels(), this.chart._xPixels() + this.chart._widthPixels()]) .domain([this._min, this._max]) .clamp(this.clamp); } else if (this.useLog) { this._scale = d3.scale.log() .range([this.chart._xPixels(), this.chart._xPixels() + this.chart._widthPixels()]) .domain([ (this._min === 0 ? Math.pow(this.logBase, -1) : this._min), (this._max === 0 ? -1 * Math.pow(this.logBase, -1) : this._max) ]) .clamp(this.clamp) .base(this.logBase) .nice(); } else if (this.measure === null || this.measure === undefined) { distinctCats = getOrderedCategories(this, "x", "y"); // If there are any slaves process accordingly if (this._slaves !== null && this._slaves !== undefined) { this._slaves.forEach(function (slave) { distinctCats = distinctCats.concat(getOrderedCategories(slave, "x", "y")); }, this); } this._scale = d3.scale.ordinal() .rangePoints([this.chart._xPixels(), this.chart._xPixels() + this.chart._widthPixels()]) .domain(distinctCats.concat([""])); } else { this._scale = d3.scale.linear() .range([this.chart._xPixels(), this.chart._xPixels() + this.chart._widthPixels()]) .domain([this._min, this._max]) .clamp(this.clamp) .nice(); } // If it's visible, orient it at the top or bottom if it's first or second respectively if (!this.hidden) { switch (this.chart._axisIndex(this, "x")) { case 0: this._draw = d3.svg.axis() .orient("bottom") .scale(this._scale); if (this.ticks) { this._draw.ticks(tickCount); } break; case 1: this._draw = d3.svg.axis() .orient("top") .scale(this._scale); if (this.ticks) { this._draw.ticks(tickCount); } break; default: break; } } } else if (this.position === "y" && (this._scale === null || refactor)) { if (this._hasTimeField()) { this._scale = d3.time.scale() // Previously used rangeRound which causes problems with the area chart (Issue #79) .range([this.chart._yPixels() + this.chart._heightPixels(), this.chart._yPixels()]) .domain([this._min, this._max]) .clamp(this.clamp); } else if (this.useLog) { this._scale = d3.scale.log() .range([this.chart._yPixels() + this.chart._heightPixels(), this.chart._yPixels()]) .domain([ (this._min === 0 ? Math.pow(this.logBase, -1) : this._min), (this._max === 0 ? -1 * Math.pow(this.logBase, -1) : this._max) ]) .clamp(this.clamp) .base(this.logBase) .nice(); } else if (this.measure === null || this.measure === undefined) { distinctCats = getOrderedCategories(this, "y", "x"); // If there are any slaves process accordingly if (this._slaves !== null && this._slaves !== undefined) { this._slaves.forEach(function (slave) { distinctCats = distinctCats.concat(getOrderedCategories(slave, "y", "x")); }, this); } this._scale = d3.scale.ordinal() .rangePoints([this.chart._yPixels() + this.chart._heightPixels(), this.chart._yPixels()]) .domain(distinctCats.concat([""])); } else { this._scale = d3.scale.linear() .range([this.chart._yPixels() + this.chart._heightPixels(), this.chart._yPixels()]) .domain([this._min, this._max]) .clamp(this.clamp) .nice(); } // if it's visible, orient it at the left or right if it's first or second respectively if (!this.hidden) { switch (this.chart._axisIndex(this, "y")) { case 0: this._draw = d3.svg.axis() .orient("left") .scale(this._scale); if (this.ticks) { this._draw.ticks(tickCount); } break; case 1: this._draw = d3.svg.axis() .orient("right") .scale(this._scale); if (this.ticks) { this._draw.ticks(tickCount); } break; default: break; } } } else if (this.position.length > 0 && this.position[0] === "z" && this._scale === null) { if (this.useLog) { this._scale = d3.scale.log() .range([this.chart._heightPixels() / 300, this.chart._heightPixels() / 10]) .domain([ (this._min === 0 ? Math.pow(this.logBase, -1) : this._min), (this._max === 0 ? -1 * Math.pow(this.logBase, -1) : this._max) ]) .clamp(this.clamp) .base(this.logBase); } else { this._scale = d3.scale.linear() .range([1, this.chart._heightPixels() / 10]) .domain([this._min, this._max]) .clamp(this.clamp); } } else if (this.position.length > 0 && this.position[0] === "p" && this._scale === null) { if (this.useLog) { this._scale = d3.scale.log() .range([0, 360]) .domain([ (this._min === 0 ? Math.pow(this.logBase, -1) : this._min), (this._max === 0 ? -1 * Math.pow(this.logBase, -1) : this._max) ]) .clamp(this.clamp) .base(this.logBase); } else { this._scale = d3.scale.linear() .range([0, 360]) .domain([this._min, this._max]) .clamp(this.clamp); } } else if (this.position.length > 0 && this.position[0] === "c" && this._scale === null) { this._scale = d3.scale.linear() .range([0, (this.colors === null || this.colors.length === 1 ? 1 : this.colors.length - 1)]) .domain([this._min, this._max]) .clamp(this.clamp); } // Apply this scale to all slaves as well if (this._slaves !== null && this._slaves !== undefined && this._slaves.length > 0) { this._slaves.forEach(function (slave) { slave._scale = this._scale; }, this); } // Check that the axis ends on a labelled tick if ((refactor === null || refactor === undefined || refactor === false) && !this._hasTimeField() && this._scale !== null && this._scale.ticks !== null && this._scale.ticks !== undefined && this._scale.ticks(tickCount).length > 0 && (this.position === "x" || this.position === "y")) { // Get the ticks determined based on the specified split ticks = this._scale.ticks(tickCount); // Get the step between ticks step = ticks[1] - ticks[0]; // Get the remainder remainder = ((this._max - this._min) % step).toFixed(0); // Store the tick step if needed to calculate _getFormat. this._tick_step = step; // If the remainder is not zero if (remainder !== 0) { // Set the bounds this._max = Math.ceil(this._max / step) * step; this._min = Math.floor(this._min / step) * step; // Recursively call the method to recalculate the scale. This shouldn't enter this block again. this._update(true); } } // Populate the origin. Previously this incorrectly looked up 0 on the axis which only works // for measure axes leading to Issue #19. This fix uses the first category value in cases where // one is required. if (distinctCats !== null && distinctCats !== undefined && distinctCats.length > 0) { origin = this._scale.copy()(distinctCats[0]); } else if (this._min > 0) { origin = this._scale.copy()(this._min); } else if (this._max < 0) { origin = this._scale.copy()(this._max); } else { origin = this._scale.copy()(0); } if (this._origin !== origin) { this._previousOrigin = (this._origin === null ? origin : this._origin); this._origin = origin; } // Return axis for chaining return this; };