Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

gallery-2014.01.28-00-45 tripp gallery-charts-stockindicators

  • Loading branch information...
commit 4293037fc3982326d3422e578634b1b6f74a862b 1 parent 731fd66
@tripp tripp authored
View
4 build/gallery-charts-stockindicators/gallery-charts-stockindicators-coverage.js
2 additions, 2 deletions not shown
View
582 build/gallery-charts-stockindicators/gallery-charts-stockindicators-debug.js
@@ -6,125 +6,31 @@ YUI.add('gallery-charts-stockindicators', function (Y, NAME) {
*
* @module gallery-charts-stockindicators
*/
-var defaultAxisLabelFormat = {
- value: null
-};
-
-Y.CategoryAxisBase.ATTRS.labelFormat = defaultAxisLabelFormat;
-Y.CategoryAxis.ATTRS.labelFormat = defaultAxisLabelFormat;
-//patch CartesianSeries destructor bug
-Y.CartesianSeries.prototype.destructor = function() {
- if(this.get("rendered"))
- {
- if(this._xDataReadyHandle)
- {
- this._xDataReadyHandle.detach();
- }
- if(this._xDataUpdateHandle)
- {
- this._xDataUpdateHandle.detach();
- }
- if(this._yDataReadyHandle)
- {
- this._yDataReadyHandle.detach();
- }
- if(this._yDataUpdateHandle)
- {
- this._yDataUpdateHandle.detach();
- }
- if(this._xAxisChangeHandle)
- {
- this._xAxisChangeHandle.detach();
- }
- if(this._yAxisChangeHandle)
- {
- this._yAxisChangeHandle.detach();
- }
- }
-};
-
-if(Y.VMLShape) {
- Y.VMLShape.ATTRS.stroke.setter = function(val) {
- var i,
- stroke,
- wt,
- tmpl = this.get("stroke") || this._getDefaultStroke();
- if(val)
- {
- if(val.hasOwnProperty("weight"))
- {
- wt = parseInt(val.weight, 10);
- if(!isNaN(wt))
- {
- val.weight = wt;
- }
- }
- for(i in val)
- {
- if(val.hasOwnProperty(i))
- {
- tmpl[i] = val[i];
- }
- }
- }
- if(tmpl.color && tmpl.color.toLowerCase().indexOf("rgba") > -1)
- {
- tmpl.opacity = Y.Color._getAlpha(tmpl.color);
- tmpl.color = Y.Color.toHex(tmpl.color);
- }
- stroke = tmpl;
- this._strokeFlag = true;
- return stroke;
- };
- Y.VMLShape.ATTRS.fill.setter = function(val) {
- var i,
- fill,
- tmpl = this.get("fill") || this._getDefaultFill();
-
- if(val)
- {
- //ensure, fill type is solid if color is explicitly passed.
- if(val.hasOwnProperty("color"))
- {
- val.type = "solid";
- }
- for(i in val)
- {
- if(val.hasOwnProperty(i))
- {
- tmpl[i] = val[i];
- }
- }
- }
- fill = tmpl;
- if(fill && fill.color)
- {
- if(fill.color === undefined || fill.color === "none")
- {
- fill.color = null;
- }
- else
- {
- if(fill.color.toLowerCase().indexOf("rgba") > -1)
- {
- fill.opacity = Y.Color._getAlpha(fill.color);
- fill.color = Y.Color.toHex(fill.color);
- }
- }
- }
- this._fillFlag = true;
- return fill;
- };
-}
+/**
+ * Provides functionality for a crosshair.
+ *
+ * @module gallery-charts-stockindicators
+ */
/**
* Creates an updatable crosshair on the Graph which can be controlled
* by mouse and touch events.
*
- * @module gallery-charts-stockindicators
* @class Crosshair
* @constructor
* @param {Object} config Configuration parameters.
+ * <dl>
+ * <dt>dotdiameter</dt><dd>The diameter of the circle or dot.</dd>
+ * <dt>drawHorizontal</dt><dd>Indicates whether to draw the horizontal line. The default
+ * value is `false`.</dd>
+ * <dt>drawVertical</dt><dd>Indicates whether to draw the verical line. The default
+ * value is `true`.</dd>
+ * <dt>lineColor</dt><dd>The color to use for lines.</dd>
+ * <dt>lineWidth</dt><dd>The weight of the lines.</dd>
+ * <dt>useCircle</dt><dd>Determines whether to use an empty circle. The default value is
+ * `false`.</dd>
+ * <dt>useDot</dt><dd>Determines whether to use a dot. The default value is `true`.</dd>
+ * </dl>
*/
Y.Crosshair = function() {
this.initializer.apply(this, arguments);
@@ -192,7 +98,7 @@ Y.Crosshair.prototype = {
* @method setTarget
* @param {Number} pageX The x-coordinate to map in which to map the crosshair.
*/
- setTarget: function(pageX) {
+ setTarget: function(pageX, redraw) {
var xy = this._xy,
x = pageX - xy[0],
y,
@@ -214,7 +120,22 @@ Y.Crosshair.prototype = {
}
}
}
- this.graphic._redraw();
+ this.updateFlag = true;
+ if(redraw) {
+ this.graphic._redraw();
+ }
+ },
+
+ /**
+ * Updates the crosshair items.
+ *
+ * @method redraw
+ */
+ redraw: function() {
+ if(this.updateFlag) {
+ this.graphic._redraw();
+ this.updateFlag = false;
+ }
},
/**
@@ -567,12 +488,52 @@ Y.Gridlines = Y.Base.create("gridlines", Y.Base, [Y.Renderer], {
}
});
/**
+ * Provides functionality for a legend.
+ *
+ * @module gallery-charts-stockindicators
+ */
+/**
* Displays a legend when the user interacts with the corresponding chart
* application.
*
- * @module gallery-charts-stockindicators
* @class StockIndicatorsLegend
* @constructor
+ * @param {Object} config Configuration parameters.
+ * <dl>
+ * <dt>dataProvider</dt><dd>Reference to the application's `dataProvider` attribute.</dd>
+ * <dt>dateColor</dt><dd>The color to be used for the date text in the legend.</dd>
+ * <dt>delim</dt><dd>String value prefixing the display name of each legend item.</dd>
+ * <dt>dateLabelFunction</dt><dd>The function used for formatting the date label.</dd>
+ * <dt>dateLabelFormat</dt><dd>The strf format used to format the date label.</dd>
+ * <dt>dateLabelScope</dt><dd>The scope for the dateLabelFunction</dd>
+ * <dt>displayKeys</dt><dd>An array of displayKeys to be used in the legend. Each display key
+ * is the text to be displayed in the legend for the corresponding value key.</dd>
+ * <dt>displayName</dt><dd>Indicates whether to display the display name. The default
+ * value is `true`.</dd>
+ * <dt>displayValue</dt><dd>Indicates whether to display the value. The default value
+ * is `true`.</dd>
+ * <dt>drawSwatch</dt><dd>Indicates whether or no to draw a colored swatch by the display
+ * name. The default value is `true`.</dd>
+ * <dt>font</dt><dd>The font to use for all text in the legend.</dd>
+ * <dt>fontSize</dt><dd>The font size to use for all text in the legend.</dd>
+ * <dt>height</dt><dd>The height of the legend.</dd>
+ * <dt>priceDownColor</dt><dd>The color to be used for the value text when the value is negative.</dd>
+ * <dt>priceUpColor</dt><dd>The color to be used for value text when the value is positive.</dd>
+ * <dt>swatchWidth</dt><dd>The width of the swatch for each legend item.</dd>
+ * <dt>valueKeys</dt><dd>The value keys, in order, to be used in the legend.</dd>
+ * <dt>valueLabelFormat</dt><dd>Object literal indicating how to format the legend values.
+ * <dl>
+ * <dt>prefix</dt><dd>The prefix.</dd>
+ * <dt>suffix</dt><dd>The suffix.</dd>
+ * <dt>thousandsSeparator</dt><dd>The thousands separator.</dd>
+ * <dt>decimalPlaces</dt><dd>The number of decimals to display.</dd>
+ * <dt>decimalsSeparator</dt><dd>The decimal separator.</dd>
+ * </dl>
+ * </dd>
+ * <dt>width</dt><dd>The width of the legend.</dd>
+ * <dt>x</dt><dd>The x-coordinate for the legend</dd>
+ * <dt>y</dt><dd>The y-coordinate for the legend</dd>
+ * </dl>
*/
function StockIndicatorsLegend() {
this.init.apply(this, arguments);
@@ -655,7 +616,7 @@ StockIndicatorsLegend.prototype = {
this.formatDate = cfg.formatDate;
this._xy = Y.DOM.getXY(this.contentDiv);
},
-
+
/**
* Removes all elements of the legend.
*
@@ -689,7 +650,7 @@ StockIndicatorsLegend.prototype = {
}
}
},
-
+
/**
* Updates the legend.
*
@@ -697,12 +658,24 @@ StockIndicatorsLegend.prototype = {
* @param {Number} pageX
* @param {Array} dataProvider
*/
- update: function(pageX, dataProvider) {
+ update: function(pageX, dataProvider, redraw) {
var xy = this._xy,
x = pageX - xy[0],
- index = Math.floor(x / this.width * dataProvider.length),
- dataItem = dataProvider[index],
- queue = this.seriesQueue,
+ index = Math.floor(x / this.width * dataProvider.length);
+ this._dataItem = dataProvider[index];
+ if(redraw) {
+ this.redraw();
+ }
+ },
+
+
+ /**
+ * Draws the legend.
+ *
+ * @method redraw
+ */
+ redraw: function() {
+ var queue = this.seriesQueue,
key,
len = queue.length,
item,
@@ -712,38 +685,48 @@ StockIndicatorsLegend.prototype = {
dateLabelFunction = this.dateLabelFunction,
dateLabelScope = this.dateLabelScope,
dateLabelFormat = this.dateLabelFormat,
- dateLabelArgs;
- val = dataItem.Date || dataItem.Timestamp;
- if(dateLabelFunction) {
- dateLabelArgs = [val];
- if(dateLabelFormat) {
- dateLabelArgs.push(dateLabelFormat);
+ dateLabelArgs,
+ dataItem = this._dataItem;
+ if(dataItem) {
+ val = dataItem.Date || dataItem.Timestamp;
+ if(dateLabelFunction) {
+ dateLabelArgs = [val];
+ if(dateLabelFormat) {
+ dateLabelArgs.push(dateLabelFormat);
+ }
+ val = dateLabelFunction.apply(dateLabelScope, dateLabelArgs);
}
- val = dateLabelFunction.apply(dateLabelScope, dateLabelArgs);
- }
- this.dateItem.value.innerHTML = Y.Escape.html(val);
- for(i = 0; i < len; i = i + 1) {
- key = queue[i];
- item = items[key];
- if(dataItem.hasOwnProperty(key)) {
- item.li.style.display = "inline-block";
- val = dataItem[key];
- item.value.innerHTML = Y.Number.format(parseFloat(val), this.valueLabelFormat);
- Y.DOM.setStyle(item.value, "color", val > 0 ? this.priceUpColor : this.priceDownColor);
- } else {
- item.li.style.display = "none";
+ this.dateItem.value.innerHTML = Y.Escape.html(val);
+ for(i = 0; i < len; i = i + 1) {
+ key = queue[i];
+ item = items[key];
+ if(dataItem.hasOwnProperty(key)) {
+ item.li.style.display = "inline-block";
+ val = dataItem[key];
+ item.value.innerHTML = Y.Number.format(parseFloat(val), this.valueLabelFormat);
+ Y.DOM.setStyle(item.value, "color", val > 0 ? this.priceUpColor : this.priceDownColor);
+ } else {
+ item.li.style.display = "none";
+ }
}
+ dataItem = this._dataItem = null;
}
}
};
Y.StockIndicatorsLegend = StockIndicatorsLegend;
/**
+ * Provides functionality for a chart.
+ *
+ * @module gallery-charts-stockindicators
+ */
+
+/**
* StockIndicatorsChart is an application that generates a chart or charts based on a key indexed array of data and an
* array of charts configuration data.
*
- * @module gallery-charts-stockindicators
* @class StockIndicatorsChart
* @constructor
+ * @param {Object} config An object literal contain properties defined in the <a href="#attr_charts">charts</a> attribute.
*/
function StockIndicatorsChart() {
StockIndicatorsChart.superclass.constructor.apply(this, arguments);
@@ -758,8 +741,12 @@ StockIndicatorsChart.ATTRS = {
* An object literal representing the `axes` for the chart. Each `axes` object contains a `date`
* and a `numeric` axis.
* <dl>
- * <dt>date</dt>The date axis is a `CategoryAxis` instance.
- * <dt>numeric</dt> The numeric axis is a `NumericAxis` instance.
+ * <dt>date</dt><dd>A <a href="http://yuilibrary.com/yui/docs/api/classes/CategoryAxis.html">CategoryAxis</a>
+ * instance. Possible attributes are listed
+ * <a href="http://yuilibrary.com/yui/docs/api/classes/CategoryAxis.html#attr_appendLabelFunction">here</a>.</dd>
+ * <dt>numeric</dt><dd>A <a href="http://yuilibrary.com/yui/docs/api/classes/NumericAxis.html">NumericAxis</a>
+ * instance. Possible attributes are listed
+ * <a href="http://yuilibrary.com/yui/docs/api/classes/NumericAxis.html#attr_alwaysShowZero">here</a>.</dd>
* </dl>
* </dd>
* <dt>categoryKey</dt><dd>A reference to the key in the `dataProvider` that represents the values
@@ -767,24 +754,11 @@ StockIndicatorsChart.ATTRS = {
* <dt>colors</dt><dd>An object containing key values pairs in which the key is a reference to the values
* of the `dataProvider` and the value is the color associated with each key. This data is used to determine
* the colors for the corresponding graphs, legends and crosshair markers.</dd>
- * <dt>crosshair</dt><dd>Configuration properties for the crosshair display that shows when
+ * <dt>crosshair</dt><dd>Configuration properties for the <a href="Crosshair.html">Crosshair</a> display that shows when
* interacting with a chart. It consists of `marker` shapes that correspond with each series of the
* chart, and optional horizontal and vertical lines. By default, the vertical line is displayed and
* the horizontal line is not. The colors of each `marker` is determined by its corresponding series
- * color. The crosshairConfig object has the following configurable properties:
- * <dl>
- * <dt>dotdiameter</dt><dd>The diameter of the circle or dot.</dd>
- * <dt>drawHorizontal</dt><dd>Indicates whether to draw the horizontal line. The default
- * value is `false`.</dd>
- * <dt>drawVertical</dt><dd>Indicates whether to draw the verical line. The default
- * value is `true`.</dd>
- * <dt>lineColor</dt><dd>The color to use for lines.</dd>
- * <dt>lineWidth</dt><dd>The weight of the lines.</dd>
- * <dt>useCircle</dt><dd>Determines whether to use an empty circle. The default value is
- * `false`.</dd>
- * <dt>useDot</dt><dd>Determines whether to use a dot. The default value is `true`.</dd>
- * </dl>
- * </dd>
+ * color. Possible configuration values are documented <a href="Crosshair.html">here</a>.</dd>
* <dt>dotdiameter</dt><dd>The diameter to be used for marker graphs in the chart.</dd>
* <dt>gridcolor</dt><dd>The color to be used for the background grid of the chart.</dd>
* <dt>height</dt><dd>The height of the chart including the legend, graph and date axis.</dd>
@@ -796,9 +770,11 @@ StockIndicatorsChart.ATTRS = {
* <dt>currency</dt><dd>Reference to the currency used to measure the data.</dd>
* <dt>displayKey</dt><dd>A key or array of keys, depending on the indicator mapped to a valueKey
* from the `dataProvider` that will be displayed in the corresponding legend.</dd>
+ * <dt>groupMarkers</dt><dd>Indicates whether to draw all markers as a single dom element.</dd>
* <dt>indicator</dt><dd>Represents the type of indicator data that will be displayed. (e.g. `quote`,
* `bollinger`, `psar`)</dd>
* <dt>iscomp</dt><dd>Indicates whether the indicator is a comparison indicator.</dd>
+ * <dt>labels</dt><dd>An array of of values used to create labels on the x-axis.</dd>
* <dt>ticker</dt><dd>Indicates the stock ticker of the indicator. (e.g. `yhoo`)</dd>
* <dt>type</dt><dd>Indicates the type of financial graph used to display the indicator data.
* (e.g. `candlestick`, `line`)
@@ -806,38 +782,9 @@ StockIndicatorsChart.ATTRS = {
* values from the `dataProvider`.</dd>
* </dl>
* </dd>
- * <dt>legend</dt><dd>
- * <dl>
- * <dt>currency</dt><dd>The prefix to be used for the values in each legend item.</dd>
- * <dt>dataProvider</dt><dd>Reference to the application's `dataProvider` attribute.</dd>
- * <dt>dateColor</dt><dd>The color to be used for the date text in the legend.</dd>
- * <dt>delim</dt><dd>String value prefixing the display name of each legend item.</dd>
- * <dt>displayKeys</dt><dd>An array of displayKeys to be used in the legend. Each display key
- * is the text to be displayed in the legend for the corresponding value key.</dd>
- * <dt>dislayName</dt><dd>Indicates whether to display the display name. The default
- * value is `true`.</dd>
- * <dt>displayValue</dt><dd>Indicates whether to display the value. The default value
- * is `true`.</dd>
- * <dt>drawSwatch</dt><dd>Indicates whether or no to draw a colored swatch by the display
- * name. The default value is `true`.</dd>
- * <dt>font</dt><dd>The font to use for all text in the legend.</dd>
- * <dt>fontSize</dt><dd>The font size to use for all text in the legend.</dd>
- * <dt>height</dt><dd>The height of the legend.</dd>
- * <dt>priceDownColor</dt><dd>The color to be used for the value text when the value is negative.</dd>
- * <dt>priceUpColor</dt><dd>The color to be used for value text when the value is positive.</dd>
- * <dt>swatchWidth</dt><dd>The width of the swatch for each legend item.</dd>
- * <dt>valueKeys</dt><dd>The value keys, in order, to be used in the legend.</dd>
- * <dt>valueLabelFormat</dt><dd>Object literal indicating how to format the legend values.
- * <dl>
- * <dt>prefix</dt><dd>The prefix.</dd>
- * <dt>suffix</dt><dd>The suffix.</dd>
- * <dt>thousandsSeparator</dt><dd>The thousands separator.</dd>
- * <dt>decimalPlaces</dt><dd>The number of decimals to display.</dd>
- * <dt>decimalsSeparator</dt><dd>The decimal separator.</dd>
- * </dl>
- * </dd>
- * </dl>
- * </dd>
+ * <dt>legend</dt><dd>Configuration properties used to construct the <a href="StockIndicatorsLegend.html">StockIndicatorsLegend</a>.
+ * Possible configuration values are documented <a href="StockIndicatorsLegend.html">here</a>. The x and y properties are not
+ * configurable through this object as they are determined by the layout of the charts in this application. </dd>
* <dt>lineWidth</dt><dd>The weight to be used for line graphs in the chart.</dd>
* <dt>numBar</dt><dd>The value used to calculate the width of the columns in a graph when the `rangeType` is
* `daily`. By default, the column width is determined from number of data values across the x axis and the
@@ -852,7 +799,7 @@ StockIndicatorsChart.ATTRS = {
* <dt>y</dt><dd>The y coordinate for the chart in relation to the application.</dd>
* </dl>
*
- * @attribute chartsData
+ * @attribute charts
* @type: Array
*/
charts: {},
@@ -903,6 +850,7 @@ Y.extend(StockIndicatorsChart, Y.Widget, {
* @param {Object} e Event payload
*/
updatesLegendsCrosshair: function(e) {
+ e.preventDefault();
var crosshair,
crosshairs = this._crosshairs,
legends = this._legends,
@@ -920,17 +868,74 @@ Y.extend(StockIndicatorsChart, Y.Widget, {
xy = chart.xy,
x = pageX - xy[0];
crosshair = this._crosshairs[i];
- crosshair.setTarget(pageX);
+ crosshair.setTarget(pageX, this._autoDraw);
}
len = legends.length;
for(i = 0; i < len; i = i + 1) {
- legends[i].update(pageX, this._dataProvider);
+ legends[i].update(pageX, this._dataProvider, this._autoDraw);
}
}
this.curX = pageX;
},
/**
+ * Starts a timeline used to manage redraws based on requestAnimationFrame.
+ *
+ * @method startTimeline
+ */
+ startTimeline: function() {
+ if(!this._runTimeline) {
+ this._runTimeline = true;
+ this._timelineStart = (new Date()).valueOf() - 17;
+ this.redraw();
+ }
+ },
+
+ /**
+ * Ends a timeline.
+ *
+ * @method stopTimeline
+ */
+ stopTimeline: function() {
+ var args,
+ timelineId = this._timelineId;
+ this._runTimeline = false;
+ if(timelineId) {
+ args = [timelineId];
+ this._timelineId = null;
+ }
+ },
+
+ /**
+ * Draws chart elements based on the timeline.
+ *
+ * @method redraw
+ */
+ redraw: function() {
+ var scope = this,
+ crosshairs = this._crosshairs,
+ legends = this._legends,
+ i,
+ len = crosshairs.length,
+ endTime = (new Date()).valueOf();
+ if(endTime >= this._timelineStart + 17) {
+ for(i = 0; i < len; i = i + 1) {
+ crosshairs[i].redraw();
+ }
+ len = legends.length;
+ for(i = 0; i < len; i = i + 1) {
+ legends[i].redraw();
+ }
+ this._timelineStart = (new Date()).valueOf();
+ }
+ if(this._runTimeline && !this._autoDraw) {
+ this._timelineId = this._onEnterFrame.apply(window, [function() {
+ scope.redraw();
+ }]);
+ }
+ },
+
+ /**
*
*/
initializer: function() {
@@ -942,6 +947,12 @@ Y.extend(StockIndicatorsChart, Y.Widget, {
this._crosshairs = [];
this._hotspots = [];
this._legends = [];
+ this._runTimeline = false;
+ this._onEnterFrame = window.requestAnimationFrame ||
+ window.mozRequestAnimationFrame ||
+ window.webkitRequestAnimationFrame ||
+ window.msRequestAnimationFrame;
+ this._autoDraw = this._onEnterFrame ? false : true;
StockIndicatorsChart.superclass.initializer.apply(this, arguments);
},
@@ -990,12 +1001,18 @@ Y.extend(StockIndicatorsChart, Y.Widget, {
indLen = indicators.length,
valueIter,
valueLen,
- valueKey;
+ valueKey,
+ groupMarkers;
for(indIter = 0; indIter < indLen; indIter = indIter + 1) {
indicator = indicators[indIter];
valueKey = indicator.valueKey;
- if(indicator.type === "candlestick" || typeof valueKey === "string") {
+ indicatorType = indicator.type;
+ if(indicatorType === "candlestick" || typeof valueKey === "string") {
+ groupMarkers = indicatorType !== "candlestick" &&
+ indicatorType !== "line" &&
+ indicator.groupMarkers;
seriesCollection.push({
+ groupMarkers: groupMarkers,
type: indicator.type,
xKey: config.categoryKey,
yKey: indicator.valueKey
@@ -1004,7 +1021,9 @@ Y.extend(StockIndicatorsChart, Y.Widget, {
valueLen = valueKey.length;
for(valueIter = 0; valueIter < valueLen; valueIter = valueIter + 1) {
indicatorType = indicator.type;
+ groupMarkers = indicatorType !== "line" && indicator.groupMarkers;
seriesCollection.push({
+ groupMarkers: groupMarkers,
type: typeof indicatorType === "string" ? indicatorType : indicatorType[valueIter],
xKey: config.categoryKey,
yKey: indicator.valueKey[valueIter]
@@ -1183,6 +1202,20 @@ Y.extend(StockIndicatorsChart, Y.Widget, {
};
},
+ /**
+ * Maps axis class to key.
+ *
+ * @property _axesClassMap
+ * @type AxisBase
+ * @private
+ */
+ _axesClassMap: {
+ numeric: Y.NumericAxis,
+ numericbase: Y.NumericAxisBase,
+ category: Y.CategoryAxis,
+ categorybase: Y.CategoryAxisBase
+ },
+
/**
* Add the axes to the chart and returns an object literal with references to the
* `date` and `numeric` axes.
@@ -1199,7 +1232,9 @@ Y.extend(StockIndicatorsChart, Y.Widget, {
numericConfig = config.axes.numeric,
dateConfig = config.axes.date,
numericAxis,
- dateAxis;
+ dateAxis,
+ NumericClass = this._axesClassMap[numericConfig.type],
+ DateClass = this._axesClassMap[dateConfig.type];
numericConfig.render = cb;
numericConfig.y = config.y + config.legend.height;
numericConfig.x = config.width - numericConfig.width;
@@ -1207,8 +1242,8 @@ Y.extend(StockIndicatorsChart, Y.Widget, {
dateConfig.render = cb;
dateConfig.y = config.y + config.height - dateConfig.height;
dateConfig.width = config.width;
- numericAxis = new Y.NumericAxis(numericConfig);
- dateAxis = new Y.CategoryAxis(dateConfig);
+ numericAxis = new NumericClass(numericConfig);
+ dateAxis = new DateClass(dateConfig);
bb = dateAxis.get("boundingBox");
bb.setStyle("left", 0 + "px");
bb.setStyle("top", (config.y + config.height - dateConfig.height) + "px");
@@ -1479,16 +1514,165 @@ Y.extend(StockIndicatorsChart, Y.Widget, {
}
});
Y.StockIndicatorsChart = StockIndicatorsChart;
+/**
+ * Creates a spark graph.
+ *
+ * @module gallery-charts-stockindicators
+ * @class StockIndicatorsSpark
+ * @constructor
+ */
+Y.StockIndicatorsSpark = function() {
+ this._init.apply(this, arguments);
+ return this;
+};
+
+Y.StockIndicatorsSpark.prototype = {
+ /**
+ * Maps keys to corresponding class.
+ *
+ * @property _graphMap
+ * @type Object
+ * @private
+ */
+ _graphMap: {
+ line: Y.LineSeries,
+ marker: Y.MarkerSeries,
+ column: Y.ColumnSeries,
+ area: Y.AreaSeries
+ },
+
+ /**
+ * Maps keys to the property of a style attribute
+ * of the corresponding `SeriesBase` instance.
+ *
+ * @property _styleMap
+ * @type Object
+ * @private
+ */
+ _styleMap: {
+ line: "line",
+ marker: "marker",
+ column: "marker",
+ area: "area"
+ },
+
+ /**
+ * Sets properties for the graph.
+ *
+ * @method _init
+ * @param {Object} config Properties for the graph.
+ * @private
+ */
+ _init: function(config) {
+ var styles = config.styles,
+ bb = document.createElement('div'),
+ cb = document.createElement('div'),
+ render = config.render,
+ type = config.type || "line",
+ style = type === "column" ? "marker" : type,
+ SparkClass = this._graphMap[type];
+ this.dataProvider = config.dataProvider;
+ this.xKey = config.xKey;
+ this.yKey = config.yKey;
+ if(!styles) {
+ styles = {};
+ if(config[style]) {
+ styles[style] = config[style];
+ } else {
+ styles[style] = {};
+ if(config.color) {
+ styles.line.color = config.color;
+ }
+ if(config.alpha) {
+ styles.line.alpha = config.alpha;
+ }
+ if(type === "line") {
+ styles.line.weight = isNaN(config.weight) ? 1 : config.weight;
+ }
+ }
+ }
+ this.xAxis = new Y.CategoryAxisBase({
+ dataProvider: this.dataProvider,
+ keys: [this.xKey]
+ });
+ this.yAxis = new Y.NumericAxisBase({
+ dataProvider: this.dataProvider,
+ keys: [this.yKey],
+ alwaysShowZero: false
+ });
+ bb.style.position = "absolute";
+ Y.DOM.setStyle(bb, "inlineBlock");
+ cb.style.position = "relative";
+ render = document.getElementById(render);
+ render.appendChild(bb);
+ bb.appendChild(cb);
+ cb.style.width = Y.DOM.getComputedStyle(render, "width");
+ cb.style.height = Y.DOM.getComputedStyle(render, "height");
+ this.graphic = new Y.Graphic({
+ render: cb,
+ autoDraw: false
+ });
+ this.graph = new SparkClass({
+ rendered: true,
+ dataProvider: config.dataProvider,
+ graphic: this.graphic,
+ styles: styles,
+ xAxis: this.xAxis,
+ yAxis: this.yAxis,
+ xKey: this.xKey,
+ yKey: this.yKey
+ });
+ this.contentBox = cb;
+ this.boundingBox = bb;
+ this.graph.validate();
+ this.graphic._redraw();
+ },
+
+ /**
+ * Removes all elements of the spark.
+ *
+ * @method destroy
+ */
+ destroy: function() {
+ var parentNode;
+ if(this.xAxis) {
+ this.xAxis.destroy(true);
+ }
+ if(this.yAxis) {
+ this.yAxis.destroy(true);
+ }
+ if(this.graph) {
+ this.graph.destroy();
+ }
+ if(this.graphic) {
+ this.graphic.destroy();
+ }
+ if(this.contentBox) {
+ parentNode = this.contentBox.parentNode;
+ if(parentNode) {
+ parentNode.removeChild(this.contentBox);
+ }
+ }
+ if(this.boundingBox) {
+ parentNode = this.boundingBox.parentNode;
+ if(parentNode) {
+ parentNode.removeChild(this.boundingBox);
+ }
+ }
+ }
+};
-}, 'gallery-2013.12.20-18-06', {
+}, 'gallery-2014.01.28-00-45', {
"requires": [
+ "escape",
"graphics-group",
"axis-numeric",
"axis-category",
"series-line",
"series-marker",
"series-column",
- "series-candlestick"
+ "series-candlestick",
+ "series-area"
]
});
View
6 build/gallery-charts-stockindicators/gallery-charts-stockindicators-min.js
@@ -1,3 +1,3 @@
-YUI.add("gallery-charts-stockindicators",function(e,t){function r(){this.init.apply(this,arguments)}function i(){i.superclass.constructor.apply(this,arguments)}var n={value:null};e.CategoryAxisBase.ATTRS.labelFormat=n,e.CategoryAxis.ATTRS.labelFormat=n,e.CartesianSeries.prototype.destructor=function(){this.get("rendered")&&(this._xDataReadyHandle&&this._xDataReadyHandle.detach(),this._xDataUpdateHandle&&this._xDataUpdateHandle.detach(),this._yDataReadyHandle&&this._yDataReadyHandle.detach(),this._yDataUpdateHandle&&this._yDataUpdateHandle.detach(),this._xAxisChangeHandle&&this._xAxisChangeHandle.detach(),this._yAxisChangeHandle&&this._yAxisChangeHandle.detach())},e.VMLShape&&(e.VMLShape.ATTRS.stroke.setter=function(t){var n,r,i,s=this.get("stroke")||this._getDefaultStroke();if(t){t.hasOwnProperty("weight")&&(i=parseInt(t.weight,10),isNaN(i)||(t.weight=i));for(n in t)t.hasOwnProperty(n)&&(s[n]=t[n])}return s.color&&s.color.toLowerCase().indexOf("rgba")>-1&&(s.opacity=e.Color._getAlpha(s.color),s.color=e.Color.toHex(s.color)),r=s,this._strokeFlag=!0,r},e.VMLShape.ATTRS.fill.setter=function(t){var n,r,i=this.get("fill")||this._getDefaultFill();if(t){t.hasOwnProperty("color")&&(t.type="solid");for(n in t)t.hasOwnProperty(n)&&(i[n]=t[n])}return r=i,r&&r.color&&(r.color===undefined||r.color==="none"?r.color=null:r.color.toLowerCase().indexOf("rgba")>-1&&(r.opacity=e.Color._getAlpha(r.color),r.color=e.Color.toHex(r.color))),this._fillFlag=!0,r}),e.Crosshair=function(){this.initializer.apply(this,arguments)},e.Crosshair.prototype={initializer:function(t){var n=new e.Graphic({render:t.render,autoDraw:!1,width:t.width,height:t.height,x:t.x,y:t.y}),r=t.width,i=t.height,s=t.series,o,u=t.category,a,f,l=s.length;a=n.addShape({shapeRendering:"crispEdges",type:"path",stroke:u.stroke}).moveTo(0,0).lineTo(0,i).end(),this._xcoords=u.coords,this._yline=a,this.width=t.width,this.height=t.height;if(s){for(f=0;f<l;f+=1)o=s[f],o.line&&(o.xLine=n.addShape({shapeRendering:"crispEdges",type:"path",stroke:o.stroke,fill:o.fill}).moveTo(0,0).lineTo(r,0).end()),o.marker&&(o.marker.y=o.marker.height/-2,o.marker.x=o.marker.width/-2,o.marker.type=o.marker.type||o.marker.shape,o.marker=n.addShape(o.marker));this._series=s}this._xy=n.getXY(),this.graphic=n},setTarget:function(e){var t=this._xy,n=e-t[0],r,i=this._series,s,o,u=Math.floor(n/this.width*this._xcoords.length),a=i.length;this._yline.set("transform","translate("+n+")");if(i)for(o=0;o<a;o+=1)s=i[o],r=s.coords[u],s.marker&&s.marker.set("transform","translate("+n+", "+r+")"),s.line&&s.line.set("transform","translate("+n+", "+r+")");this.graphic._redraw()},destroy:function(){var e=this._series,t=this._yline,n,r,i;if(e){i=e.length;for(r=0;r<i;r+=1)n=e[r],n.marker&&n.marker.get("graphic").destroy(),n.line&&n.line.get("graphic").destroy(),t&&t.get("graphic").destroy()}}},e.Gridlines=e.Base.create("gridlines",e.Base,[e.Renderer],{_path:null,remove:function(){var e=this._path;e&&e.destroy()},draw:function(){this.get("axis")&&this.get("graphic")&&this._drawGridlines.apply(this,arguments)},_drawGridlines:function(e,t,n,r){var i=this._path,s=this.get("axis"),o=s.get("position"),u,a=this.get("direction"),f=this.get("graphic"),l=this.get("styles").fill,c=this.get("styles").border,h=this.get("styles").line,p=l&&c?c:h,d,v;n=n||0,r=r||2,isFinite(e)&&isFinite(t)&&e>0&&t>0&&(o!=="none"&&s&&s.get("tickPoints")?u=s.get("tickPoints"):u=this._getPoints(s.get("styles").majorUnit.count,e,t),i?(i.set("width",e),i.set("height",t),i.set("stroke",p),l&&i.set("fill",l)):(d={type:"path",width:e,stroke:p,height:t},l&&(d.fill=l),i=f.addShape(d),i.addClass("yui3-gridlines"),this._path=i),a==="vertical"?(v=l?this._verticalFill:this._verticalLine,v(i,u,t,n,r,e)):(v=l?this._horizontalFill:this._horizontalLine,v(i,u,e,n,r,t)),i.end())},_getPoints:function(e,t,n){var r,i=[],s,o=e-1;for(r=0;r<e;r+=1)s=r/o,i[r]={x:t*s,y:n*s};return i},_horizontalLine:function(e,t,n){var r,i=t.length,s;for(r=0;r<i;r+=1)s=t[r].y,e.moveTo(0,s),e.lineTo(n,s)},_verticalLine:function(e,t,n){var r,i=t.length,s;for(r=0;r<i;r+=1)s=t[r].x,e.moveTo(s,0),e.lineTo(s,n)},_horizontalFill:function(e,t,n,r,i,s){var o,u,a,f=t.length;for(o=r;o<f;o+=i)u=t[o].y,a=o<f-1?t[o+1].y:s,e.moveTo(0,u),e.lineTo(0,a),e.lineTo(n,a),e.lineTo(n,u),e.lineTo(0,u),e.closePath()},_verticalFill:function(e,t,n,r,i,s){var o,u,a,f=t.length;for(o=r;o<f;o+=i)u=t[o].x,a=o<f-1?t[o+1].x:s,e.moveTo(u,0),e.lineTo(a,0),e.lineTo(a,n),e.lineTo(u,n),e.lineTo(u,0),e.closePath()},_getDefaultStyles:function(){var e={line:{color:"#f0efe9",weight:1,alpha:1},fill:null};return e}},{ATTRS:{direction:{},axis:{},graphic:{},count:{}}}),r.prototype={init:function(t){var n,r,i,s=t.valueKeys,o=t.displayKeys,u,a,f,l=this.items||{},c;this.x=t.x,this.y=t.y,this.width=t.width,this.height=t.height,this.dataProvider=t.dataProvider,this.contentDiv=e.DOM.create('<div style="position:absolute;top:'+t.y+"px;"+t.x+"0px;height: "+t.height+"px; width: "+t.width+'px;" class="l-hbox">'),this.dateLabelFunction=t.dateLabelFunction,this.dateLabelFormat=t.dateLabelFormat,this.dateLabelScope=t.dateLabelScope||this,t.render.getDOMNode().appendChild(this.contentDiv),i=s.length,r=e.DOM.create('<ul style="vertical-align: middle; line-height: '+this.height+'px;padding:0px 0px 0px 0px;margin:0px 0px 0px 0px;" class="layout-item-modules pure-g">'),this.contentDiv.appendChild(r),this.dateItem={li:e.DOM.create('<li class="layout-item-module pure-u" style="display:inline-block; margin: 0px 4px 0px 0px;">'),value:e.DOM.create('<span style="border-left:'+t.swatchWidth+"px solid #fff;font-size:"+t.fontSize+";font-family:"+t.font+';" id="dateitem";font-color:'+t.dateColor+'" ></span>')},this.dateItem.li.appendChild(this.dateItem.value),r.appendChild(this.dateItem.li);for(n=0;n<i;n+=1)f=s[n],u=o[n],a={},c=t.colors[f],a.li=e.DOM.create('<li id="'+f+'" class="layout-item-module pure-u" style="display:inline-block; margin: 0px 4px 0px 0px;">'),a.bullet=e.DOM.create('<div style="display: inline-block;width:3px; height: '+this
-.height+"px; background-color:"+c+';"></div>'),a.label=e.DOM.create('<span style="font-size:'+t.fontSize+";font-family:"+t.font+";color:"+c+';display:inline:margin: 0px 0px 0px 0px;" id="'+f+'" >'+t.delim+u+" : </span>"),a.value=e.DOM.create('<span style="font-size:'+t.fontSize+";font-family:"+t.font+';display:inline:margin: 0px 0px 0px 0px;" id="'+f+'Value" ></span>'),r.appendChild(a.li),a.li.appendChild(a.bullet),a.li.appendChild(a.label),a.li.appendChild(a.value),l[f]=a,a.li.style.display="none";this.list=r,this.seriesQueue=s,this.items=l,this.priceUpColor=t.priceUpColor,this.priceDownColor=t.priceDownColor,this.valueLabelFormat=t.valueLabelFormat,this.formatDate=t.formatDate,this._xy=e.DOM.getXY(this.contentDiv)},destroy:function(){this._removeChildren(this.list),this._removeChildren(this.contentDiv),this.contentDiv&&this.contentDiv.parentNode&&this.contentDiv.parentNode.removeChild(this.contentDiv)},_removeChildren:function(e){if(e&&e.hasChildNodes()){var t;while(e.firstChild)t=e.firstChild,this._removeChildren(t),e.removeChild(t)}},update:function(t,n){var r=this._xy,i=t-r[0],s=Math.floor(i/this.width*n.length),o=n[s],u=this.seriesQueue,a,f=u.length,l,c=this.items,h,p,d=this.dateLabelFunction,v=this.dateLabelScope,m=this.dateLabelFormat,g;p=o.Date||o.Timestamp,d&&(g=[p],m&&g.push(m),p=d.apply(v,g)),this.dateItem.value.innerHTML=e.Escape.html(p);for(h=0;h<f;h+=1)a=u[h],l=c[a],o.hasOwnProperty(a)?(l.li.style.display="inline-block",p=o[a],l.value.innerHTML=e.Number.format(parseFloat(p),this.valueLabelFormat),e.DOM.setStyle(l.value,"color",p>0?this.priceUpColor:this.priceDownColor)):l.li.style.display="none"}},e.StockIndicatorsLegend=r,i.NAME="stockChart",i.ATTRS={charts:{},dataProvider:{lazyAdd:!1,getter:function(){return this._dataProvider},setter:function(e){return this._dataProvider=e,e}}},e.extend(i,e.Widget,{drawCharts:function(){var e=[],t=this.get("charts"),n=this.get("contentBox"),r,i=t.length;this._removeAll();for(r=0;r<i;r+=1)e[r]=this.drawChart(t[r],n);this._charts=e},updatesLegendsCrosshair:function(e){var t,n=this._crosshairs,r=this._legends,i=e&&e.hasOwnProperty("changedTouches"),s=i?e.changedTouches[0].pageX:e.pageX,o=i?e.changedTouches[0].pageY:e.pageY,u=n.length,a,f,l,c;if(s%1===0&&o%1===0&&this.curX!==s){for(c=0;c<u;c+=1)a=this._charts[c],f=a.xy,l=s-f[0],t=this._crosshairs[c],t.setTarget(s);u=r.length;for(c=0;c<u;c+=1)r[c].update(s,this._dataProvider)}this.curX=s},initializer:function(){var e=this.get("contentBox");e.setStyle("position","relative"),this._axes=[],this._graphs=[],this._graphics=[],this._crosshairs=[],this._hotspots=[],this._legends=[],i.superclass.initializer.apply(this,arguments)},_graphMap:{line:e.LineSeries,marker:e.MarkerSeries,column:e.ColumnSeries,candlestick:e.CandlestickSeries},_getGraph:function(e){return this._graphMap[e]},_getSeriesCollection:function(e){var t=[],n,r=e.indicators,i,s,o=r.length,u,a,f;for(s=0;s<o;s+=1){n=r[s],f=n.valueKey;if(n.type==="candlestick"||typeof f=="string")t.push({type:n.type,xKey:e.categoryKey,yKey:n.valueKey});else{a=f.length;for(u=0;u<a;u+=1)i=n.type,t.push({type:typeof i=="string"?i:i[u],xKey:e.categoryKey,yKey:n.valueKey[u]})}}return t},_getSeriesStyles:function(e,t){var n,r=t.colors,i,s,o,u,a,f=e.length;for(a=0;a<f;a+=1){n=e[a];switch(n.type){case"line":n.styles={line:{weight:t.lineWidth,color:r[n.yKey]}};break;case"candlestick":n.styles={upcandle:{fill:{color:r.priceUp}},downcandle:{fill:{color:r.priceDown}}};break;case"marker":o=this.get("dataProvider"),i=Math.min(t.dotDiameter,t.width/o.length),n.styles={marker:{width:i,height:i,border:{color:r[n.yKey],weight:0},fill:{color:r[n.yKey]}}};break;case"column":o=this.get("dataProvider"),u=t.rangeType,s=t.width/o.length,s=Math.min(10,Math.round(s-s*.4)),s-=2,s=Math.max(1,s),n.styles={marker:{width:s,border:{weight:0},fill:{color:r[n.yKey]}}}}}return e},_drawGraphs:function(e,t,n){var r=this._getSeriesStyles(this._getSeriesCollection(e),e),i,s,o,u={},a=t.date,f=t.numeric,l,c,h=r.length;for(c=0;c<h;c+=1)i=r[c],i.xAxis=a,i.yAxis=f,i.graphic=n,l=this._getGraph(i.type),o=new l(i),o.draw(),s=i.yKey,typeof s!="string"&&(s="quote"),u[s]=o;return this._graphs.push(o),u},_drawGridlines:function(t,n,r){var i=r.get("width"),s=r.get("height"),o=new e.Gridlines({graphic:r,direction:"horizontal",axis:n.numeric}),u=new e.Gridlines({graphic:r,direction:"vertical",axis:n.date,styles:{fill:{color:t.gridColor},border:{weight:0}}});return o.draw(i,s),u.draw(i,s,t.rangeType==="intraday"?0:1),o._path.toBack(),u._path.toBack(),{horizontal:o,vertical:u}},_drawAxes:function(t,n){var r,i,s=t.axes.numeric,o=t.axes.date,u,a;return s.render=n,s.y=t.y+t.legend.height,s.x=t.width-s.width,s.height=t.height-o.height-t.legend.height,o.render=n,o.y=t.y+t.height-o.height,o.width=t.width,u=new e.NumericAxis(s),a=new e.CategoryAxis(o),i=a.get("boundingBox"),i.setStyle("left","0px"),i.setStyle("top",t.y+t.height-o.height+"px"),i=u.get("boundingBox"),i.setStyle("left",s.x+"px"),i.setStyle("top",t.y+t.legend.height+"px"),r={numeric:u,date:a},this._axes.push(r),r},_drawHotspot:function(t,n){var r=e.Node.create('<div class="yui3-hotspot" id="fincharthotspot_'+this._hotspots.length+'" style="width:'+t.width+"px;height:"+(t.height-t.legend.height-t.axes.date.height)+"px;position:absolute;left:0px;top:"+(t.y+t.legend.height)+'px;opacity:0;background:#fff;z-index:4"></div>');r.setStyle("opacity",0),n.append(r),this._hotspots.push(r)},_createGraphic:function(t,n){var r=new e.Graphic({render:n,width:this.get("width"),height:t.height-t.legend.height-t.axes.date.height,x:0,y:t.y+t.legend.height,autoDraw:!1});return this._graphics.push(r),r},_addCrosshair:function(t,n,r){var i,s=t.crosshair,o={stroke:{color:s.lineColor,weight:s.lineWidth}},u=[],a,f,l=t.colors;for(f in n)n.hasOwnProperty(f)&&(a=n[f],u.push({marker:{shape:"circle",width:s.dotDiameter,height:s.dotDiameter,fill:{color:l[f==="quote"?"close":f]},stroke:{weight:0}},coords:f==="quote"?a.get("ycoords").close:a.get("ycoords")}),o.coords=a.get("xcoords"));return i=new
-e.Crosshair({width:t.width,height:t.height-t.axes.date.height-t.legend.height,x:0,y:t.y+t.legend.height,render:r,series:u,category:o}),this._crosshairs.push(i),i},_addLegend:function(t,n){var r,i=t.legend;return i.colors=t.colors,i.render=n,i.y=t.y,r=new e.StockIndicatorsLegend(i),this._legends.push(r),r},drawChart:function(e,t){var n,r=this._drawAxes(e,t),i=this._createGraphic(e,t),s=this._drawGridlines(e,r,i),o=this._drawGraphs(e,r,i),u=this._drawHotspot(e,t),a=this._addCrosshair(e,o,t),f=this._addLegend(e,t);return n={axes:r,graphic:i,gridlines:s,graphs:o,hotspot:u,crosshair:a,legend:f,xy:i.getXY()},i._redraw(),n},_destroyCrosshairs:function(){var e,t=this._charts.length,n;while(this._crosshairs.length>0)n=this._crosshairs.pop(),n.destroy();for(e=0;e<t;e+=1)delete this._charts[e].crosshair},_destroyHotspots:function(){var e,t=this._charts.length,n;while(this._hotspots.length>0)n=this._hotspots.pop(),n.empty(),n.remove(!0);for(e=0;e<t;e+=1)delete this._charts[e].hotspot},_destroyAxes:function(){var e,t=this._charts.length,n;while(this._axes.length>0)n=this._axes.pop(),n.date.destroy(!0),n.numeric.destroy(!0);for(e=0;e<t;e+=1)delete this._charts[e].axes},_destroyGraphs:function(){var e,t=this._charts.length,n;while(this._graphs.length>0)n=this._graphs.pop(),n.destroy(!0);for(e=0;e<t;e+=1)delete this._charts[e].graph},_destroyLegends:function(){var e,t=this._charts.length,n;while(this._legends.length>0)n=this._legends.pop(),n.destroy();for(e=0;e<t;e+=1)delete this._charts[e].legend},_destroyGraphics:function(){var e,t=this._charts.length,n;while(this._graphics.length>0)n=this._graphics.pop(),n.destroy();for(e=0;e<t;e+=1)delete this._charts[e].graphic},_removeAll:function(){var e,t;if(this._charts){this._destroyCrosshairs(),this._destroyHotspots(),this._destroyLegends(),this._destroyGraphs(),this._destroyAxes(),this._destroyGraphics();while(this._charts.length>0){e=this._charts.pop();for(t in e)e.hasOwnProperty(t)&&delete e[t]}}},destructor:function(){this._removeAll()}}),e.StockIndicatorsChart=i},"gallery-2013.12.20-18-06",{requires:["graphics-group","axis-numeric","axis-category","series-line","series-marker","series-column","series-candlestick"]});
+YUI.add("gallery-charts-stockindicators",function(e,t){function n(){this.init.apply(this,arguments)}function r(){r.superclass.constructor.apply(this,arguments)}e.Crosshair=function(){this.initializer.apply(this,arguments)},e.Crosshair.prototype={initializer:function(t){var n=new e.Graphic({render:t.render,autoDraw:!1,width:t.width,height:t.height,x:t.x,y:t.y}),r=t.width,i=t.height,s=t.series,o,u=t.category,a,f,l=s.length;a=n.addShape({shapeRendering:"crispEdges",type:"path",stroke:u.stroke}).moveTo(0,0).lineTo(0,i).end(),this._xcoords=u.coords,this._yline=a,this.width=t.width,this.height=t.height;if(s){for(f=0;f<l;f+=1)o=s[f],o.line&&(o.xLine=n.addShape({shapeRendering:"crispEdges",type:"path",stroke:o.stroke,fill:o.fill}).moveTo(0,0).lineTo(r,0).end()),o.marker&&(o.marker.y=o.marker.height/-2,o.marker.x=o.marker.width/-2,o.marker.type=o.marker.type||o.marker.shape,o.marker=n.addShape(o.marker));this._series=s}this._xy=n.getXY(),this.graphic=n},setTarget:function(e,t){var n=this._xy,r=e-n[0],i,s=this._series,o,u,a=Math.floor(r/this.width*this._xcoords.length),f=s.length;this._yline.set("transform","translate("+r+")");if(s)for(u=0;u<f;u+=1)o=s[u],i=o.coords[a],o.marker&&o.marker.set("transform","translate("+r+", "+i+")"),o.line&&o.line.set("transform","translate("+r+", "+i+")");this.updateFlag=!0,t&&this.graphic._redraw()},redraw:function(){this.updateFlag&&(this.graphic._redraw(),this.updateFlag=!1)},destroy:function(){var e=this._series,t=this._yline,n,r,i;if(e){i=e.length;for(r=0;r<i;r+=1)n=e[r],n.marker&&n.marker.get("graphic").destroy(),n.line&&n.line.get("graphic").destroy(),t&&t.get("graphic").destroy()}}},e.Gridlines=e.Base.create("gridlines",e.Base,[e.Renderer],{_path:null,remove:function(){var e=this._path;e&&e.destroy()},draw:function(){this.get("axis")&&this.get("graphic")&&this._drawGridlines.apply(this,arguments)},_drawGridlines:function(e,t,n,r){var i=this._path,s=this.get("axis"),o=s.get("position"),u,a=this.get("direction"),f=this.get("graphic"),l=this.get("styles").fill,c=this.get("styles").border,h=this.get("styles").line,p=l&&c?c:h,d,v;n=n||0,r=r||2,isFinite(e)&&isFinite(t)&&e>0&&t>0&&(o!=="none"&&s&&s.get("tickPoints")?u=s.get("tickPoints"):u=this._getPoints(s.get("styles").majorUnit.count,e,t),i?(i.set("width",e),i.set("height",t),i.set("stroke",p),l&&i.set("fill",l)):(d={type:"path",width:e,stroke:p,height:t},l&&(d.fill=l),i=f.addShape(d),i.addClass("yui3-gridlines"),this._path=i),a==="vertical"?(v=l?this._verticalFill:this._verticalLine,v(i,u,t,n,r,e)):(v=l?this._horizontalFill:this._horizontalLine,v(i,u,e,n,r,t)),i.end())},_getPoints:function(e,t,n){var r,i=[],s,o=e-1;for(r=0;r<e;r+=1)s=r/o,i[r]={x:t*s,y:n*s};return i},_horizontalLine:function(e,t,n){var r,i=t.length,s;for(r=0;r<i;r+=1)s=t[r].y,e.moveTo(0,s),e.lineTo(n,s)},_verticalLine:function(e,t,n){var r,i=t.length,s;for(r=0;r<i;r+=1)s=t[r].x,e.moveTo(s,0),e.lineTo(s,n)},_horizontalFill:function(e,t,n,r,i,s){var o,u,a,f=t.length;for(o=r;o<f;o+=i)u=t[o].y,a=o<f-1?t[o+1].y:s,e.moveTo(0,u),e.lineTo(0,a),e.lineTo(n,a),e.lineTo(n,u),e.lineTo(0,u),e.closePath()},_verticalFill:function(e,t,n,r,i,s){var o,u,a,f=t.length;for(o=r;o<f;o+=i)u=t[o].x,a=o<f-1?t[o+1].x:s,e.moveTo(u,0),e.lineTo(a,0),e.lineTo(a,n),e.lineTo(u,n),e.lineTo(u,0),e.closePath()},_getDefaultStyles:function(){var e={line:{color:"#f0efe9",weight:1,alpha:1},fill:null};return e}},{ATTRS:{direction:{},axis:{},graphic:{},count:{}}}),n.prototype={init:function(t){var n,r,i,s=t.valueKeys,o=t.displayKeys,u,a,f,l=this.items||{},c;this.x=t.x,this.y=t.y,this.width=t.width,this.height=t.height,this.dataProvider=t.dataProvider,this.contentDiv=e.DOM.create('<div style="position:absolute;top:'+t.y+"px;"+t.x+"0px;height: "+t.height+"px; width: "+t.width+'px;" class="l-hbox">'),this.dateLabelFunction=t.dateLabelFunction,this.dateLabelFormat=t.dateLabelFormat,this.dateLabelScope=t.dateLabelScope||this,t.render.getDOMNode().appendChild(this.contentDiv),i=s.length,r=e.DOM.create('<ul style="vertical-align: middle; line-height: '+this.height+'px;padding:0px 0px 0px 0px;margin:0px 0px 0px 0px;" class="layout-item-modules pure-g">'),this.contentDiv.appendChild(r),this.dateItem={li:e.DOM.create('<li class="layout-item-module pure-u" style="display:inline-block; margin: 0px 4px 0px 0px;">'),value:e.DOM.create('<span style="border-left:'+t.swatchWidth+"px solid #fff;font-size:"+t.fontSize+";font-family:"+t.font+';" id="dateitem";font-color:'+t.dateColor+'" ></span>')},this.dateItem.li.appendChild(this.dateItem.value),r.appendChild(this.dateItem.li);for(n=0;n<i;n+=1)f=s[n],u=o[n],a={},c=t.colors[f],a.li=e.DOM.create('<li id="'+f+'" class="layout-item-module pure-u" style="display:inline-block; margin: 0px 4px 0px 0px;">'),a.bullet=e.DOM.create('<div style="display: inline-block;width:3px; height: '+this.height+"px; background-color:"+c+';"></div>'),a.label=e.DOM.create('<span style="font-size:'+t.fontSize+";font-family:"+t.font+";color:"+c+';display:inline:margin: 0px 0px 0px 0px;" id="'+f+'" >'+t.delim+u+" : </span>"),a.value=e.DOM.create('<span style="font-size:'+t.fontSize+";font-family:"+t.font+';display:inline:margin: 0px 0px 0px 0px;" id="'+f+'Value" ></span>'),r.appendChild(a.li),a.li.appendChild(a.bullet),a.li.appendChild(a.label),a.li.appendChild(a.value),l[f]=a,a.li.style.display="none";this.list=r,this.seriesQueue=s,this.items=l,this.priceUpColor=t.priceUpColor,this.priceDownColor=t.priceDownColor,this.valueLabelFormat=t.valueLabelFormat,this.formatDate=t.formatDate,this._xy=e.DOM.getXY(this.contentDiv)},destroy:function(){this._removeChildren(this.list),this._removeChildren(this.contentDiv),this.contentDiv&&this.contentDiv.parentNode&&this.contentDiv.parentNode.removeChild(this.contentDiv)},_removeChildren:function(e){if(e&&e.hasChildNodes()){var t;while(e.firstChild)t=e.firstChild,this._removeChildren(t),e.removeChild(t)}},update:function(e,t,n){var r=this._xy,i=e-r[0],s=Math.floor(i/this.width*t.length);this._dataItem=t[s],n&&this.redraw()},redraw:function(){var t=
+this.seriesQueue,n,r=t.length,i,s=this.items,o,u,a=this.dateLabelFunction,f=this.dateLabelScope,l=this.dateLabelFormat,c,h=this._dataItem;if(h){u=h.Date||h.Timestamp,a&&(c=[u],l&&c.push(l),u=a.apply(f,c)),this.dateItem.value.innerHTML=e.Escape.html(u);for(o=0;o<r;o+=1)n=t[o],i=s[n],h.hasOwnProperty(n)?(i.li.style.display="inline-block",u=h[n],i.value.innerHTML=e.Number.format(parseFloat(u),this.valueLabelFormat),e.DOM.setStyle(i.value,"color",u>0?this.priceUpColor:this.priceDownColor)):i.li.style.display="none";h=this._dataItem=null}}},e.StockIndicatorsLegend=n,r.NAME="stockChart",r.ATTRS={charts:{},dataProvider:{lazyAdd:!1,getter:function(){return this._dataProvider},setter:function(e){return this._dataProvider=e,e}}},e.extend(r,e.Widget,{drawCharts:function(){var e=[],t=this.get("charts"),n=this.get("contentBox"),r,i=t.length;this._removeAll();for(r=0;r<i;r+=1)e[r]=this.drawChart(t[r],n);this._charts=e},updatesLegendsCrosshair:function(e){e.preventDefault();var t,n=this._crosshairs,r=this._legends,i=e&&e.hasOwnProperty("changedTouches"),s=i?e.changedTouches[0].pageX:e.pageX,o=i?e.changedTouches[0].pageY:e.pageY,u=n.length,a,f,l,c;if(s%1===0&&o%1===0&&this.curX!==s){for(c=0;c<u;c+=1)a=this._charts[c],f=a.xy,l=s-f[0],t=this._crosshairs[c],t.setTarget(s,this._autoDraw);u=r.length;for(c=0;c<u;c+=1)r[c].update(s,this._dataProvider,this._autoDraw)}this.curX=s},startTimeline:function(){this._runTimeline||(this._runTimeline=!0,this._timelineStart=(new Date).valueOf()-17,this.redraw())},stopTimeline:function(){var e,t=this._timelineId;this._runTimeline=!1,t&&(e=[t],this._timelineId=null)},redraw:function(){var e=this,t=this._crosshairs,n=this._legends,r,i=t.length,s=(new Date).valueOf();if(s>=this._timelineStart+17){for(r=0;r<i;r+=1)t[r].redraw();i=n.length;for(r=0;r<i;r+=1)n[r].redraw();this._timelineStart=(new Date).valueOf()}this._runTimeline&&!this._autoDraw&&(this._timelineId=this._onEnterFrame.apply(window,[function(){e.redraw()}]))},initializer:function(){var e=this.get("contentBox");e.setStyle("position","relative"),this._axes=[],this._graphs=[],this._graphics=[],this._crosshairs=[],this._hotspots=[],this._legends=[],this._runTimeline=!1,this._onEnterFrame=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame,this._autoDraw=this._onEnterFrame?!1:!0,r.superclass.initializer.apply(this,arguments)},_graphMap:{line:e.LineSeries,marker:e.MarkerSeries,column:e.ColumnSeries,candlestick:e.CandlestickSeries},_getGraph:function(e){return this._graphMap[e]},_getSeriesCollection:function(e){var t=[],n,r=e.indicators,i,s,o=r.length,u,a,f,l;for(s=0;s<o;s+=1){n=r[s],f=n.valueKey,i=n.type;if(i==="candlestick"||typeof f=="string")l=i!=="candlestick"&&i!=="line"&&n.groupMarkers,t.push({groupMarkers:l,type:n.type,xKey:e.categoryKey,yKey:n.valueKey});else{a=f.length;for(u=0;u<a;u+=1)i=n.type,l=i!=="line"&&n.groupMarkers,t.push({groupMarkers:l,type:typeof i=="string"?i:i[u],xKey:e.categoryKey,yKey:n.valueKey[u]})}}return t},_getSeriesStyles:function(e,t){var n,r=t.colors,i,s,o,u,a,f=e.length;for(a=0;a<f;a+=1){n=e[a];switch(n.type){case"line":n.styles={line:{weight:t.lineWidth,color:r[n.yKey]}};break;case"candlestick":n.styles={upcandle:{fill:{color:r.priceUp}},downcandle:{fill:{color:r.priceDown}}};break;case"marker":o=this.get("dataProvider"),i=Math.min(t.dotDiameter,t.width/o.length),n.styles={marker:{width:i,height:i,border:{color:r[n.yKey],weight:0},fill:{color:r[n.yKey]}}};break;case"column":o=this.get("dataProvider"),u=t.rangeType,s=t.width/o.length,s=Math.min(10,Math.round(s-s*.4)),s-=2,s=Math.max(1,s),n.styles={marker:{width:s,border:{weight:0},fill:{color:r[n.yKey]}}}}}return e},_drawGraphs:function(e,t,n){var r=this._getSeriesStyles(this._getSeriesCollection(e),e),i,s,o,u={},a=t.date,f=t.numeric,l,c,h=r.length;for(c=0;c<h;c+=1)i=r[c],i.xAxis=a,i.yAxis=f,i.graphic=n,l=this._getGraph(i.type),o=new l(i),o.draw(),s=i.yKey,typeof s!="string"&&(s="quote"),u[s]=o;return this._graphs.push(o),u},_drawGridlines:function(t,n,r){var i=r.get("width"),s=r.get("height"),o=new e.Gridlines({graphic:r,direction:"horizontal",axis:n.numeric}),u=new e.Gridlines({graphic:r,direction:"vertical",axis:n.date,styles:{fill:{color:t.gridColor},border:{weight:0}}});return o.draw(i,s),u.draw(i,s,t.rangeType==="intraday"?0:1),o._path.toBack(),u._path.toBack(),{horizontal:o,vertical:u}},_axesClassMap:{numeric:e.NumericAxis,numericbase:e.NumericAxisBase,category:e.CategoryAxis,categorybase:e.CategoryAxisBase},_drawAxes:function(e,t){var n,r,i=e.axes.numeric,s=e.axes.date,o,u,a=this._axesClassMap[i.type],f=this._axesClassMap[s.type];return i.render=t,i.y=e.y+e.legend.height,i.x=e.width-i.width,i.height=e.height-s.height-e.legend.height,s.render=t,s.y=e.y+e.height-s.height,s.width=e.width,o=new a(i),u=new f(s),r=u.get("boundingBox"),r.setStyle("left","0px"),r.setStyle("top",e.y+e.height-s.height+"px"),r=o.get("boundingBox"),r.setStyle("left",i.x+"px"),r.setStyle("top",e.y+e.legend.height+"px"),n={numeric:o,date:u},this._axes.push(n),n},_drawHotspot:function(t,n){var r=e.Node.create('<div class="yui3-hotspot" id="fincharthotspot_'+this._hotspots.length+'" style="width:'+t.width+"px;height:"+(t.height-t.legend.height-t.axes.date.height)+"px;position:absolute;left:0px;top:"+(t.y+t.legend.height)+'px;opacity:0;background:#fff;z-index:4"></div>');r.setStyle("opacity",0),n.append(r),this._hotspots.push(r)},_createGraphic:function(t,n){var r=new e.Graphic({render:n,width:this.get("width"),height:t.height-t.legend.height-t.axes.date.height,x:0,y:t.y+t.legend.height,autoDraw:!1});return this._graphics.push(r),r},_addCrosshair:function(t,n,r){var i,s=t.crosshair,o={stroke:{color:s.lineColor,weight:s.lineWidth}},u=[],a,f,l=t.colors;for(f in n)n.hasOwnProperty(f)&&(a=n[f],u.push({marker:{shape:"circle",width:s.dotDiameter,height:s.dotDiameter,fill:{color:l[f==="quote"?"close":f]},stroke:{weight:0}},coords:f==="quote"?a.get("ycoords").close:a.get("ycoords")}),o.coords=a.
+get("xcoords"));return i=new e.Crosshair({width:t.width,height:t.height-t.axes.date.height-t.legend.height,x:0,y:t.y+t.legend.height,render:r,series:u,category:o}),this._crosshairs.push(i),i},_addLegend:function(t,n){var r,i=t.legend;return i.colors=t.colors,i.render=n,i.y=t.y,r=new e.StockIndicatorsLegend(i),this._legends.push(r),r},drawChart:function(e,t){var n,r=this._drawAxes(e,t),i=this._createGraphic(e,t),s=this._drawGridlines(e,r,i),o=this._drawGraphs(e,r,i),u=this._drawHotspot(e,t),a=this._addCrosshair(e,o,t),f=this._addLegend(e,t);return n={axes:r,graphic:i,gridlines:s,graphs:o,hotspot:u,crosshair:a,legend:f,xy:i.getXY()},i._redraw(),n},_destroyCrosshairs:function(){var e,t=this._charts.length,n;while(this._crosshairs.length>0)n=this._crosshairs.pop(),n.destroy();for(e=0;e<t;e+=1)delete this._charts[e].crosshair},_destroyHotspots:function(){var e,t=this._charts.length,n;while(this._hotspots.length>0)n=this._hotspots.pop(),n.empty(),n.remove(!0);for(e=0;e<t;e+=1)delete this._charts[e].hotspot},_destroyAxes:function(){var e,t=this._charts.length,n;while(this._axes.length>0)n=this._axes.pop(),n.date.destroy(!0),n.numeric.destroy(!0);for(e=0;e<t;e+=1)delete this._charts[e].axes},_destroyGraphs:function(){var e,t=this._charts.length,n;while(this._graphs.length>0)n=this._graphs.pop(),n.destroy(!0);for(e=0;e<t;e+=1)delete this._charts[e].graph},_destroyLegends:function(){var e,t=this._charts.length,n;while(this._legends.length>0)n=this._legends.pop(),n.destroy();for(e=0;e<t;e+=1)delete this._charts[e].legend},_destroyGraphics:function(){var e,t=this._charts.length,n;while(this._graphics.length>0)n=this._graphics.pop(),n.destroy();for(e=0;e<t;e+=1)delete this._charts[e].graphic},_removeAll:function(){var e,t;if(this._charts){this._destroyCrosshairs(),this._destroyHotspots(),this._destroyLegends(),this._destroyGraphs(),this._destroyAxes(),this._destroyGraphics();while(this._charts.length>0){e=this._charts.pop();for(t in e)e.hasOwnProperty(t)&&delete e[t]}}},destructor:function(){this._removeAll()}}),e.StockIndicatorsChart=r,e.StockIndicatorsSpark=function(){return this._init.apply(this,arguments),this},e.StockIndicatorsSpark.prototype={_graphMap:{line:e.LineSeries,marker:e.MarkerSeries,column:e.ColumnSeries,area:e.AreaSeries},_styleMap:{line:"line",marker:"marker",column:"marker",area:"area"},_init:function(t){var n=t.styles,r=document.createElement("div"),i=document.createElement("div"),s=t.render,o=t.type||"line",u=o==="column"?"marker":o,a=this._graphMap[o];this.dataProvider=t.dataProvider,this.xKey=t.xKey,this.yKey=t.yKey,n||(n={},t[u]?n[u]=t[u]:(n[u]={},t.color&&(n.line.color=t.color),t.alpha&&(n.line.alpha=t.alpha),o==="line"&&(n.line.weight=isNaN(t.weight)?1:t.weight))),this.xAxis=new e.CategoryAxisBase({dataProvider:this.dataProvider,keys:[this.xKey]}),this.yAxis=new e.NumericAxisBase({dataProvider:this.dataProvider,keys:[this.yKey],alwaysShowZero:!1}),r.style.position="absolute",e.DOM.setStyle(r,"inlineBlock"),i.style.position="relative",s=document.getElementById(s),s.appendChild(r),r.appendChild(i),i.style.width=e.DOM.getComputedStyle(s,"width"),i.style.height=e.DOM.getComputedStyle(s,"height"),this.graphic=new e.Graphic({render:i,autoDraw:!1}),this.graph=new a({rendered:!0,dataProvider:t.dataProvider,graphic:this.graphic,styles:n,xAxis:this.xAxis,yAxis:this.yAxis,xKey:this.xKey,yKey:this.yKey}),this.contentBox=i,this.boundingBox=r,this.graph.validate(),this.graphic._redraw()},destroy:function(){var e;this.xAxis&&this.xAxis.destroy(!0),this.yAxis&&this.yAxis.destroy(!0),this.graph&&this.graph.destroy(),this.graphic&&this.graphic.destroy(),this.contentBox&&(e=this.contentBox.parentNode,e&&e.removeChild(this.contentBox)),this.boundingBox&&(e=this.boundingBox.parentNode,e&&e.removeChild(this.boundingBox))}}},"gallery-2014.01.28-00-45",{requires:["escape","graphics-group","axis-numeric","axis-category","series-line","series-marker","series-column","series-candlestick","series-area"]});
View
582 build/gallery-charts-stockindicators/gallery-charts-stockindicators.js
@@ -6,125 +6,31 @@ YUI.add('gallery-charts-stockindicators', function (Y, NAME) {
*
* @module gallery-charts-stockindicators
*/
-var defaultAxisLabelFormat = {
- value: null
-};
-
-Y.CategoryAxisBase.ATTRS.labelFormat = defaultAxisLabelFormat;
-Y.CategoryAxis.ATTRS.labelFormat = defaultAxisLabelFormat;
-//patch CartesianSeries destructor bug
-Y.CartesianSeries.prototype.destructor = function() {
- if(this.get("rendered"))
- {
- if(this._xDataReadyHandle)
- {
- this._xDataReadyHandle.detach();
- }
- if(this._xDataUpdateHandle)
- {
- this._xDataUpdateHandle.detach();
- }
- if(this._yDataReadyHandle)
- {
- this._yDataReadyHandle.detach();
- }
- if(this._yDataUpdateHandle)
- {
- this._yDataUpdateHandle.detach();
- }
- if(this._xAxisChangeHandle)
- {
- this._xAxisChangeHandle.detach();
- }
- if(this._yAxisChangeHandle)
- {
- this._yAxisChangeHandle.detach();
- }
- }
-};
-
-if(Y.VMLShape) {
- Y.VMLShape.ATTRS.stroke.setter = function(val) {
- var i,
- stroke,
- wt,
- tmpl = this.get("stroke") || this._getDefaultStroke();
- if(val)
- {
- if(val.hasOwnProperty("weight"))
- {
- wt = parseInt(val.weight, 10);
- if(!isNaN(wt))
- {
- val.weight = wt;
- }
- }
- for(i in val)
- {
- if(val.hasOwnProperty(i))
- {
- tmpl[i] = val[i];
- }
- }
- }
- if(tmpl.color && tmpl.color.toLowerCase().indexOf("rgba") > -1)
- {
- tmpl.opacity = Y.Color._getAlpha(tmpl.color);
- tmpl.color = Y.Color.toHex(tmpl.color);
- }
- stroke = tmpl;
- this._strokeFlag = true;
- return stroke;
- };
- Y.VMLShape.ATTRS.fill.setter = function(val) {
- var i,
- fill,
- tmpl = this.get("fill") || this._getDefaultFill();
-
- if(val)
- {
- //ensure, fill type is solid if color is explicitly passed.
- if(val.hasOwnProperty("color"))
- {
- val.type = "solid";
- }
- for(i in val)
- {
- if(val.hasOwnProperty(i))
- {
- tmpl[i] = val[i];
- }
- }
- }
- fill = tmpl;
- if(fill && fill.color)
- {
- if(fill.color === undefined || fill.color === "none")
- {
- fill.color = null;
- }
- else
- {
- if(fill.color.toLowerCase().indexOf("rgba") > -1)
- {
- fill.opacity = Y.Color._getAlpha(fill.color);
- fill.color = Y.Color.toHex(fill.color);
- }
- }
- }
- this._fillFlag = true;
- return fill;
- };
-}
+/**
+ * Provides functionality for a crosshair.
+ *
+ * @module gallery-charts-stockindicators
+ */
/**
* Creates an updatable crosshair on the Graph which can be controlled
* by mouse and touch events.
*
- * @module gallery-charts-stockindicators
* @class Crosshair
* @constructor
* @param {Object} config Configuration parameters.
+ * <dl>
+ * <dt>dotdiameter</dt><dd>The diameter of the circle or dot.</dd>
+ * <dt>drawHorizontal</dt><dd>Indicates whether to draw the horizontal line. The default
+ * value is `false`.</dd>
+ * <dt>drawVertical</dt><dd>Indicates whether to draw the verical line. The default
+ * value is `true`.</dd>
+ * <dt>lineColor</dt><dd>The color to use for lines.</dd>
+ * <dt>lineWidth</dt><dd>The weight of the lines.</dd>
+ * <dt>useCircle</dt><dd>Determines whether to use an empty circle. The default value is
+ * `false`.</dd>
+ * <dt>useDot</dt><dd>Determines whether to use a dot. The default value is `true`.</dd>
+ * </dl>
*/
Y.Crosshair = function() {
this.initializer.apply(this, arguments);
@@ -192,7 +98,7 @@ Y.Crosshair.prototype = {
* @method setTarget
* @param {Number} pageX The x-coordinate to map in which to map the crosshair.
*/
- setTarget: function(pageX) {
+ setTarget: function(pageX, redraw) {
var xy = this._xy,
x = pageX - xy[0],
y,
@@ -214,7 +120,22 @@ Y.Crosshair.prototype = {
}
}
}
- this.graphic._redraw();
+ this.updateFlag = true;
+ if(redraw) {
+ this.graphic._redraw();
+ }
+ },
+
+ /**
+ * Updates the crosshair items.
+ *
+ * @method redraw
+ */
+ redraw: function() {
+ if(this.updateFlag) {
+ this.graphic._redraw();
+ this.updateFlag = false;
+ }
},
/**
@@ -567,12 +488,52 @@ Y.Gridlines = Y.Base.create("gridlines", Y.Base, [Y.Renderer], {
}
});
/**
+ * Provides functionality for a legend.
+ *
+ * @module gallery-charts-stockindicators
+ */
+/**
* Displays a legend when the user interacts with the corresponding chart
* application.
*
- * @module gallery-charts-stockindicators
* @class StockIndicatorsLegend
* @constructor
+ * @param {Object} config Configuration parameters.
+ * <dl>
+ * <dt>dataProvider</dt><dd>Reference to the application's `dataProvider` attribute.</dd>
+ * <dt>dateColor</dt><dd>The color to be used for the date text in the legend.</dd>
+ * <dt>delim</dt><dd>String value prefixing the display name of each legend item.</dd>
+ * <dt>dateLabelFunction</dt><dd>The function used for formatting the date label.</dd>
+ * <dt>dateLabelFormat</dt><dd>The strf format used to format the date label.</dd>
+ * <dt>dateLabelScope</dt><dd>The scope for the dateLabelFunction</dd>
+ * <dt>displayKeys</dt><dd>An array of displayKeys to be used in the legend. Each display key
+ * is the text to be displayed in the legend for the corresponding value key.</dd>
+ * <dt>displayName</dt><dd>Indicates whether to display the display name. The default
+ * value is `true`.</dd>
+ * <dt>displayValue</dt><dd>Indicates whether to display the value. The default value
+ * is `true`.</dd>
+ * <dt>drawSwatch</dt><dd>Indicates whether or no to draw a colored swatch by the display
+ * name. The default value is `true`.</dd>
+ * <dt>font</dt><dd>The font to use for all text in the legend.</dd>
+ * <dt>fontSize</dt><dd>The font size to use for all text in the legend.</dd>
+ * <dt>height</dt><dd>The height of the legend.</dd>
+ * <dt>priceDownColor</dt><dd>The color to be used for the value text when the value is negative.</dd>
+ * <dt>priceUpColor</dt><dd>The color to be used for value text when the value is positive.</dd>
+ * <dt>swatchWidth</dt><dd>The width of the swatch for each legend item.</dd>
+ * <dt>valueKeys</dt><dd>The value keys, in order, to be used in the legend.</dd>
+ * <dt>valueLabelFormat</dt><dd>Object literal indicating how to format the legend values.
+ * <dl>
+ * <dt>prefix</dt><dd>The prefix.</dd>
+ * <dt>suffix</dt><dd>The suffix.</dd>
+ * <dt>thousandsSeparator</dt><dd>The thousands separator.</dd>
+ * <dt>decimalPlaces</dt><dd>The number of decimals to display.</dd>
+ * <dt>decimalsSeparator</dt><dd>The decimal separator.</dd>
+ * </dl>
+ * </dd>
+ * <dt>width</dt><dd>The width of the legend.</dd>
+ * <dt>x</dt><dd>The x-coordinate for the legend</dd>
+ * <dt>y</dt><dd>The y-coordinate for the legend</dd>
+ * </dl>
*/
function StockIndicatorsLegend() {
this.init.apply(this, arguments);
@@ -655,7 +616,7 @@ StockIndicatorsLegend.prototype = {
this.formatDate = cfg.formatDate;
this._xy = Y.DOM.getXY(this.contentDiv);
},
-
+
/**
* Removes all elements of the legend.
*
@@ -689,7 +650,7 @@ StockIndicatorsLegend.prototype = {
}
}
},
-
+
/**
* Updates the legend.
*
@@ -697,12 +658,24 @@ StockIndicatorsLegend.prototype = {
* @param {Number} pageX
* @param {Array} dataProvider
*/
- update: function(pageX, dataProvider) {
+ update: function(pageX, dataProvider, redraw) {
var xy = this._xy,
x = pageX - xy[0],
- index = Math.floor(x / this.width * dataProvider.length),
- dataItem = dataProvider[index],
- queue = this.seriesQueue,
+ index = Math.floor(x / this.width * dataProvider.length);
+ this._dataItem = dataProvider[index];
+ if(redraw) {
+ this.redraw();
+ }
+ },
+
+
+ /**
+ * Draws the legend.
+ *
+ * @method redraw
+ */
+ redraw: function() {
+ var queue = this.seriesQueue,
key,
len = queue.length,
item,
@@ -712,38 +685,48 @@ StockIndicatorsLegend.prototype = {
dateLabelFunction = this.dateLabelFunction,
dateLabelScope = this.dateLabelScope,
dateLabelFormat = this.dateLabelFormat,
- dateLabelArgs;
- val = dataItem.Date || dataItem.Timestamp;
- if(dateLabelFunction) {
- dateLabelArgs = [val];
- if(dateLabelFormat) {
- dateLabelArgs.push(dateLabelFormat);
+ dateLabelArgs,
+ dataItem = this._dataItem;
+ if(dataItem) {
+ val = dataItem.Date || dataItem.Timestamp;
+ if(dateLabelFunction) {
+ dateLabelArgs = [val];
+ if(dateLabelFormat) {
+ dateLabelArgs.push(dateLabelFormat);
+ }
+ val = dateLabelFunction.apply(dateLabelScope, dateLabelArgs);
}
- val = dateLabelFunction.apply(dateLabelScope, dateLabelArgs);
- }
- this.dateItem.value.innerHTML = Y.Escape.html(val);
- for(i = 0; i < len; i = i + 1) {
- key = queue[i];
- item = items[key];
- if(dataItem.hasOwnProperty(key)) {
- item.li.style.display = "inline-block";
- val = dataItem[key];
- item.value.innerHTML = Y.Number.format(parseFloat(val), this.valueLabelFormat);
- Y.DOM.setStyle(item.value, "color", val > 0 ? this.priceUpColor : this.priceDownColor);
- } else {
- item.li.style.display = "none";
+ this.dateItem.value.innerHTML = Y.Escape.html(val);
+ for(i = 0; i < len; i = i + 1) {
+ key = queue[i];
+ item = items[key];
+ if(dataItem.hasOwnProperty(key)) {
+ item.li.style.display = "inline-block";
+ val = dataItem[key];
+ item.value.innerHTML = Y.Number.format(parseFloat(val), this.valueLabelFormat);
+ Y.DOM.setStyle(item.value, "color", val > 0 ? this.priceUpColor : this.priceDownColor);
+ } else {
+ item.li.style.display = "none";
+ }
}
+ dataItem = this._dataItem = null;
}
}
};
Y.StockIndicatorsLegend = StockIndicatorsLegend;
/**
+ * Provides functionality for a chart.
+ *
+ * @module gallery-charts-stockindicators
+ */
+
+/**
* StockIndicatorsChart is an application that generates a chart or charts based on a key indexed array of data and an
* array of charts configuration data.
*
- * @module gallery-charts-stockindicators
* @class StockIndicatorsChart
* @constructor
+ * @param {Object} config An object literal contain properties defined in the <a href="#attr_charts">charts</a> attribute.
*/
function StockIndicatorsChart() {
StockIndicatorsChart.superclass.constructor.apply(this, arguments);
@@ -758,8 +741,12 @@ StockIndicatorsChart.ATTRS = {
* An object literal representing the `axes` for the chart. Each `axes` object contains a `date`
* and a `numeric` axis.
* <dl>
- * <dt>date</dt>The date axis is a `CategoryAxis` instance.
- * <dt>numeric</dt> The numeric axis is a `NumericAxis` instance.
+ * <dt>date</dt><dd>A <a href="http://yuilibrary.com/yui/docs/api/classes/CategoryAxis.html">CategoryAxis</a>
+ * instance. Possible attributes are listed
+ * <a href="http://yuilibrary.com/yui/docs/api/classes/CategoryAxis.html#attr_appendLabelFunction">here</a>.</dd>
+ * <dt>numeric</dt><dd>A <a href="http://yuilibrary.com/yui/docs/api/classes/NumericAxis.html">NumericAxis</a>
+ * instance. Possible attributes are listed
+ * <a href="http://yuilibrary.com/yui/docs/api/classes/NumericAxis.html#attr_alwaysShowZero">here</a>.</dd>
* </dl>
* </dd>
* <dt>categoryKey</dt><dd>A reference to the key in the `dataProvider` that represents the values
@@ -767,24 +754,11 @@ StockIndicatorsChart.ATTRS = {
* <dt>colors</dt><dd>An object containing key values pairs in which the key is a reference to the values
* of the `dataProvider` and the value is the color associated with each key. This data is used to determine
* the colors for the corresponding graphs, legends and crosshair markers.</dd>
- * <dt>crosshair</dt><dd>Configuration properties for the crosshair display that shows when
+ * <dt>crosshair</dt><dd>Configuration properties for the <a href="Crosshair.html">Crosshair</a> display that shows when
* interacting with a chart. It consists of `marker` shapes that correspond with each series of the
* chart, and optional horizontal and vertical lines. By default, the vertical line is displayed and
* the horizontal line is not. The colors of each `marker` is determined by its corresponding series
- * color. The crosshairConfig object has the following configurable properties:
- * <dl>
- * <dt>dotdiameter</dt><dd>The diameter of the circle or dot.</dd>
- * <dt>drawHorizontal</dt><dd>Indicates whether to draw the horizontal line. The default
- * value is `false`.</dd>
- * <dt>drawVertical</dt><dd>Indicates whether to draw the verical line. The default
- * value is `true`.</dd>
- * <dt>lineColor</dt><dd>The color to use for lines.</dd>
- * <dt>lineWidth</dt><dd>The weight of the lines.</dd>
- * <dt>useCircle</dt><dd>Determines whether to use an empty circle. The default value is
- * `false`.</dd>
- * <dt>useDot</dt><dd>Determines whether to use a dot. The default value is `true`.</dd>
- * </dl>
- * </dd>
+ * color. Possible configuration values are documented <a href="Crosshair.html">here</a>.</dd>
* <dt>dotdiameter</dt><dd>The diameter to be used for marker graphs in the chart.</dd>
* <dt>gridcolor</dt><dd>The color to be used for the background grid of the chart.</dd>
* <dt>height</dt><dd>The height of the chart including the legend, graph and date axis.</dd>
@@ -796,9 +770,11 @@ StockIndicatorsChart.ATTRS = {
* <dt>currency</dt><dd>Reference to the currency used to measure the data.</dd>
* <dt>displayKey</dt><dd>A key or array of keys, depending on the indicator mapped to a valueKey
* from the `dataProvider` that will be displayed in the corresponding legend.</dd>
+ * <dt>groupMarkers</dt><dd>Indicates whether to draw all markers as a single dom element.</dd>
* <dt>indicator</dt><dd>Represents the type of indicator data that will be displayed. (e.g. `quote`,
* `bollinger`, `psar`)</dd>
* <dt>iscomp</dt><dd>Indicates whether the indicator is a comparison indicator.</dd>
+ * <dt>labels</dt><dd>An array of of values used to create labels on the x-axis.</dd>
* <dt>ticker</dt><dd>Indicates the stock ticker of the indicator. (e.g. `yhoo`)</dd>
* <dt>type</dt><dd>Indicates the type of financial graph used to display the indicator data.
* (e.g. `candlestick`, `line`)
@@ -806,38 +782,9 @@ StockIndicatorsChart.ATTRS = {
* values from the `dataProvider`.</dd>
* </dl>
* </dd>
- * <dt>legend</dt><dd>
- * <dl>
- * <dt>currency</dt><dd>The prefix to be used for the values in each legend item.</dd>
- * <dt>dataProvider</dt><dd>Reference to the application's `dataProvider` attribute.</dd>
- * <dt>dateColor</dt><dd>The color to be used for the date text in the legend.</dd>
- * <dt>delim</dt><dd>String value prefixing the display name of each legend item.</dd>
- * <dt>displayKeys</dt><dd>An array of displayKeys to be used in the legend. Each display key
- * is the text to be displayed in the legend for the corresponding value key.</dd>
- * <dt>dislayName</dt><dd>Indicates whether to display the display name. The default
- * value is `true`.</dd>
- * <dt>displayValue</dt><dd>Indicates whether to display the value. The default value
- * is `true`.</dd>
- * <dt>drawSwatch</dt><dd>Indicates whether or no to draw a colored swatch by the display
- * name. The default value is `true`.</dd>
- * <dt>font</dt><dd>The font to use for all text in the legend.</dd>
- * <dt>fontSize</dt><dd>The font size to use for all text in the legend.</dd>
- * <dt>height</dt><dd>The height of the legend.</dd>
- * <dt>priceDownColor</dt><dd>The color to be used for the value text when the value is negative.</dd>
- * <dt>priceUpColor</dt><dd>The color to be used for value text when the value is positive.</dd>
- * <dt>swatchWidth</dt><dd>The width of the swatch for each legend item.</dd>
- * <dt>valueKeys</dt><dd>The value keys, in order, to be used in the legend.</dd>
- * <dt>valueLabelFormat</dt><dd>Object literal indicating how to format the legend values.
- * <dl>
- * <dt>prefix</dt><dd>The prefix.</dd>
- * <dt>suffix</dt><dd>The suffix.</dd>
- * <dt>thousandsSeparator</dt><dd>The thousands separator.</dd>
- * <dt>decimalPlaces</dt><dd>The number of decimals to display.</dd>
- * <dt>decimalsSeparator</dt><dd>The decimal separator.</dd>
- * </dl>
- * </dd>
- * </dl>
- * </dd>
+ * <dt>legend</dt><dd>Configuration properties used to construct the <a href="StockIndicatorsLegend.html">StockIndicatorsLegend</a>.
+ * Possible configuration values are documented <a href="StockIndicatorsLegend.html">here</a>. The x and y properties are not
+ * configurable through this object as they are determined by the layout of the charts in this application. </dd>
* <dt>lineWidth</dt><dd>The weight to be used for line graphs in the chart.</dd>
* <dt>numBar</dt><dd>The value used to calculate the width of the columns in a graph when the `rangeType` is
* `daily`. By default, the column width is determined from number of data values across the x axis and the
@@ -852,7 +799,7 @@ StockIndicatorsChart.ATTRS = {
* <dt>y</dt><dd>The y coordinate for the chart in relation to the application.</dd>
* </dl>
*
- * @attribute chartsData
+ * @attribute charts
* @type: Array
*/
charts: {},
@@ -903,6 +850,7 @@ Y.extend(StockIndicatorsChart, Y.Widget, {
* @param {Object} e Event payload
*/
updatesLegendsCrosshair: function(e) {
+ e.preventDefault();
var crosshair,
crosshairs = this._crosshairs,
legends = this._legends,
@@ -920,17 +868,74 @@ Y.extend(StockIndicatorsChart, Y.Widget, {
xy = chart.xy,
x = pageX - xy[0];
crosshair = this._crosshairs[i];
- crosshair.setTarget(pageX);
+ crosshair.setTarget(pageX, this._autoDraw);
}
len = legends.length;
for(i = 0; i < len; i = i + 1) {
- legends[i].update(pageX, this._dataProvider);
+ legends[i].update(pageX, this._dataProvider, this._autoDraw);
}
}
this.curX = pageX;
},
/**
+ * Starts a timeline used to manage redraws based on requestAnimationFrame.
+ *
+ * @method startTimeline
+ */
+ startTimeline: function() {
+ if(!this._runTimeline) {
+ this._runTimeline = true;
+ this._timelineStart = (new Date()).valueOf() - 17;
+ this.redraw();
+ }
+ },
+
+ /**
+ * Ends a timeline.
+ *
+ * @method stopTimeline
+ */
+ stopTimeline: function() {
+ var args,
+ timelineId = this._timelineId;
+ this._runTimeline = false;
+ if(timelineId) {
+ args = [timelineId];
+ this._timelineId = null;
+ }
+ },
+
+ /**
+ * Draws chart elements based on the timeline.
+ *
+ * @method redraw
+ */
+ redraw: function() {
+ var scope = this,
+ crosshairs = this._crosshairs,
+ legends = this._legends,
+ i,
+ len = crosshairs.length,
+ endTime = (new Date()).valueOf();
+ if(endTime >= this._timelineStart + 17) {
+ for(i = 0; i < len; i = i + 1) {
+ crosshairs[i].redraw();
+ }
+ len = legends.length;
+ for(i = 0; i < len; i = i + 1) {
+ legends[i].redraw();
+ }
+ this._timelineStart = (new Date()).valueOf();
+ }
+ if(this._runTimeline && !this._autoDraw) {
+ this._timelineId = this._onEnterFrame.apply(window, [function() {
+ scope.redraw();
+ }]);
+ }
+ },
+
+ /**
*
*/
initializer: function() {
@@ -942,6 +947,12 @@ Y.extend(StockIndicatorsChart, Y.Widget, {
this._crosshairs = [];
this._hotspots = [];
this._legends = [];
+ this._runTimeline = false;
+ this._onEnterFrame = window.requestAnimationFrame ||
+ window.mozRequestAnimationFrame ||
+ window.webkitRequestAnimationFrame ||
+ window.msRequestAnimationFrame;
+ this._autoDraw = this._onEnterFrame ? false : true;
StockIndicatorsChart.superclass.initializer.apply(this, arguments);
},
@@ -990,12 +1001,18 @@ Y.extend(StockIndicatorsChart, Y.Widget, {
indLen = indicators.length,
valueIter,
valueLen,
- valueKey;
+ valueKey,
+ groupMarkers;
for(indIter = 0; indIter < indLen; indIter = indIter + 1) {
indicator = indicators[indIter];
valueKey = indicator.valueKey;
- if(indicator.type === "candlestick" || typeof valueKey === "string") {
+ indicatorType = indicator.type;
+ if(indicatorType === "candlestick" || typeof valueKey === "string") {
+ groupMarkers = indicatorType !== "candlestick" &&
+ indicatorType !== "line" &&
+ indicator.groupMarkers;
seriesCollection.push({
+ groupMarkers: groupMarkers,
type: indicator.type,
xKey: config.categoryKey,
yKey: indicator.valueKey
@@ -1004,7 +1021,9 @@ Y.extend(StockIndicatorsChart, Y.Widget, {
valueLen = valueKey.length;
for(valueIter = 0; valueIter < valueLen; valueIter = valueIter + 1) {
indicatorType = indicator.type;
+ groupMarkers = indicatorType !== "line" && indicator.groupMarkers;
seriesCollection.push({
+ groupMarkers: groupMarkers,
type: typeof indicatorType === "string" ? indicatorType : indicatorType[valueIter],
xKey: config.categoryKey,
yKey: indicator.valueKey[valueIter]
@@ -1183,6 +1202,20 @@ Y.extend(StockIndicatorsChart, Y.Widget, {
};
},
+ /**
+ * Maps axis class to key.
+ *
+ * @property _axesClassMap
+ * @type AxisBase
+ * @private
+ */
+ _axesClassMap: {
+ numeric: Y.NumericAxis,
+ numericbase: Y.NumericAxisBase,
+ category: Y.CategoryAxis,
+ categorybase: Y.CategoryAxisBase
+ },
+
/**
* Add the axes to the chart and returns an object literal with references to the
* `date` and `numeric` axes.
@@ -1199,7 +1232,9 @@ Y.extend(StockIndicatorsChart, Y.Widget, {
numericConfig = config.axes.numeric,
dateConfig = config.axes.date,
numericAxis,
- dateAxis;
+ dateAxis,
+ NumericClass = this._axesClassMap[numericConfig.type],
+ DateClass = this._axesClassMap[dateConfig.type];
numericConfig.render = cb;
numericConfig.y = config.y + config.legend.height;
numericConfig.x = config.width - numericConfig.width;
@@ -1207,8 +1242,8 @@ Y.extend(StockIndicatorsChart, Y.Widget, {
dateConfig.render = cb;
dateConfig.y = config.y + config.height - dateConfig.height;
dateConfig.width = config.width;
- numericAxis = new Y.NumericAxis(numericConfig);
- dateAxis = new Y.CategoryAxis(dateConfig);
+ numericAxis = new NumericClass(numericConfig);
+ dateAxis = new DateClass(dateConfig);
bb = dateAxis.get("boundingBox");
bb.setStyle("left", 0 + "px");
bb.setStyle("top", (config.y + config.height - dateConfig.height) + "px");
@@ -1479,16 +1514,165 @@ Y.extend(StockIndicatorsChart, Y.Widget, {
}
});
Y.StockIndicatorsChart = StockIndicatorsChart;
+/**
+ * Creates a spark graph.
+ *
+ * @module gallery-charts-stockindicators
+ * @class StockIndicatorsSpark
+ * @constructor
+ */
+Y.StockIndicatorsSpark = function() {
+ this._init.apply(this, arguments);
+ return this;
+};
+
+Y.StockIndicatorsSpark.prototype = {
+ /**
+ * Maps keys to corresponding class.
+ *
+ * @property _graphMap
+ * @type Object
+ * @private
+ */
+ _graphMap: {
+ line: Y.LineSeries,
+ marker: Y.MarkerSeries,
+ column: Y.ColumnSeries,
+ area: Y.AreaSeries
+ },
+
+ /**
+ * Maps keys to the property of a style attribute
+ * of the corresponding `SeriesBase` instance.
+ *
+ * @property _styleMap
+ * @type Object
+ * @private
+ */
+ _styleMap: {
+ line: "line",
+ marker: "marker",
+ column: "marker",
+ area: "area"
+ },
+
+ /**
+ * Sets properties for the graph.
+ *
+ * @method _init
+ * @param {Object} config Properties for the graph.
+ * @private
+ */
+ _init: function(config) {
+ var styles = config.styles,
+ bb = document.createElement('div'),
+ cb = document.createElement('div'),
+ render = config.render,
+ type = config.type || "line",
+ style = type === "column" ? "marker" : type,
+ SparkClass = this._graphMap[type];
+ this.dataProvider = config.dataProvider;
+ this.xKey = config.xKey;
+ this.yKey = config.yKey;
+ if(!styles) {
+ styles = {};
+ if(config[style]) {
+ styles[style] = config[style];
+ } else {
+ styles[style] = {};
+ if(config.color) {
+ styles.line.color = config.color;
+ }
+ if(config.alpha) {
+ styles.line.alpha = config.alpha;
+ }
+ if(type === "line") {
+ styles.line.weight = isNaN(config.weight) ? 1 : config.weight;
+ }
+ }
+ }
+ this.xAxis = new Y.CategoryAxisBase({
+ dataProvider: this.dataProvider,
+ keys: [this.xKey]
+ });
+ this.yAxis = new Y.NumericAxisBase({
+ dataProvider: this.dataProvider,
+ keys: [this.yKey],
+ alwaysShowZero: false
+ });
+ bb.style.position = "absolute";
+ Y.DOM.setStyle(bb, "inlineBlock");
+ cb.style.position = "relative";
+ render = document.getElementById(render);
+ render.appendChild(bb);
+ bb.appendChild(cb);
+ cb.style.width = Y.DOM.getComputedStyle(render, "width");
+ cb.style.height = Y.DOM.getComputedStyle(render, "height");
+ this.graphic = new Y.Graphic({
+ render: cb,
+ autoDraw: false
+ });
+ this.graph = new SparkClass({
+ rendered: true,
+ dataProvider: config.dataProvider,
+ graphic: this.graphic,
+ styles: styles,
+ xAxis: this.xAxis,
+ yAxis: this.yAxis,
+ xKey: this.xKey,
+ yKey: this.yKey
+ });
+ this.contentBox = cb;
+ this.boundingBox = bb;
+ this.graph.validate();
+ this.graphic._redraw();
+ },
+
+ /**
+ * Removes all elements of the spark.
+ *
+ * @method destroy
+ */
+ destroy: function() {
+ var parentNode;
+ if(this.xAxis) {
+ this.xAxis.destroy(true);
+ }
+ if(this.yAxis) {
+ this.yAxis.destroy(true);
+ }
+ if(this.graph) {
+ this.graph.destroy();
+ }
+ if(this.graphic) {
+ this.graphic.destroy();
+ }
+ if(this.contentBox) {
+ parentNode = this.contentBox.parentNode;
+ if(parentNode) {
+ parentNode.removeChild(this.contentBox);
+ }
+ }
+ if(this.boundingBox) {
+ parentNode = this.boundingBox.parentNode;
+ if(parentNode) {
+ parentNode.removeChild(this.boundingBox);
+ }
+ }
+ }
+};
-}, 'gallery-2013.12.20-18-06', {
+}, 'gallery-2014.01.28-00-45', {
"requires": [
+ "escape",
"graphics-group",
"axis-numeric",
"axis-category",
"series-line",
"series-marker",
"series-column",
- "series-candlestick"
+ "series-candlestick",
+ "series-area"
]
});
View
3  src/gallery-charts-stockindicators/build.json
@@ -6,7 +6,8 @@
"Crosshair.js",
"Gridlines.js",
"StockIndicatorsLegend.js",
- "StockIndicatorsChart.js"
+ "StockIndicatorsChart.js",
+ "StockIndicatorsSpark.js"
]
}
}
View
147 src/gallery-charts-stockindicators/js/Crosshair.js
@@ -4,125 +4,31 @@
*
* @module gallery-charts-stockindicators
*/
-var defaultAxisLabelFormat = {
- value: null
-};
-
-Y.CategoryAxisBase.ATTRS.labelFormat = defaultAxisLabelFormat;
-Y.CategoryAxis.ATTRS.labelFormat = defaultAxisLabelFormat;
-//patch CartesianSeries destructor bug
-Y.CartesianSeries.prototype.destructor = function() {
- if(this.get("rendered"))
- {
- if(this._xDataReadyHandle)
- {
- this._xDataReadyHandle.detach();
- }
- if(this._xDataUpdateHandle)
- {
- this._xDataUpdateHandle.detach();
- }
- if(this._yDataReadyHandle)
- {
- this._yDataReadyHandle.detach();
- }
- if(this._yDataUpdateHandle)
- {
- this._yDataUpdateHandle.detach();
- }
- if(this._xAxisChangeHandle)
- {
- this._xAxisChangeHandle.detach();
- }
- if(this._yAxisChangeHandle)
- {
- this._yAxisChangeHandle.detach();
- }
- }
-};
-
-if(Y.VMLShape) {
- Y.VMLShape.ATTRS.stroke.setter = function(val) {
- var i,
- stroke,
- wt,
- tmpl = this.get("stroke") || this._getDefaultStroke();
- if(val)
- {
- if(val.hasOwnProperty("weight"))
- {
- wt = parseInt(val.weight, 10);
- if(!isNaN(wt))
- {
- val.weight = wt;
- }
- }
- for(i in val)
- {
- if(val.hasOwnProperty(i))
- {
- tmpl[i] = val[i];
- }
- }
- }
- if(tmpl.color && tmpl.color.toLowerCase().indexOf("rgba") > -1)
- {
- tmpl.opacity = Y.Color._getAlpha(tmpl.color);
- tmpl.color = Y.Color.toHex(tmpl.color);
- }
- stroke = tmpl;
- this._strokeFlag = true;
- return stroke;
- };
- Y.VMLShape.ATTRS.fill.setter = function(val) {
- var i,
- fill,
- tmpl = this.get("fill") || this._getDefaultFill();
-
- if(val)
- {
- //ensure, fill type is solid if color is explicitly passed.
- if(val.hasOwnProperty("color"))
- {
- val.type = "solid";
- }
- for(i in val)
- {
- if(val.hasOwnProperty(i))
- {
- tmpl[i] = val[i];
- }
- }
- }
- fill = tmpl;
- if(fill && fill.color)
- {
- if(fill.color === undefined || fill.color === "none")
- {
- fill.color = null;
- }
- else
- {
- if(fill.color.toLowerCase().indexOf("rgba") > -1)
- {
- fill.opacity = Y.Color._getAlpha(fill.color);
- fill.color = Y.Color.toHex(fill.color);
- }
- }
- }
- this._fillFlag = true;
- return fill;
- };
-}
+/**
+ * Provides functionality for a crosshair.
+ *
+ * @module gallery-charts-stockindicators
+ */
/**
* Creates an updatable crosshair on the Graph which can be controlled
* by mouse and touch events.
*
- * @module gallery-charts-stockindicators
* @class Crosshair
* @constructor
* @param {Object} config Configuration parameters.
+ * <dl>
+ * <dt>dotdiameter</dt><dd>The diameter of the circle or dot.</dd>
+ * <dt>drawHorizontal</dt><dd>Indicates whether to draw the horizontal line. The default
+ * value is `false`.</dd>
+ * <dt>drawVertical</dt><dd>Indicates whether to draw the verical line. The default
+ * value is `true`.</dd>
+ * <dt>lineColor</dt><dd>The color to use for lines.</dd>
+ * <dt>lineWidth</dt><dd>The weight of the lines.</dd>
+ * <dt>useCircle</dt><dd>Determines whether to use an empty circle. The default value is
+ * `false`.</dd>
+ * <dt>useDot</dt><dd>Determines whether to use a dot. The default value is `true`.</dd>
+ * </dl>
*/
Y.Crosshair = function() {
this.initializer.apply(this, arguments);
@@ -190,7 +96,7 @@ Y.Crosshair.prototype = {
* @method setTarget
* @param {Number} pageX The x-coordinate to map in which to map the crosshair.
*/
- setTarget: function(pageX) {
+ setTarget: function(pageX, redraw) {
var xy = this._xy,
x = pageX - xy[0],
y,
@@ -212,7 +118,22 @@ Y.Crosshair.prototype = {
}
}
}
- this.graphic._redraw();
+ this.updateFlag = true;
+ if(redraw) {
+ this.graphic._redraw();
+ }
+ },
+
+ /**
+ * Updates the crosshair items.
+ *
+ * @method redraw
+ */
+ redraw: function() {
+ if(this.updateFlag) {
+ this.graphic._redraw();
+ this.updateFlag = false;
+ }
},
/**
View
174 src/gallery-charts-stockindicators/js/StockIndicatorsChart.js
@@ -1,10 +1,16 @@
/**
+ * Provides functionality for a chart.
+ *
+ * @module gallery-charts-stockindicators
+ */
+
+/**
* StockIndicatorsChart is an application that generates a chart or charts based on a key indexed array of data and an
* array of charts configuration data.
*
- * @module gallery-charts-stockindicators
* @class StockIndicatorsChart
* @constructor
+ * @param {Object} config An object literal contain properties defined in the <a href="#attr_charts">charts</a> attribute.
*/
function StockIndicatorsChart() {
StockIndicatorsChart.superclass.constructor.apply(this, arguments);
@@ -19,8 +25,12 @@ StockIndicatorsChart.ATTRS = {
* An object literal representing the `axes` for the chart. Each `axes` object contains a `date`
* and a `numeric` axis.
* <dl>
- * <dt>date</dt>The date axis is a `CategoryAxis` instance.
- * <dt>numeric</dt> The numeric axis is a `NumericAxis` instance.
+ * <dt>date</dt><dd>A <a href="http://yuilibrary.com/yui/docs/api/classes/CategoryAxis.html">CategoryAxis</a>
+ * instance. Possible attributes are listed
+ * <a href="http://yuilibrary.com/yui/docs/api/classes/CategoryAxis.html#attr_appendLabelFunction">here</a>.</dd>
+ * <dt>numeric</dt><dd>A <a href="http://yuilibrary.com/yui/docs/api/classes/NumericAxis.html">NumericAxis</a>
+ * instance. Possible attributes are listed
+ * <a href="http://yuilibrary.com/yui/docs/api/classes/NumericAxis.html#attr_alwaysShowZero">here</a>.</dd>
* </dl>
* </dd>
* <dt>categoryKey</dt><dd>A reference to the key in the `dataProvider` that represents the values
@@ -28,24 +38,11 @@ StockIndicatorsChart.ATTRS = {
* <dt>colors</dt><dd>An object containing key values pairs in which the key is a reference to the values
* of the `dataProvider` and the value is the color associated with each key. This data is used to determine
* the colors for the corresponding graphs, legends and crosshair markers.</dd>
- * <dt>crosshair</dt><dd>Configuration properties for the crosshair display that shows when
+ * <dt>crosshair</dt><dd>Configuration properties for the <a href="Crosshair.html">Crosshair</a> display that shows when
* interacting with a chart. It consists of `marker` shapes that correspond with each series of the
* chart, and optional horizontal and vertical lines. By default, the vertical line is displayed and
* the horizontal line is not. The colors of each `marker` is determined by its corresponding series
- * color. The crosshairConfig object has the following configurable properties:
- * <dl>
- * <dt>dotdiameter</dt><dd>The diameter of the circle or dot.</dd>
- * <dt>drawHorizontal</dt><dd>Indicates whether to draw the horizontal line. The default
- * value is `false`.</dd>
- * <dt>drawVertical</dt><dd>Indicates whether to draw the verical line. The default
- * value is `true`.</dd>
- * <dt>lineColor</dt><dd>The color to use for lines.</dd>
- * <dt>lineWidth</dt><dd>The weight of the lines.</dd>
- * <dt>useCircle</dt><dd>Determines whether to use an empty circle. The default value is
- * `false`.</dd>
- * <dt>useDot</dt><dd>Determines whether to use a dot. The default value is `true`.</dd>
- * </dl>
- * </dd>
+ * color. Possible configuration values are documented <a href="Crosshair.html">here</a>.</dd>
* <dt>dotdiameter</dt><dd>The diameter to be used for marker graphs in the chart.</dd>
* <dt>gridcolor</dt><dd>The color to be used for the background grid of the chart.</dd>
* <dt>height</dt><dd>The height of the chart including the legend, graph and date axis.</dd>
@@ -57,9 +54,11 @@ StockIndicatorsChart.ATTRS = {
* <dt>currency</dt><dd>Reference to the currency used to measure the data.</dd>
* <dt>displayKey</dt><dd>A key or array of keys, depending on the indicator mapped to a valueKey
* from the `dataProvider` that will be displayed in the corresponding legend.</dd>
+ * <dt>groupMarkers</dt><dd>Indicates whether to draw all markers as a single dom element.</dd>
* <dt>indicator</dt><dd>Represents the type of indicator data that will be displayed. (e.g. `quote`,
* `bollinger`, `psar`)</dd>
* <dt>iscomp</dt><dd>Indicates whether the indicator is a comparison indicator.</dd>
+ * <dt>labels</dt><dd>An array of of values used to create labels on the x-axis.</dd>
* <dt>ticker</dt><dd>Indicates the stock ticker of the indicator. (e.g. `yhoo`)</dd>
* <dt>type</dt><dd>Indicates the type of financial graph used to display the indicator data.
* (e.g. `candlestick`, `line`)
@@ -67,38 +66,9 @@ StockIndicatorsChart.ATTRS = {
* values from the `dataProvider`.</dd>
* </dl>
* </dd>
- * <dt>legend</dt><dd>
- * <dl>
- * <dt>currency</dt><dd>The prefix to be used for the values in each legend item.</dd>
- * <dt>dataProvider</dt><dd>Reference to the application's `dataProvider` attribute.</dd>
- * <dt>dateColor</dt><dd>The color to be used for the date text in the legend.</dd>
- * <dt>delim</dt><dd>String value prefixing the display name of each legend item.</dd>
- * <dt>displayKeys</dt><dd>An array of displayKeys to be used in the legend. Each display key
- * is the text to be displayed in the legend for the corresponding value key.</dd>
- * <dt>dislayName</dt><dd>Indicates whether to display the display name. The default
- * value is `true`.</dd>
- * <dt>displayValue</dt><dd>Indicates whether to display the value. The default value
- * is `true`.</dd>
- * <dt>drawSwatch</dt><dd>Indicates whether or no to draw a colored swatch by the display
- * name. The default value is `true`.</dd>
- * <dt>font</dt><dd>The font to use for all text in the legend.</dd>
- * <dt>fontSize</dt><dd>The font size to use for all text in the legend.</dd>
- * <dt>height</dt><dd>The height of the legend.</dd>
- * <dt>priceDownColor</dt><dd>The color to be used for the value text when the value is negative.</dd>
- * <dt>priceUpColor</dt><dd>The color to be used for value text when the value is positive.</dd>
- * <dt>swatchWidth</dt><dd>The width of the swatch for each legend item.</dd>
- * <dt>valueKeys</dt><dd>The value keys, in order, to be used in the legend.</dd>
- * <dt>valueLabelFormat</dt><dd>Object literal indicating how to format the legend values.
- * <dl>
- * <dt>prefix</dt><dd>The prefix.</dd>
- * <dt>suffix</dt><dd>The suffix.</dd>
- * <dt>thousandsSeparator</dt><dd>The thousands separator.</dd>
- * <dt>decimalPlaces</dt><dd>The number of decimals to display.</dd>
- * <dt>decimalsSeparator</dt><dd>The decimal separator.</dd>
- * </dl>
- * </dd>
- * </dl>
- * </dd>
+ * <dt>legend</dt><dd>Configuration properties used to construct the <a href="StockIndicatorsLegend.html">StockIndicatorsLegend</a>.
+ * Possible configuration values are documented <a href="StockIndicatorsLegend.html">here</a>. The x and y properties are not
+ * configurable through this object as they are determined by the layout of the charts in this application. </dd>
* <dt>lineWidth</dt><dd>The weight to be used for line graphs in the chart.</dd>
* <dt>numBar</dt><dd>The value used to calculate the width of the columns in a graph when the `rangeType` is
* `daily`. By default, the column width is determined from number of data values across the x axis and the
@@ -113,7 +83,7 @@ StockIndicatorsChart.ATTRS = {
* <dt>y</dt><dd>The y coordinate for the chart in relation to the application.</dd>
* </dl>
*
- * @attribute chartsData
+ * @attribute charts
* @type: Array
*/
charts: {},
@@ -164,6 +134,7 @@ Y.extend(StockIndicatorsChart, Y.Widget, {
* @param {Object} e Event payload
*/
updatesLegendsCrosshair: function(e) {
+ e.preventDefault();
var crosshair,
crosshairs = this._crosshairs,
legends = this._legends,
@@ -181,17 +152,74 @@ Y.extend(StockIndicatorsChart, Y.Widget, {
xy = chart.xy,
x = pageX - xy[0];
crosshair = this._crosshairs[i];
- crosshair.setTarget(pageX);
+ crosshair.setTarget(pageX, this._autoDraw);
}
len = legends.length;
for(i = 0; i < len; i = i + 1) {
- legends[i].update(pageX, this._dataProvider);
+ legends[i].update(pageX, this._dataProvider, this._autoDraw);
}
}
this.curX = pageX;
},
/**
+ * Starts a timeline used to manage redraws based on requestAnimationFrame.
+ *
+ * @method startTimeline
+ */
+ startTimeline: function() {
+ if(!this._runTimeline) {
+ this._runTimeline = true;
+ this._timelineStart = (new Date()).valueOf() - 17;
+ this.redraw();
+ }
+ },
+
+ /**
+ * Ends a timeline.
+ *
+ * @method stopTimeline
+ */
+ stopTimeline: function() {
+ var args,
+ timelineId = this._timelineId;
+ this._runTimeline = false;
+ if(timelineId) {
+ args = [timelineId];
+ this._timelineId = null;
+ }
+ },
+
+ /**
+ * Draws chart elements based on the timeline.
+ *
+ * @method redraw
+ */
+ redraw: function() {
+ var scope = this,
+ crosshairs = this._crosshairs,
+ legends = this._legends,
+ i,
+ len = crosshairs.length,
+ endTime = (new Date()).valueOf();
+ if(endTime >= this._timelineStart + 17) {
+ for(i = 0; i < len; i = i + 1) {
+ crosshairs[i].redraw();
+ }
+ len = legends.length;
+ for(i = 0; i < len; i = i + 1) {
+ legends[i].redraw();
+ }
+ this._timelineStart = (new Date()).valueOf();
+ }
+ if(this._runTimeline && !this._autoDraw) {
+ this._timelineId = this._onEnterFrame.apply(window, [function() {
+ scope.redraw();
+ }]);
+ }
+ },
+
+ /**
*
*/
initializer: function() {
@@ -203,6 +231,12 @@ Y.extend(StockIndicatorsChart, Y.Widget, {
this._crosshairs = [];
this._hotspots = [];
this._legends = [];
+ this._runTimeline = false;
+ this._onEnterFrame = window.requestAnimationFrame ||
+ window.mozRequestAnimationFrame ||
+ window.webkitRequestAnimationFrame ||
+ window.msRequestAnimationFrame;
+ this._autoDraw = this._onEnterFrame ? false : true;
StockIndicatorsChart.superclass.initializer.apply(this, arguments);
},
@@ -251,12 +285,18 @@ Y.extend(StockIndicatorsChart, Y.Widget, {
indLen = indicators.length,
valueIter,
valueLen,
- valueKey;
+ valueKey,
+ groupMarkers;
for(indIter = 0; indIter < indLen; indIter = indIter + 1) {
indicator = indicators[indIter];
valueKey = indicator.valueKey;
- if(indicator.type === "candlestick" || typeof valueKey === "string") {
+ indicatorType = indicator.type;
+ if(indicatorType === "candlestick" || typeof valueKey === "string") {
+ groupMarkers = indicatorType !== "candlestick" &&
+ indicatorType !== "line" &&
+ indicator.groupMarkers;
seriesCollection.push({
+ groupMarkers: groupMarkers,
type: indicator.type,
xKey: config.categoryKey,
yKey: indicator.valueKey
@@ -265,7 +305,9 @@ Y.extend(StockIndicatorsChart, Y.Widget, {
valueLen = valueKey.length;
for(valueIter = 0; valueIter < valueLen; valueIter = valueIter + 1) {
indicatorType = indicator.type;
+ groupMarkers = indicatorType !== "line" && indicator.groupMarkers;
seriesCollection.push({
+ groupMarkers: groupMarkers,
type: typeof indicatorType === "string" ? indicatorType : indicatorType[valueIter],
xKey: config.categoryKey,
yKey: indicator.valueKey[valueIter]
@@ -444,6 +486,20 @@ Y.extend(StockIndicatorsChart, Y.Widget, {
};
},
+ /**
+ * Maps axis class to key.
+ *
+ * @property _axesClassMap
+ * @type AxisBase
+ * @private
+ */
+ _axesClassMap: {
+ numeric: Y.NumericAxis,
+ numericbase: Y.NumericAxisBase,
+ category: Y.CategoryAxis,
+ categorybase: Y.CategoryAxisBase
+ },
+
/**
* Add the axes to the chart and returns an object literal with references to the
* `date` and `numeric` axes.
@@ -460,7 +516,9 @@ Y.extend(StockIndicatorsChart, Y.Widget, {
numericConfig = config.axes.numeric,
dateConfig = config.axes.date,
numericAxis,
- dateAxis;
+ dateAxis,
+ NumericClass = this._axesClassMap[numericConfig.type],
+ DateClass = this._axesClassMap[dateConfig.type];
numericConfig.render = cb;
numericConfig.y = config.y + config.legend.height;
numericConfig.x = config.width - numericConfig.width;
@@ -468,8 +526,8 @@ Y.extend(StockIndicatorsChart, Y.Widget, {
dateConfig.render = cb;
dateConfig.y = config.y + config.height - dateConfig.height;
dateConfig.width = config.width;
- numericAxis = new Y.NumericAxis(numericConfig);
- dateAxis = new Y.CategoryAxis(dateConfig);
+ numericAxis = new NumericClass(numericConfig);
+ dateAxis = new DateClass(dateConfig);
bb = dateAxis.get("boundingBox");
bb.setStyle("left", 0 + "px");
bb.setStyle("top", (config.y + config.height - dateConfig.height) + "px");
View
108 src/gallery-charts-stockindicators/js/StockIndicatorsLegend.js
@@ -1,10 +1,50 @@
/**
+ * Provides functionality for a legend.
+ *
+ * @module gallery-charts-stockindicators
+ */
+/**
* Displays a legend when the user interacts with the corresponding chart
* application.
*
- * @module gallery-charts-stockindicators
* @class StockIndicatorsLegend
* @constructor
+ * @param {Object} config Configuration parameters.
+ * <dl>
+ * <dt>dataProvider</dt><dd>Reference to the application's `dataProvider` attribute.</dd>
+ * <dt>dateColor</dt><dd>The color to be used for the date text in the legend.</dd>
+ * <dt>delim</dt><dd>String value prefixing the display name of each legend item.</dd>
+ * <dt>dateLabelFunction</dt><dd>The function used for formatting the date label.</dd>
+ * <dt>dateLabelFormat</dt><dd>The strf format used to format the date label.</dd>
+ * <dt>dateLabelScope</dt><dd>The scope for the dateLabelFunction</dd>
+ * <dt>displayKeys</dt><dd>An array of displayKeys to be used in the legend. Each display key
+ * is the text to be displayed in the legend for the corresponding value key.</dd>
+ * <dt>displayName</dt><dd>Indicates whether to display the display name. The default
+ * value is `true`.</dd>
+ * <dt>displayValue</dt><dd>Indicates whether to display the value. The default value
+ * is `true`.</dd>
+ * <dt>drawSwatch</dt><dd>Indicates whether or no to draw a colored swatch by the display
+ * name. The default value is `true`.</dd>
+ * <dt>font</dt><dd>The font to use for all text in the legend.</dd>
+ * <dt>fontSize</dt><dd>The font size to use for all text in the legend.</dd>
+ * <dt>height</dt><dd>The height of the legend.</dd>
+ * <dt>priceDownColor</dt><dd>The color to be used for the value text when the value is negative.</dd>
+ * <dt>priceUpColor</dt><dd>The color to be used for value text when the value is positive.</dd>
+ * <dt>swatchWidth</dt><dd>The width of the swatch for each legend item.</dd>
+ * <dt>valueKeys</dt><dd>The value keys, in order, to be used in the legend.</dd>
+ * <dt>valueLabelFormat</dt><dd>Object literal indicating how to format the legend values.
+ * <dl>
+ * <dt>prefix</dt><dd>The prefix.</dd>
+ * <dt>suffix</dt><dd>The suffix.</dd>
+ * <dt>thousandsSeparator</dt><dd>The thousands separator.</dd>
+ * <dt>decimalPlaces</dt><dd>The number of decimals to display.</dd>
+ * <dt>decimalsSeparator</dt><dd>The decimal separator.</dd>
+ * </dl>
+ * </dd>
+ * <dt>width</dt><dd>The width of the legend.</dd>
+ * <dt>x</dt><dd>The x-coordinate for the legend</dd>
+ * <dt>y</dt><dd>The y-coordinate for the legend</dd>
+ * </dl>
*/
function StockIndicatorsLegend() {
this.init.apply(this, arguments);
@@ -87,7 +127,7 @@ StockIndicatorsLegend.prototype = {
this.formatDate = cfg.formatDate;
this._xy = Y.DOM.getXY(this.contentDiv);
},
-
+
/**
* Removes all elements of the legend.
*
@@ -121,7 +161,7 @@ StockIndicatorsLegend.prototype = {
}
}
},
-
+
/**
* Updates the legend.
*
@@ -129,12 +169,24 @@ StockIndicatorsLegend.prototype = {
* @param {Number} pageX
* @param {Array} dataProvider
*/
- update: function(pageX, dataProvider) {
+ update: function(pageX, dataProvider, redraw) {
var xy = this._xy,
x = pageX - xy[0],
- index = Math.floor(x / this.width * dataProvider.length),
- dataItem = dataProvider[index],
- queue = this.seriesQueue,
+ index = Math.floor(x / this.width * dataProvider.length);
+ this._dataItem = dataProvider[index];
+ if(redraw) {
+ this.redraw();
+ }
+ },
+
+
+ /**
+ * Draws the legend.
+ *
+ * @method redraw
+ */
+ redraw: function() {
+ var queue = this.seriesQueue,
key,
len = queue.length,
item,
@@ -144,27 +196,31 @@ StockIndicatorsLegend.prototype = {
dateLabelFunction = this.dateLabelFunction,
dateLabelScope = this.dateLabelScope,
dateLabelFormat = this.dateLabelFormat,
- dateLabelArgs;
- val = dataItem.Date || dataItem.Timestamp;
- if(dateLabelFunction) {
- dateLabelArgs = [val];