Upgrade to ExtJS 4.0.2 - Released 06/09/2011
[extjs.git] / docs / source / Line.html
index f924e61..4d5131e 100644 (file)
@@ -1,4 +1,21 @@
-<!DOCTYPE html><html><head><title>Sencha Documentation Project</title><link rel="stylesheet" href="../reset.css" type="text/css"><link rel="stylesheet" href="../prettify.css" type="text/css"><link rel="stylesheet" href="../prettify_sa.css" type="text/css"><script type="text/javascript" src="../prettify.js"></script></head><body onload="prettyPrint()"><pre class="prettyprint"><pre><span id='Ext-chart.series.Line'>/**
+<!DOCTYPE html>
+<html>
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+  <title>The source code</title>
+  <link href="../prettify/prettify.css" type="text/css" rel="stylesheet" />
+  <script type="text/javascript" src="../prettify/prettify.js"></script>
+  <style type="text/css">
+    .highlight { display: block; background-color: #ddd; }
+  </style>
+  <script type="text/javascript">
+    function highlight() {
+      document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
+    }
+  </script>
+</head>
+<body onload="prettyPrint(); highlight();">
+  <pre class="prettyprint lang-js"><span id='Ext-chart-series-Line'>/**
 </span> * @class Ext.chart.series.Line
  * @extends Ext.chart.series.Cartesian
  * 
  *         }]
  *     });
  *  
- * In this configuration we're adding two series (or lines), one bound to the `data1` property of the store and the other to `data3`. The type for both configurations is 
- * `line`. The `xField` for both series is the same, the name propert of the store. Both line series share the same axis, the left axis. You can set particular marker 
- * configuration by adding properties onto the markerConfig object. Both series have an object as highlight so that markers animate smoothly to the properties in highlight 
- * when hovered. The second series has `fill=true` which means that the line will also have an area below it of the same color.
+ * In this configuration we're adding two series (or lines), one bound to the `data1` 
+ * property of the store and the other to `data3`. The type for both configurations is 
+ * `line`. The `xField` for both series is the same, the name propert of the store. 
+ * Both line series share the same axis, the left axis. You can set particular marker 
+ * configuration by adding properties onto the markerConfig object. Both series have 
+ * an object as highlight so that markers animate smoothly to the properties in highlight 
+ * when hovered. The second series has `fill=true` which means that the line will also 
+ * have an area below it of the same color.
+ *
+ * **Note:** In the series definition remember to explicitly set the axis to bind the 
+ * values of the line series to. This can be done by using the `axis` configuration property.
  */
