UNPKG

yuidoc-asp

Version:

YUIDoc, YUI's JavaScript Documentation engine tweaked to work with VB/VBScript comments.

1,504 lines (1,457 loc) 69.2 kB
/** * The CartesianChart class creates a chart with horizontal and vertical axes. * * @module charts * @class CartesianChart * @extends ChartBase * @constructor */ Y.CartesianChart = Y.Base.create("cartesianChart", Y.Widget, [Y.ChartBase], { /** * @method renderUI * @private */ renderUI: function() { var bb = this.get("boundingBox"), cb = this.get("contentBox"), tt = this.get("tooltip"), overlay, overlayClass = _getClassName("overlay"); //move the position = absolute logic to a class file bb.setStyle("position", "absolute"); cb.setStyle("position", "absolute"); this._addAxes(); this._addGridlines(); this._addSeries(); if(tt && tt.show) { this._addTooltip(); } //If there is a style definition. Force them to set. this.get("styles"); if(this.get("interactionType") == "planar") { overlay = DOCUMENT.createElement("div"); this.get("contentBox").appendChild(overlay); this._overlay = Y.one(overlay); this._overlay.setStyle("position", "absolute"); this._overlay.setStyle("background", "#fff"); this._overlay.setStyle("opacity", 0); this._overlay.addClass(overlayClass); this._overlay.setStyle("zIndex", 4); } this._setAriaElements(bb, cb); this._redraw(); }, /** * When `interactionType` is set to `planar`, listens for mouse move events and fires `planarEvent:mouseover` or `planarEvent:mouseout` depending on the position of the mouse in relation to * data points on the `Chart`. * * @method _planarEventDispatcher * @param {Object} e Event object. * @private */ _planarEventDispatcher: function(e) { var graph = this.get("graph"), bb = this.get("boundingBox"), cb = graph.get("contentBox"), isTouch = e && e.hasOwnProperty("changedTouches"), pageX = isTouch ? e.changedTouches[0].pageX : e.pageX, pageY = isTouch ? e.changedTouches[0].pageY : e.pageY, posX = pageX - bb.getX(), posY = pageY - bb.getY(), offset = { x: pageX - cb.getX(), y: pageY - cb.getY() }, sc = graph.get("seriesCollection"), series, i = 0, index, oldIndex = this._selectedIndex, item, items = [], categoryItems = [], valueItems = [], direction = this.get("direction"), hasMarkers, catAxis, valAxis, coord, //data columns and area data could be created on a graph level markerPlane, len, coords; e.halt(true); if(direction == "horizontal") { catAxis = "x"; valAxis = "y"; } else { valAxis = "x"; catAxis = "y"; } coord = offset[catAxis]; if(sc) { len = sc.length; while(i < len && !markerPlane) { if(sc[i]) { markerPlane = sc[i].get(catAxis + "MarkerPlane"); } i++; } } if(markerPlane) { len = markerPlane.length; for(i = 0; i < len; ++i) { if(coord <= markerPlane[i].end && coord >= markerPlane[i].start) { index = i; break; } } len = sc.length; for(i = 0; i < len; ++i) { series = sc[i]; coords = series.get(valAxis + "coords"); hasMarkers = series.get("markers"); if(hasMarkers && !isNaN(oldIndex) && oldIndex > -1) { series.updateMarkerState("mouseout", oldIndex); } if(coords && coords[index] > -1) { if(hasMarkers && !isNaN(index) && index > -1) { series.updateMarkerState("mouseover", index); } item = this.getSeriesItems(series, index); categoryItems.push(item.category); valueItems.push(item.value); items.push(series); } } this._selectedIndex = index; /** * Broadcasts when `interactionType` is set to `planar` and a series' marker plane has received a mouseover event. * * * @event planarEvent:mouseover * @preventable false * @param {EventFacade} e Event facade with the following additional * properties: * <dl> * <dt>categoryItem</dt><dd>An array of hashes, each containing information about the category `Axis` of each marker whose plane has been intersected.</dd> * <dt>valueItem</dt><dd>An array of hashes, each containing information about the value `Axis` of each marker whose plane has been intersected.</dd> * <dt>x</dt><dd>The x-coordinate of the mouse in relation to the Chart.</dd> * <dt>y</dt><dd>The y-coordinate of the mouse in relation to the Chart.</dd> * <dt>pageX</dt><dd>The x location of the event on the page (including scroll)</dd> * <dt>pageY</dt><dd>The y location of the event on the page (including scroll)</dd> * <dt>items</dt><dd>An array including all the series which contain a marker whose plane has been intersected.</dd> * <dt>index</dt><dd>Index of the markers in their respective series.</dd> * <dt>originEvent</dt><dd>Underlying dom event.</dd> * </dl> */ /** * Broadcasts when `interactionType` is set to `planar` and a series' marker plane has received a mouseout event. * * @event planarEvent:mouseout * @preventable false * @param {EventFacade} e */ if(index > -1) { this.fire("planarEvent:mouseover", { categoryItem:categoryItems, valueItem:valueItems, x:posX, y:posY, pageX:pageX, pageY:pageY, items:items, index:index, originEvent:e }); } else { this.fire("planarEvent:mouseout"); } } }, /** * Indicates the default series type for the chart. * * @property _type * @type {String} * @private */ _type: "combo", /** * Queue of axes instances that will be updated. This method is used internally to determine when all axes have been updated. * * @property _itemRenderQueue * @type Array * @private */ _itemRenderQueue: null, /** * Adds an `Axis` instance to the `_itemRenderQueue`. * * @method _addToAxesRenderQueue * @param {Axis} axis An `Axis` instance. * @private */ _addToAxesRenderQueue: function(axis) { if(!this._itemRenderQueue) { this._itemRenderQueue = []; } if(Y.Array.indexOf(this._itemRenderQueue, axis) < 0) { this._itemRenderQueue.push(axis); } }, /** * Adds axis instance to the appropriate array based on position * * @method _addToAxesCollection * @param {String} position The position of the axis * @param {Axis} axis The `Axis` instance */ _addToAxesCollection: function(position, axis) { var axesCollection = this.get(position + "AxesCollection"); if(!axesCollection) { axesCollection = []; this.set(position + "AxesCollection", axesCollection); } axesCollection.push(axis); }, /** * Returns the default value for the `seriesCollection` attribute. * * @method _getDefaultSeriesCollection * @param {Array} val Array containing either `CartesianSeries` instances or objects containing data to construct series instances. * @return Array * @private */ _getDefaultSeriesCollection: function() { return this._parseSeriesCollection(); }, /** * Parses and returns a series collection from an object and default properties. * * @method _parseSeriesCollection * @param {Object} val Object contain properties for series being set. * @return Object * @private */ _parseSeriesCollection: function(val) { var dir = this.get("direction"), sc = val || [], catAxis, valAxis, tempKeys = [], series, seriesKeys = this.get("seriesKeys").concat(), i, index, l, type = this.get("type"), key, catKey, seriesKey, graph, categoryKey = this.get("categoryKey"), showMarkers = this.get("showMarkers"), showAreaFill = this.get("showAreaFill"), showLines = this.get("showLines"); if(dir == "vertical") { catAxis = "yAxis"; catKey = "yKey"; valAxis = "xAxis"; seriesKey = "xKey"; } else { catAxis = "xAxis"; catKey = "xKey"; valAxis = "yAxis"; seriesKey = "yKey"; } l = sc.length; for(i = 0; i < l; ++i) { key = this._getBaseAttribute(sc[i], seriesKey); if(key) { index = Y.Array.indexOf(seriesKeys, key); if(index > -1) { seriesKeys.splice(index, 1); } tempKeys.push(key); } } if(seriesKeys.length > 0) { tempKeys = tempKeys.concat(seriesKeys); } l = tempKeys.length; for(i = 0; i < l; ++i) { series = sc[i] || {type:type}; if(series instanceof Y.CartesianSeries) { this._parseSeriesAxes(series); continue; } series[catKey] = series[catKey] || categoryKey; series[seriesKey] = series[seriesKey] || seriesKeys.shift(); series[catAxis] = this._getCategoryAxis(); series[valAxis] = this._getSeriesAxis(series[seriesKey]); series.type = series.type || type; if((series.type == "combo" || series.type == "stackedcombo" || series.type == "combospline" || series.type == "stackedcombospline")) { if(showAreaFill !== null) { series.showAreaFill = (series.showAreaFill !== null && series.showAreaFill !== undefined) ? series.showAreaFill : showAreaFill; } if(showMarkers !== null) { series.showMarkers = (series.showMarkers !== null && series.showMarkers !== undefined) ? series.showMarkers : showMarkers; } if(showLines !== null) { series.showLines = (series.showLines !== null && series.showLines !== undefined) ? series.showLines : showLines; } } sc[i] = series; } if(val) { graph = this.get("graph"); graph.set("seriesCollection", sc); sc = graph.get("seriesCollection"); } return sc; }, /** * Parse and sets the axes for a series instance. * * @method _parseSeriesAxes * @param {CartesianSeries} series A `CartesianSeries` instance. * @private */ _parseSeriesAxes: function(series) { var axes = this.get("axes"), xAxis = series.get("xAxis"), yAxis = series.get("yAxis"), YAxis = Y.Axis, axis; if(xAxis && !(xAxis instanceof YAxis) && Y_Lang.isString(xAxis) && axes.hasOwnProperty(xAxis)) { axis = axes[xAxis]; if(axis instanceof YAxis) { series.set("xAxis", axis); } } if(yAxis && !(yAxis instanceof YAxis) && Y_Lang.isString(yAxis) && axes.hasOwnProperty(yAxis)) { axis = axes[yAxis]; if(axis instanceof YAxis) { series.set("yAxis", axis); } } }, /** * Returns the category axis instance for the chart. * * @method _getCategoryAxis * @return Axis * @private */ _getCategoryAxis: function() { var axis, axes = this.get("axes"), categoryAxisName = this.get("categoryAxisName") || this.get("categoryKey"); axis = axes[categoryAxisName]; return axis; }, /** * Returns the value axis for a series. * * @method _getSeriesAxis * @param {String} key The key value used to determine the axis instance. * @return Axis * @private */ _getSeriesAxis:function(key, axisName) { var axes = this.get("axes"), i, keys, axis; if(axes) { if(axisName && axes.hasOwnProperty(axisName)) { axis = axes[axisName]; } else { for(i in axes) { if(axes.hasOwnProperty(i)) { keys = axes[i].get("keys"); if(keys && keys.hasOwnProperty(key)) { axis = axes[i]; break; } } } } } return axis; }, /** * Gets an attribute from an object, using a getter for Base objects and a property for object * literals. Used for determining attributes from series/axis references which can be an actual class instance * or a hash of properties that will be used to create a class instance. * * @method _getBaseAttribute * @param {Object} item Object or instance in which the attribute resides. * @param {String} key Attribute whose value will be returned. * @return Object * @private */ _getBaseAttribute: function(item, key) { if(item instanceof Y.Base) { return item.get(key); } if(item.hasOwnProperty(key)) { return item[key]; } return null; }, /** * Sets an attribute on an object, using a setter of Base objects and a property for object * literals. Used for setting attributes on a Base class, either directly or to be stored in an object literal * for use at instantiation. * * @method _setBaseAttribute * @param {Object} item Object or instance in which the attribute resides. * @param {String} key Attribute whose value will be assigned. * @param {Object} value Value to be assigned to the attribute. * @private */ _setBaseAttribute: function(item, key, value) { if(item instanceof Y.Base) { item.set(key, value); } else { item[key] = value; } }, /** * Creates `Axis` instances. * * @method _setAxes * @param {Object} val Object containing `Axis` instances or objects in which to construct `Axis` instances. * @return Object * @private */ _setAxes: function(val) { var hash = this._parseAxes(val), axes = {}, axesAttrs = { edgeOffset: "edgeOffset", position: "position", overlapGraph:"overlapGraph", labelFunction:"labelFunction", labelFunctionScope:"labelFunctionScope", labelFormat:"labelFormat", maximum:"maximum", minimum:"minimum", roundingMethod:"roundingMethod", alwaysShowZero:"alwaysShowZero", title:"title", width:"width", height:"height" }, dp = this.get("dataProvider"), ai, i, pos, axis, axisPosition, dh, axisClass, config, axesCollection; for(i in hash) { if(hash.hasOwnProperty(i)) { dh = hash[i]; if(dh instanceof Y.Axis) { axis = dh; } else { axis = null; config = {}; config.dataProvider = dh.dataProvider || dp; config.keys = dh.keys; if(dh.hasOwnProperty("roundingUnit")) { config.roundingUnit = dh.roundingUnit; } pos = dh.position; if(dh.styles) { config.styles = dh.styles; } config.position = dh.position; for(ai in axesAttrs) { if(axesAttrs.hasOwnProperty(ai) && dh.hasOwnProperty(ai)) { config[ai] = dh[ai]; } } //only check for existing axis if we constructed the default axes already if(val) { axis = this.getAxisByKey(i); } if(axis && axis instanceof Y.Axis) { axisPosition = axis.get("position"); if(pos != axisPosition) { if(axisPosition != "none") { axesCollection = this.get(axisPosition + "AxesCollection"); axesCollection.splice(Y.Array.indexOf(axesCollection, axis), 1); } if(pos != "none") { this._addToAxesCollection(pos, axis); } } axis.setAttrs(config); } else { axisClass = this._getAxisClass(dh.type); axis = new axisClass(config); axis.after("axisRendered", Y.bind(this._itemRendered, this)); } } if(axis) { axesCollection = this.get(pos + "AxesCollection"); if(axesCollection && Y.Array.indexOf(axesCollection, axis) > 0) { axis.set("overlapGraph", false); } axes[i] = axis; } } } return axes; }, /** * Adds axes to the chart. * * @method _addAxes * @private */ _addAxes: function() { var axes = this.get("axes"), i, axis, pos, w = this.get("width"), h = this.get("height"), node = Y.Node.one(this._parentNode); if(!this._axesCollection) { this._axesCollection = []; } for(i in axes) { if(axes.hasOwnProperty(i)) { axis = axes[i]; if(axis instanceof Y.Axis) { if(!w) { this.set("width", node.get("offsetWidth")); w = this.get("width"); } if(!h) { this.set("height", node.get("offsetHeight")); h = this.get("height"); } this._addToAxesRenderQueue(axis); pos = axis.get("position"); if(!this.get(pos + "AxesCollection")) { this.set(pos + "AxesCollection", [axis]); } else { this.get(pos + "AxesCollection").push(axis); } this._axesCollection.push(axis); if(axis.get("keys").hasOwnProperty(this.get("categoryKey"))) { this.set("categoryAxis", axis); } axis.render(this.get("contentBox")); } } } }, /** * Renders the Graph. * * @method _addSeries * @private */ _addSeries: function() { var graph = this.get("graph"), sc = this.get("seriesCollection"); graph.render(this.get("contentBox")); }, /** * Adds gridlines to the chart. * * @method _addGridlines * @private */ _addGridlines: function() { var graph = this.get("graph"), hgl = this.get("horizontalGridlines"), vgl = this.get("verticalGridlines"), direction = this.get("direction"), leftAxesCollection = this.get("leftAxesCollection"), rightAxesCollection = this.get("rightAxesCollection"), bottomAxesCollection = this.get("bottomAxesCollection"), topAxesCollection = this.get("topAxesCollection"), seriesAxesCollection, catAxis = this.get("categoryAxis"), hAxis, vAxis; if(this._axesCollection) { seriesAxesCollection = this._axesCollection.concat(); seriesAxesCollection.splice(Y.Array.indexOf(seriesAxesCollection, catAxis), 1); } if(hgl) { if(leftAxesCollection && leftAxesCollection[0]) { hAxis = leftAxesCollection[0]; } else if(rightAxesCollection && rightAxesCollection[0]) { hAxis = rightAxesCollection[0]; } else { hAxis = direction == "horizontal" ? catAxis : seriesAxesCollection[0]; } if(!this._getBaseAttribute(hgl, "axis") && hAxis) { this._setBaseAttribute(hgl, "axis", hAxis); } if(this._getBaseAttribute(hgl, "axis")) { graph.set("horizontalGridlines", hgl); } } if(vgl) { if(bottomAxesCollection && bottomAxesCollection[0]) { vAxis = bottomAxesCollection[0]; } else if (topAxesCollection && topAxesCollection[0]) { vAxis = topAxesCollection[0]; } else { vAxis = direction == "vertical" ? catAxis : seriesAxesCollection[0]; } if(!this._getBaseAttribute(vgl, "axis") && vAxis) { this._setBaseAttribute(vgl, "axis", vAxis); } if(this._getBaseAttribute(vgl, "axis")) { graph.set("verticalGridlines", vgl); } } }, /** * Returns all the keys contained in a `dataProvider`. * * @method _getAllKeys * @param {Array} dp Collection of objects to be parsed. * @return Object */ _getAllKeys: function(dp) { var i = 0, len = dp.length, item, key, keys = {}; for(; i < len; ++i) { item = dp[i]; for(key in item) { if(item.hasOwnProperty(key)) { keys[key] = true; } } } return keys; }, /** * Default Function for the axes attribute. * * @method _getDefaultAxes * @return Object * @private */ _getDefaultAxes: function() { return this._parseAxes(); }, /** * Generates and returns a key-indexed object containing `Axis` instances or objects used to create `Axis` instances. * * @method _parseAxes * @param {Object} axes Object containing `Axis` instances or `Axis` attributes. * @return Object * @private */ _parseAxes: function(axes) { var catKey = this.get("categoryKey"), axis, attr, keys, newAxes = {}, claimedKeys = [], categoryAxisName = this.get("categoryAxisName") || this.get("categoryKey"), valueAxisName = this.get("valueAxisName"), seriesKeys = this.get("seriesKeys") || [], i, l, ii, ll, cIndex, dv, dp = this.get("dataProvider"), direction = this.get("direction"), seriesPosition, categoryPosition, valueAxes = [], seriesAxis = this.get("stacked") ? "stacked" : "numeric"; if(direction == "vertical") { seriesPosition = "bottom"; categoryPosition = "left"; } else { seriesPosition = "left"; categoryPosition = "bottom"; } if(axes) { for(i in axes) { if(axes.hasOwnProperty(i)) { axis = axes[i]; keys = this._getBaseAttribute(axis, "keys"); attr = this._getBaseAttribute(axis, "type"); if(attr == "time" || attr == "category") { categoryAxisName = i; this.set("categoryAxisName", i); if(Y_Lang.isArray(keys) && keys.length > 0) { catKey = keys[0]; this.set("categoryKey", catKey); } newAxes[i] = axis; } else if(i == categoryAxisName) { newAxes[i] = axis; } else { newAxes[i] = axis; if(i != valueAxisName && keys && Y_Lang.isArray(keys)) { ll = keys.length; for(ii = 0; ii < ll; ++ii) { claimedKeys.push(keys[ii]); } valueAxes.push(newAxes[i]); } if(!(this._getBaseAttribute(newAxes[i], "type"))) { this._setBaseAttribute(newAxes[i], "type", seriesAxis); } if(!(this._getBaseAttribute(newAxes[i], "position"))) { this._setBaseAttribute(newAxes[i], "position", this._getDefaultAxisPosition(newAxes[i], valueAxes, seriesPosition)); } } } } } if(seriesKeys.length < 1) { dv = this._getAllKeys(dp); for(i in dv) { if(dv.hasOwnProperty(i) && i != catKey && Y.Array.indexOf(claimedKeys, i) == -1) { seriesKeys.push(i); } } } cIndex = Y.Array.indexOf(seriesKeys, catKey); if(cIndex > -1) { seriesKeys.splice(cIndex, 1); } l = claimedKeys.length; for(i = 0; i < l; ++i) { cIndex = Y.Array.indexOf(seriesKeys, claimedKeys[i]); if(cIndex > -1) { seriesKeys.splice(cIndex, 1); } } if(!newAxes.hasOwnProperty(categoryAxisName)) { newAxes[categoryAxisName] = {}; } if(!(this._getBaseAttribute(newAxes[categoryAxisName], "keys"))) { this._setBaseAttribute(newAxes[categoryAxisName], "keys", [catKey]); } if(!(this._getBaseAttribute(newAxes[categoryAxisName], "position"))) { this._setBaseAttribute(newAxes[categoryAxisName], "position", categoryPosition); } if(!(this._getBaseAttribute(newAxes[categoryAxisName], "type"))) { this._setBaseAttribute(newAxes[categoryAxisName], "type", this.get("categoryType")); } if(!newAxes.hasOwnProperty(valueAxisName) && seriesKeys && seriesKeys.length > 0) { newAxes[valueAxisName] = {keys:seriesKeys}; valueAxes.push(newAxes[valueAxisName]); } if(claimedKeys.length > 0) { if(seriesKeys.length > 0) { seriesKeys = claimedKeys.concat(seriesKeys); } else { seriesKeys = claimedKeys; } } if(newAxes.hasOwnProperty(valueAxisName)) { if(!(this._getBaseAttribute(newAxes[valueAxisName], "position"))) { this._setBaseAttribute(newAxes[valueAxisName], "position", this._getDefaultAxisPosition(newAxes[valueAxisName], valueAxes, seriesPosition)); } if(!(this._getBaseAttribute(newAxes[valueAxisName], "type"))) { this._setBaseAttribute(newAxes[valueAxisName], "type", seriesAxis); } if(!(this._getBaseAttribute(newAxes[valueAxisName], "keys"))) { this._setBaseAttribute(newAxes[valueAxisName], "keys", seriesKeys); } } this.set("seriesKeys", seriesKeys); return newAxes; }, /** * Determines the position of an axis when one is not specified. * * @method _getDefaultAxisPosition * @param {Axis} axis `Axis` instance. * @param {Array} valueAxes Array of `Axis` instances. * @param {String} position Default position depending on the direction of the chart and type of axis. * @return String * @private */ _getDefaultAxisPosition: function(axis, valueAxes, position) { var direction = this.get("direction"), i = Y.Array.indexOf(valueAxes, axis); if(valueAxes[i - 1] && valueAxes[i - 1].position) { if(direction == "horizontal") { if(valueAxes[i - 1].position == "left") { position = "right"; } else if(valueAxes[i - 1].position == "right") { position = "left"; } } else { if (valueAxes[i -1].position == "bottom") { position = "top"; } else { position = "bottom"; } } } return position; }, /** * Returns an object literal containing a categoryItem and a valueItem for a given series index. Below is the structure of each: * * @method getSeriesItems * @param {CartesianSeries} series Reference to a series. * @param {Number} index Index of the specified item within a series. * @return Object An object literal containing the following: * * <dl> * <dt>categoryItem</dt><dd>Object containing the following data related to the category axis of the series. * <dl> * <dt>axis</dt><dd>Reference to the category axis of the series.</dd> * <dt>key</dt><dd>Category key for the series.</dd> * <dt>value</dt><dd>Value on the axis corresponding to the series index.</dd> * </dl> * </dd> * <dt>valueItem</dt><dd>Object containing the following data related to the category axis of the series. * <dl> * <dt>axis</dt><dd>Reference to the value axis of the series.</dd> * <dt>key</dt><dd>Value key for the series.</dd> * <dt>value</dt><dd>Value on the axis corresponding to the series index.</dd> * </dl> * </dd> * </dl> */ getSeriesItems: function(series, index) { var xAxis = series.get("xAxis"), yAxis = series.get("yAxis"), xKey = series.get("xKey"), yKey = series.get("yKey"), categoryItem, valueItem; if(this.get("direction") == "vertical") { categoryItem = { axis:yAxis, key:yKey, value:yAxis.getKeyValueAt(yKey, index) }; valueItem = { axis:xAxis, key:xKey, value: xAxis.getKeyValueAt(xKey, index) }; } else { valueItem = { axis:yAxis, key:yKey, value:yAxis.getKeyValueAt(yKey, index) }; categoryItem = { axis:xAxis, key:xKey, value: xAxis.getKeyValueAt(xKey, index) }; } categoryItem.displayName = series.get("categoryDisplayName"); valueItem.displayName = series.get("valueDisplayName"); categoryItem.value = categoryItem.axis.getKeyValueAt(categoryItem.key, index); valueItem.value = valueItem.axis.getKeyValueAt(valueItem.key, index); return {category:categoryItem, value:valueItem}; }, /** * Handler for sizeChanged event. * * @method _sizeChanged * @param {Object} e Event object. * @private */ _sizeChanged: function(e) { if(this._axesCollection) { var ac = this._axesCollection, i = 0, l = ac.length; for(; i < l; ++i) { this._addToAxesRenderQueue(ac[i]); } this._redraw(); } }, /** * Returns the maximum distance in pixels that the extends outside the top bounds of all vertical axes. * * @method _getTopOverflow * @param {Array} set1 Collection of axes to check. * @param {Array} set2 Seconf collection of axes to check. * @param {Number} width Width of the axes * @return Number * @private */ _getTopOverflow: function(set1, set2, height) { var i = 0, len, overflow = 0, axis; if(set1) { len = set1.length; for(; i < len; ++i) { axis = set1[i]; overflow = Math.max(overflow, Math.abs(axis.getMaxLabelBounds().top) - (axis.getEdgeOffset(axis.get("styles").majorTicks.count, height) * 0.5)); } } if(set2) { i = 0; len = set2.length; for(; i < len; ++i) { axis = set2[i]; overflow = Math.max(overflow, Math.abs(axis.getMaxLabelBounds().top) - (axis.getEdgeOffset(axis.get("styles").majorTicks.count, height) * 0.5)); } } return overflow; }, /** * Returns the maximum distance in pixels that the extends outside the right bounds of all horizontal axes. * * @method _getRightOverflow * @param {Array} set1 Collection of axes to check. * @param {Array} set2 Seconf collection of axes to check. * @param {Number} width Width of the axes * @return Number * @private */ _getRightOverflow: function(set1, set2, width) { var i = 0, len, overflow = 0, axis; if(set1) { len = set1.length; for(; i < len; ++i) { axis = set1[i]; overflow = Math.max(overflow, axis.getMaxLabelBounds().right - (axis.getEdgeOffset(axis.get("styles").majorTicks.count, width) * 0.5)); } } if(set2) { i = 0; len = set2.length; for(; i < len; ++i) { axis = set2[i]; overflow = Math.max(overflow, axis.getMaxLabelBounds().right - (axis.getEdgeOffset(axis.get("styles").majorTicks.count, width) * 0.5)); } } return overflow; }, /** * Returns the maximum distance in pixels that the extends outside the left bounds of all horizontal axes. * * @method _getLeftOverflow * @param {Array} set1 Collection of axes to check. * @param {Array} set2 Seconf collection of axes to check. * @param {Number} width Width of the axes * @return Number * @private */ _getLeftOverflow: function(set1, set2, width) { var i = 0, len, overflow = 0, axis; if(set1) { len = set1.length; for(; i < len; ++i) { axis = set1[i]; overflow = Math.max(overflow, Math.abs(axis.getMinLabelBounds().left) - (axis.getEdgeOffset(axis.get("styles").majorTicks.count, width) * 0.5)); } } if(set2) { i = 0; len = set2.length; for(; i < len; ++i) { axis = set2[i]; overflow = Math.max(overflow, Math.abs(axis.getMinLabelBounds().left) - (axis.getEdgeOffset(axis.get("styles").majorTicks.count, width) * 0.5)); } } return overflow; }, /** * Returns the maximum distance in pixels that the extends outside the bottom bounds of all vertical axes. * * @method _getBottomOverflow * @param {Array} set1 Collection of axes to check. * @param {Array} set2 Seconf collection of axes to check. * @param {Number} height Height of the axes * @return Number * @private */ _getBottomOverflow: function(set1, set2, height) { var i = 0, len, overflow = 0, axis; if(set1) { len = set1.length; for(; i < len; ++i) { axis = set1[i]; overflow = Math.max(overflow, axis.getMinLabelBounds().bottom - (axis.getEdgeOffset(axis.get("styles").majorTicks.count, height) * 0.5)); } } if(set2) { i = 0; len = set2.length; for(; i < len; ++i) { axis = set2[i]; overflow = Math.max(overflow, axis.getMinLabelBounds().bottom - (axis.getEdgeOffset(axis.get("styles").majorTicks.count, height) * 0.5)); } } return overflow; }, /** * Redraws and position all the components of the chart instance. * * @method _redraw * @private */ _redraw: function() { if(this._drawing) { this._callLater = true; return; } this._drawing = true; this._callLater = false; var w = this.get("width"), h = this.get("height"), leftPaneWidth = 0, rightPaneWidth = 0, topPaneHeight = 0, bottomPaneHeight = 0, leftAxesCollection = this.get("leftAxesCollection"), rightAxesCollection = this.get("rightAxesCollection"), topAxesCollection = this.get("topAxesCollection"), bottomAxesCollection = this.get("bottomAxesCollection"), i = 0, l, axis, graphOverflow = "visible", graph = this.get("graph"), topOverflow, bottomOverflow, leftOverflow, rightOverflow, graphWidth, graphHeight, graphX, graphY, allowContentOverflow = this.get("allowContentOverflow"), diff, rightAxesXCoords, leftAxesXCoords, topAxesYCoords, bottomAxesYCoords, graphRect = {}; if(leftAxesCollection) { leftAxesXCoords = []; l = leftAxesCollection.length; for(i = l - 1; i > -1; --i) { leftAxesXCoords.unshift(leftPaneWidth); leftPaneWidth += leftAxesCollection[i].get("width"); } } if(rightAxesCollection) { rightAxesXCoords = []; l = rightAxesCollection.length; i = 0; for(i = l - 1; i > -1; --i) { rightPaneWidth += rightAxesCollection[i].get("width"); rightAxesXCoords.unshift(w - rightPaneWidth); } } if(topAxesCollection) { topAxesYCoords = []; l = topAxesCollection.length; for(i = l - 1; i > -1; --i) { topAxesYCoords.unshift(topPaneHeight); topPaneHeight += topAxesCollection[i].get("height"); } } if(bottomAxesCollection) { bottomAxesYCoords = []; l = bottomAxesCollection.length; for(i = l - 1; i > -1; --i) { bottomPaneHeight += bottomAxesCollection[i].get("height"); bottomAxesYCoords.unshift(h - bottomPaneHeight); } } graphWidth = w - (leftPaneWidth + rightPaneWidth); graphHeight = h - (bottomPaneHeight + topPaneHeight); graphRect.left = leftPaneWidth; graphRect.top = topPaneHeight; graphRect.bottom = h - bottomPaneHeight; graphRect.right = w - rightPaneWidth; if(!allowContentOverflow) { topOverflow = this._getTopOverflow(leftAxesCollection, rightAxesCollection); bottomOverflow = this._getBottomOverflow(leftAxesCollection, rightAxesCollection); leftOverflow = this._getLeftOverflow(bottomAxesCollection, topAxesCollection); rightOverflow = this._getRightOverflow(bottomAxesCollection, topAxesCollection); diff = topOverflow - topPaneHeight; if(diff > 0) { graphRect.top = topOverflow; if(topAxesYCoords) { i = 0; l = topAxesYCoords.length; for(; i < l; ++i) { topAxesYCoords[i] += diff; } } } diff = bottomOverflow - bottomPaneHeight; if(diff > 0) { graphRect.bottom = h - bottomOverflow; if(bottomAxesYCoords) { i = 0; l = bottomAxesYCoords.length; for(; i < l; ++i) { bottomAxesYCoords[i] -= diff; } } } diff = leftOverflow - leftPaneWidth; if(diff > 0) { graphRect.left = leftOverflow; if(leftAxesXCoords) { i = 0; l = leftAxesXCoords.length; for(; i < l; ++i) { leftAxesXCoords[i] += diff; } } } diff = rightOverflow - rightPaneWidth; if(diff > 0) { graphRect.right = w - rightOverflow; if(rightAxesXCoords) { i = 0; l = rightAxesXCoords.length; for(; i < l; ++i) { rightAxesXCoords[i] -= diff; } } } } graphWidth = graphRect.right - graphRect.left; graphHeight = graphRect.bottom - graphRect.top; graphX = graphRect.left; graphY = graphRect.top; if(topAxesCollection) { l = topAxesCollection.length; i = 0; for(; i < l; i++) { axis = topAxesCollection[i]; if(axis.get("width") !== graphWidth) { axis.set("width", graphWidth); } axis.get("boundingBox").setStyle("left", graphX + "px"); axis.get("boundingBox").setStyle("top", topAxesYCoords[i] + "px"); } if(axis._hasDataOverflow()) { graphOverflow = "hidden"; } } if(bottomAxesCollection) { l = bottomAxesCollection.length; i = 0; for(; i < l; i++) { axis = bottomAxesCollection[i]; if(axis.get("width") !== graphWidth) { axis.set("width", graphWidth); } axis.get("boundingBox").setStyle("left", graphX + "px"); axis.get("boundingBox").setStyle("top", bottomAxesYCoords[i] + "px"); } if(axis._hasDataOverflow()) { graphOverflow = "hidden"; } } if(leftAxesCollection) { l = leftAxesCollection.length; i = 0; for(; i < l; ++i) { axis = leftAxesCollection[i]; axis.get("boundingBox").setStyle("top", graphY + "px"); axis.get("boundingBox").setStyle("left", leftAxesXCoords[i] + "px"); if(axis.get("height") !== graphHeight) { axis.set("height", graphHeight); } } if(axis._hasDataOverflow()) { graphOverflow = "hidden"; } } if(rightAxesCollection) { l = rightAxesCollection.length; i = 0; for(; i < l; ++i) { axis = rightAxesCollection[i]; axis.get("boundingBox").setStyle("top", graphY + "px"); axis.get("boundingBox").setStyle("left", rightAxesXCoords[i] + "px"); if(axis.get("height") !== graphHeight) { axis.set("height", graphHeight); } } if(axis._hasDataOverflow()) { graphOverflow = "hidden"; } } this._drawing = false; if(this._callLater) { this._redraw(); return; } if(graph) { graph.get("boundingBox").setStyle("left", graphX + "px"); graph.get("boundingBox").setStyle("top", graphY + "px"); graph.set("width", graphWi