-
 Ext.define('Ext.chart.series.Line', {
 
     /* Begin Definitions */
@@ -97,21 +120,28 @@ Ext.define('Ext.chart.series.Line', {
     type: 'line',
     
     alias: 'series.line',
+    
+<span id='Ext-chart-series-Line-cfg-axis'>    /**
+</span>     * @cfg {String} axis
+     * The position of the axis to bind the values to. Possible values are 'left', 'bottom', 'top' and 'right'.
+     * You must explicitly set this value to bind the values of the line series to the ones in the axis, otherwise a
+     * relative scale will be used.
+     */
 
-<span id='Ext-chart.series.Line-cfg-selectionTolerance'>    /**
+<span id='Ext-chart-series-Line-cfg-selectionTolerance'>    /**
 </span>     * @cfg {Number} selectionTolerance
      * The offset distance from the cursor position to the line series to trigger events (then used for highlighting series, etc).
      */
     selectionTolerance: 20,
     
-<span id='Ext-chart.series.Line-cfg-showMarkers'>    /**
+<span id='Ext-chart-series-Line-cfg-showMarkers'>    /**
 </span>     * @cfg {Boolean} showMarkers
      * Whether markers should be displayed at the data points along the line. If true,
      * then the {@link #markerConfig} config item will determine the markers' styling.
      */
     showMarkers: true,
 
-<span id='Ext-chart.series.Line-cfg-markerConfig'>    /**
+<span id='Ext-chart-series-Line-cfg-markerConfig'>    /**
 </span>     * @cfg {Object} markerConfig
      * The display style for the markers. Only used if {@link #showMarkers} is true.
      * The markerConfig is a configuration object containing the same set of properties defined in
@@ -129,21 +159,31 @@ Ext.define('Ext.chart.series.Line', {
      */
     markerConfig: {},
 
-<span id='Ext-chart.series.Line-cfg-style'>    /**
+<span id='Ext-chart-series-Line-cfg-style'>    /**
 </span>     * @cfg {Object} style
      * An object containing styles for the visualization lines. These styles will override the theme styles. 
      * Some options contained within the style object will are described next.
      */
     style: {},
     
-<span id='Ext-chart.series.Line-cfg-smooth'>    /**
-</span>     * @cfg {Boolean} smooth
-     * If true, the line will be smoothed/rounded around its points, otherwise straight line
-     * segments will be drawn. Defaults to false.
+<span id='Ext-chart-series-Line-cfg-smooth'>    /**
+</span>     * @cfg {Boolean/Number} smooth
+     * If set to `true` or a non-zero number, the line will be smoothed/rounded around its points; otherwise
+     * straight line segments will be drawn.
+     *
+     * A numeric value is interpreted as a divisor of the horizontal distance between consecutive points in
+     * the line; larger numbers result in sharper curves while smaller numbers result in smoother curves.
+     *
+     * If set to `true` then a default numeric value of 3 will be used. Defaults to `false`.
      */
     smooth: false,
 
-<span id='Ext-chart.series.Line-cfg-fill'>    /**
+<span id='Ext-chart-series-Line-property-defaultSmoothness'>    /**
+</span>     * @private Default numeric smoothing value to be used when {@link #smooth} = true.
+     */
+    defaultSmoothness: 3,
+
+<span id='Ext-chart-series-Line-cfg-fill'>    /**
 </span>     * @cfg {Boolean} fill
      * If true, the area below the line will be filled in using the {@link #style.eefill} and
      * {@link #style.opacity} config properties. Defaults to false.
@@ -224,7 +264,7 @@ Ext.define('Ext.chart.series.Line', {
         };
     },
 
-<span id='Ext-chart.series.Line-method-drawSeries'>    /**
+<span id='Ext-chart-series-Line-method-drawSeries'>    /**
 </span>     * Draws the series for the current chart.
      */
     drawSeries: function() {
@@ -241,7 +281,8 @@ Ext.define('Ext.chart.series.Line', {
             markerGroup = me.markerGroup,
             enableShadows = chart.shadow,
             shadowGroups = me.shadowGroups,
-            shadowAttributes = this.shadowAttributes,
+            shadowAttributes = me.shadowAttributes,
+            smooth = me.smooth,
             lnsh = shadowGroups.length,
             dummyPath = [&quot;M&quot;],
             path = [&quot;M&quot;],
@@ -251,16 +292,26 @@ Ext.define('Ext.chart.series.Line', {
             shadowBarAttr,
             xValues = [],
             yValues = [],
+            storeIndices = [],
+            numericAxis = true,
+            axisCount = 0,
             onbreak = false,
             markerStyle = me.markerStyle,
             seriesStyle = me.seriesStyle,
             seriesLabelStyle = me.seriesLabelStyle,
             colorArrayStyle = me.colorArrayStyle,
             colorArrayLength = colorArrayStyle &amp;&amp; colorArrayStyle.length || 0,
+            posHash = {
+                'left': 'right',
+                'right': 'left',
+                'top': 'bottom',
+                'bottom': 'top'
+            },
+            isNumber = Ext.isNumber,
             seriesIdx = me.seriesIdx, shadows, shadow, shindex, fromPath, fill, fillPath, rendererAttributes,
             x, y, prevX, prevY, firstY, markerCount, i, j, ln, axis, ends, marker, markerAux, item, xValue,
             yValue, coords, xScale, yScale, minX, maxX, minY, maxY, line, animation, endMarkerStyle,
-            endLineStyle, type, props, firstMarker;
+            endLineStyle, type, props, firstMarker, count, smoothPath, renderPath;
         
         //if store is empty then there's nothing to draw.
         if (!store || !store.getCount()) {
@@ -304,48 +355,89 @@ Ext.define('Ext.chart.series.Line', {
 
         me.clipRect = [bbox.x, bbox.y, bbox.width, bbox.height];
 
-        for (i = 0, ln = axes.length; i &lt; ln; i++) { 
-            axis = chart.axes.get(axes[i]);
-            if (axis) {
-                ends = axis.calcEnds();
-                if (axis.position == 'top' || axis.position == 'bottom') {
-                    minX = ends.from;
-                    maxX = ends.to;
+        chart.axes.each(function(axis) {
+            //only apply position calculations to axes that affect this series
+            //this means the axis in the position referred by this series and also
+            //the axis in the other coordinate for this series. For example: (left, top|bottom),
+            //or (top, left|right), etc.
+            if (axis.position == me.axis || axis.position != posHash[me.axis]) {
+                axisCount++;
+                if (axis.type != 'Numeric') {
+                    numericAxis = false;
+                    return;
                 }
-                else {
-                    minY = ends.from;
-                    maxY = ends.to;
+                numericAxis = (numericAxis &amp;&amp; axis.type == 'Numeric');
+                if (axis) {
+                    ends = axis.calcEnds();
+                    if (axis.position == 'top' || axis.position == 'bottom') {
+                        minX = ends.from;
+                        maxX = ends.to;
+                    }
+                    else {
+                        minY = ends.from;
+                        maxY = ends.to;
+                    }
                 }
             }
+        });
+        
+        //If there's only one axis specified for a series, then we set the default type of the other
+        //axis to a category axis. So in this case numericAxis, which would be true if both axes affecting
+        //the series are numeric should be false.
+        if (numericAxis &amp;&amp; axisCount == 1) {
+            numericAxis = false;
         }
+        
         // If a field was specified without a corresponding axis, create one to get bounds
         //only do this for the axis where real values are bound (that's why we check for
         //me.axis)
-        if (me.xField &amp;&amp; !Ext.isNumber(minX)
-            &amp;&amp; (me.axis == 'bottom' || me.axis == 'top')) {
-            axis = Ext.create('Ext.chart.axis.Axis', {
-                chart: chart,
-                fields: [].concat(me.xField)
-            }).calcEnds();
-            minX = axis.from;
-            maxX = axis.to;
-        }
-        if (me.yField &amp;&amp; !Ext.isNumber(minY)
-            &amp;&amp; (me.axis == 'right' || me.axis == 'left')) {
-            axis = Ext.create('Ext.chart.axis.Axis', {
-                chart: chart,
-                fields: [].concat(me.yField)
-            }).calcEnds();
-            minY = axis.from;
-            maxY = axis.to;
+        if (me.xField &amp;&amp; !isNumber(minX)) {
+            if (me.axis == 'bottom' || me.axis == 'top') {
+                axis = Ext.create('Ext.chart.axis.Axis', {
+                    chart: chart,
+                    fields: [].concat(me.xField)
+                }).calcEnds();
+                minX = axis.from;
+                maxX = axis.to;
+            } else if (numericAxis) {
+                axis = Ext.create('Ext.chart.axis.Axis', {
+                    chart: chart,
+                    fields: [].concat(me.xField),
+                    forceMinMax: true
+                }).calcEnds();
+                minX = axis.from;
+                maxX = axis.to;
+            }
         }
-
+        
+        if (me.yField &amp;&amp; !isNumber(minY)) {
+            if (me.axis == 'right' || me.axis == 'left') {
+                axis = Ext.create('Ext.chart.axis.Axis', {
+                    chart: chart,
+                    fields: [].concat(me.yField)
+                }).calcEnds();
+                minY = axis.from;
+                maxY = axis.to;
+            } else if (numericAxis) {
+                axis = Ext.create('Ext.chart.axis.Axis', {
+                    chart: chart,
+                    fields: [].concat(me.yField),
+                    forceMinMax: true
+                }).calcEnds();
+                minY = axis.from;
+                maxY = axis.to;
+            }
+        }
+        
         if (isNaN(minX)) {
             minX = 0;
             xScale = bbox.width / (store.getCount() - 1);
         }
         else {
-            xScale = bbox.width / (maxX - minX);
+            //In case some person decides to set an axis' minimum and maximum
+            //configuration properties to the same value, then fallback the
+            //denominator to a &gt; 0 value.
+            xScale = bbox.width / ((maxX - minX) || (store.getCount() - 1));
         }
 
         if (isNaN(minY)) {
@@ -353,9 +445,12 @@ Ext.define('Ext.chart.series.Line', {
             yScale = bbox.height / (store.getCount() - 1);
         } 
         else {
-            yScale = bbox.height / (maxY - minY);
+            //In case some person decides to set an axis' minimum and maximum
+            //configuration properties to the same value, then fallback the
+            //denominator to a &gt; 0 value.
+            yScale = bbox.height / ((maxY - minY) || (store.getCount() - 1));
         }
-
+        
         store.each(function(record, i) {
             xValue = record.get(me.xField);
             yValue = record.get(me.yField);
@@ -371,14 +466,15 @@ Ext.define('Ext.chart.series.Line', {
             // Ensure a value
             if (typeof xValue == 'string' || typeof xValue == 'object'
                 //set as uniform distribution if the axis is a category axis.
-                || (me.axis != 'top' &amp;&amp; me.axis != 'bottom')) {
+                || (me.axis != 'top' &amp;&amp; me.axis != 'bottom' &amp;&amp; !numericAxis)) {
                 xValue = i;
             }
             if (typeof yValue == 'string' || typeof yValue == 'object'
                 //set as uniform distribution if the axis is a category axis.
-                || (me.axis != 'left' &amp;&amp; me.axis != 'right')) {
+                || (me.axis != 'left' &amp;&amp; me.axis != 'right' &amp;&amp; !numericAxis)) {
                 yValue = i;
             }
+            storeIndices.push(i);
             xValues.push(xValue);
             yValues.push(yValue);
         }, me);
@@ -392,6 +488,7 @@ Ext.define('Ext.chart.series.Line', {
 
         me.items = [];
 
+        count = 0;
         ln = xValues.length;
         for (i = 0; i &lt; ln; i++) {
             xValue = xValues[i];
@@ -442,7 +539,7 @@ Ext.define('Ext.chart.series.Line', {
                 }
             }
             if (showMarkers) {
-                marker = markerGroup.getAt(i);
+                marker = markerGroup.getAt(count++);
                 if (!marker) {
                     marker = Ext.chart.Shape[type](surface, Ext.apply({
                         group: [group, markerGroup],
@@ -472,12 +569,13 @@ Ext.define('Ext.chart.series.Line', {
                     };
                 }
             }
+
             me.items.push({
                 series: me,
                 value: [xValue, yValue],
                 point: [x, y],
                 sprite: marker,
-                storeItem: store.getAt(i)
+                storeItem: store.getAt(storeIndices[i])
             });
             prevX = x;
             prevY = y;
@@ -487,19 +585,23 @@ Ext.define('Ext.chart.series.Line', {
             //nothing to be rendered
             return;    
         }
-        
-        if (me.smooth) {
-            path = Ext.draw.Draw.smooth(path, 6);
+    
+        if (smooth) {
+            smoothPath = Ext.draw.Draw.smooth(path, isNumber(smooth) ? smooth : me.defaultSmoothness);
         }
         
+        renderPath = smooth ? smoothPath : path;
+
         //Correct path if we're animating timeAxis intervals
         if (chart.markerIndex &amp;&amp; me.previousPath) {
             fromPath = me.previousPath;
-            fromPath.splice(1, 2);
+            if (!smooth) {
+                Ext.Array.erase(fromPath, 1, 2);
+            }
         } else {
             fromPath = path;
         }
-
+        
         // Only create a line if one doesn't exist.
         if (!me.line) {
             me.line = surface.add(Ext.apply({
@@ -532,7 +634,7 @@ Ext.define('Ext.chart.series.Line', {
             }
         }
         if (me.fill) {
-            fillPath = path.concat([
+            fillPath = renderPath.concat([
                 [&quot;L&quot;, x, bbox.y + bbox.height],
                 [&quot;L&quot;, bbox.x, bbox.y + bbox.height],
                 [&quot;L&quot;, bbox.x, firstY]
@@ -542,7 +644,7 @@ Ext.define('Ext.chart.series.Line', {
                     group: group,
                     type: 'path',
                     opacity: endLineStyle.opacity || 0.3,
-                    fill: colorArrayStyle[seriesIdx % colorArrayLength] || endLineStyle.fill,
+                    fill: endLineStyle.fill || colorArrayStyle[seriesIdx % colorArrayLength],
                     path: dummyPath
                 });
             }
@@ -552,7 +654,7 @@ Ext.define('Ext.chart.series.Line', {
             fill = me.fill;
             line = me.line;
             //Add renderer to line. There is not unique record associated with this.
-            rendererAttributes = me.renderer(line, false, { path: path }, i, store);
+            rendererAttributes = me.renderer(line, false, { path: renderPath }, i, store);
             Ext.apply(rendererAttributes, endLineStyle || {}, {
                 stroke: endLineStyle.stroke || endLineStyle.fill
             });
@@ -576,12 +678,12 @@ Ext.define('Ext.chart.series.Line', {
                 for(j = 0; j &lt; lnsh; j++) {
                     if (chart.markerIndex &amp;&amp; me.previousPath) {
                         me.onAnimate(shadows[j], {
-                            to: { path: path },
+                            to: { path: renderPath },
                             from: { path: fromPath }
                         });
                     } else {
                         me.onAnimate(shadows[j], {
-                            to: { path: path }
+                            to: { path: renderPath }
                         });
                     }
                 }
@@ -591,38 +693,31 @@ Ext.define('Ext.chart.series.Line', {
                 me.onAnimate(me.fillPath, {
                     to: Ext.apply({}, {
                         path: fillPath,
-                        fill: colorArrayStyle[seriesIdx % colorArrayLength] || endLineStyle.fill
+                        fill: endLineStyle.fill || colorArrayStyle[seriesIdx % colorArrayLength]
                     }, endLineStyle || {})
                 });
             }
             //animate markers
             if (showMarkers) {
+                count = 0;
                 for(i = 0; i &lt; ln; i++) {
-                    item = markerGroup.getAt(i);
-                    if (item) {
-                        if (me.items[i]) {
+                    if (me.items[i]) {
+                        item = markerGroup.getAt(count++);
+                        if (item) {
                             rendererAttributes = me.renderer(item, store.getAt(i), item._to, i, store);
                             me.onAnimate(item, {
                                 to: Ext.apply(rendererAttributes, endMarkerStyle || {})
                             });
-                        } else {
-                            item.setAttributes(Ext.apply({
-                                hidden: true 
-                            }, item._to), true);
                         }
-                    }
+                    } 
                 }
-                for(; i &lt; markerCount; i++) {
-                    item = markerGroup.getAt(i);
+                for(; count &lt; markerCount; count++) {
+                    item = markerGroup.getAt(count);
                     item.hide(true);
                 }
-//                for(i = 0; i &lt; (chart.markerIndex || 0)-1; i++) {
-//                    item = markerGroup.getAt(i);
-//                    item.hide(true);
-//                }
             }
         } else {
-            rendererAttributes = me.renderer(me.line, false, { path: path, hidden: false }, i, store);
+            rendererAttributes = me.renderer(me.line, false, { path: renderPath, hidden: false }, i, store);
             Ext.apply(rendererAttributes, endLineStyle || {}, {
                 stroke: endLineStyle.stroke || endLineStyle.fill
             });
@@ -634,7 +729,7 @@ Ext.define('Ext.chart.series.Line', {
                 shadows = me.line.shadows;
                 for(j = 0; j &lt; lnsh; j++) {
                     shadows[j].setAttributes({
-                        path: path
+                        path: renderPath
                     }, true);
                 }
             }
@@ -644,26 +739,29 @@ Ext.define('Ext.chart.series.Line', {
                 }, true);
             }
             if (showMarkers) {
+                count = 0;
                 for(i = 0; i &lt; ln; i++) {
-                    item = markerGroup.getAt(i);
-                    if (item) {
-                        if (me.items[i]) {
+                    if (me.items[i]) {
+                        item = markerGroup.getAt(count++);
+                        if (item) {
                             rendererAttributes = me.renderer(item, store.getAt(i), item._to, i, store);
                             item.setAttributes(Ext.apply(endMarkerStyle || {}, rendererAttributes || {}), true);
-                        } else {
-                            item.hide(true);
                         }
-                    }
+                    } 
                 }
-                for(; i &lt; markerCount; i++) {
-                    item = markerGroup.getAt(i);
+                for(; count &lt; markerCount; count++) {
+                    item = markerGroup.getAt(count);
                     item.hide(true);
                 }
             }
         }
 
         if (chart.markerIndex) {
-            path.splice(1, 0, path[1], path[2]);
+            if (me.smooth) {
+                Ext.Array.erase(path, 1, 2);
+            } else {
+                Ext.Array.splice(path, 1, 0, path[1], path[2]);
+            }
             me.previousPath = path;
         }
         me.renderLabels();
@@ -987,4 +1085,6 @@ Ext.define('Ext.chart.series.Line', {
     showAll: function() {
         this.toggleAll(true);
     }
-});</pre></pre></body></html>
\ No newline at end of file
+});</pre>
+</body>
+</html>