-<!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="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
+ <script type="text/javascript" src="../resources/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
- *
- * Creates a Line Chart. A Line Chart is a useful visualization technique to display quantitative information for different
+ *
+ * Creates a Line Chart. A Line Chart is a useful visualization technique to display quantitative information for different
* categories or other real values (as opposed to the bar chart), that can show some progression (or regression) in the dataset.
- * As with all other series, the Line Series must be appended in the *series* Chart array configuration. See the Chart
+ * As with all other series, the Line Series must be appended in the *series* Chart array configuration. See the Chart
* documentation for more information. A typical configuration object for the line series could be:
*
- * {@img Ext.chart.series.Line/Ext.chart.series.Line.png Ext.chart.series.Line chart series}
- *
+ * @example
* var store = Ext.create('Ext.data.JsonStore', {
* fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
* data: [
- * {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13},
- * {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3},
- * {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7},
- * {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23},
- * {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33}
+ * { 'name': 'metric one', 'data1': 10, 'data2': 12, 'data3': 14, 'data4': 8, 'data5': 13 },
+ * { 'name': 'metric two', 'data1': 7, 'data2': 8, 'data3': 16, 'data4': 10, 'data5': 3 },
+ * { 'name': 'metric three', 'data1': 5, 'data2': 2, 'data3': 14, 'data4': 12, 'data5': 7 },
+ * { 'name': 'metric four', 'data1': 2, 'data2': 14, 'data3': 6, 'data4': 1, 'data5': 23 },
+ * { 'name': 'metric five', 'data1': 4, 'data2': 4, 'data3': 36, 'data4': 13, 'data5': 33 }
* ]
* });
- *
+ *
* Ext.create('Ext.chart.Chart', {
* renderTo: Ext.getBody(),
* width: 500,
* height: 300,
* animate: true,
* store: store,
- * axes: [{
- * type: 'Numeric',
- * position: 'bottom',
- * fields: ['data1'],
- * label: {
- * renderer: Ext.util.Format.numberRenderer('0,0')
- * },
- * title: 'Sample Values',
- * grid: true,
- * minimum: 0
- * }, {
- * type: 'Category',
- * position: 'left',
- * fields: ['name'],
- * title: 'Sample Metrics'
- * }],
- * series: [{
- * type: 'line',
- * highlight: {
- * size: 7,
- * radius: 7
+ * axes: [
+ * {
+ * type: 'Numeric',
+ * position: 'left',
+ * fields: ['data1', 'data2'],
+ * label: {
+ * renderer: Ext.util.Format.numberRenderer('0,0')
+ * },
+ * title: 'Sample Values',
+ * grid: true,
+ * minimum: 0
* },
- * axis: 'left',
- * xField: 'name',
- * yField: 'data1',
- * markerCfg: {
- * type: 'cross',
- * size: 4,
- * radius: 4,
- * 'stroke-width': 0
+ * {
+ * type: 'Category',
+ * position: 'bottom',
+ * fields: ['name'],
+ * title: 'Sample Metrics'
* }
- * }, {
- * type: 'line',
- * highlight: {
- * size: 7,
- * radius: 7
+ * ],
+ * series: [
+ * {
+ * type: 'line',
+ * highlight: {
+ * size: 7,
+ * radius: 7
+ * },
+ * axis: 'left',
+ * xField: 'name',
+ * yField: 'data1',
+ * markerConfig: {
+ * type: 'cross',
+ * size: 4,
+ * radius: 4,
+ * 'stroke-width': 0
+ * }
* },
- * axis: 'left',
- * fill: true,
- * xField: 'name',
- * yField: 'data3',
- * markerCfg: {
- * type: 'circle',
- * size: 4,
- * radius: 4,
- * 'stroke-width': 0
+ * {
+ * type: 'line',
+ * highlight: {
+ * size: 7,
+ * radius: 7
+ * },
+ * axis: 'left',
+ * fill: true,
+ * xField: 'name',
+ * yField: 'data2',
+ * markerConfig: {
+ * type: 'circle',
+ * size: 4,
+ * radius: 4,
+ * 'stroke-width': 0
+ * }
* }
- * }]
+ * ]
* });
- *
- * 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 */
/* End Definitions */
type: 'line',
-
+
alias: 'series.line',
-<span id='Ext-chart.series.Line-cfg-selectionTolerance'> /**
+<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> * @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
'fill': '#f00'
}
</code></pre>
-
+
*/
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.
+ * An object containing style properties for the visualization lines and fill.
+ * These styles will override the theme styles. The following are valid style properties:
+ *
+ * - `stroke` - an rgb or hex color string for the background color of the line
+ * - `stroke-width` - the width of the stroke (integer)
+ * - `fill` - the background fill color string (hex or rgb), only works if {@link #fill} is `true`
+ * - `opacity` - the opacity of the line and the fill color (decimal)
+ *
+ * Example usage:
+ *
+ * style: {
+ * stroke: '#00ff00',
+ * 'stroke-width': 10,
+ * fill: '#80A080',
+ * opacity: 0.2
+ * }
*/
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.
+ * 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.
*/
fill: false,
me.markerGroup = surface.getGroup(me.seriesId + '-markers');
}
if (shadow) {
- for (i = 0, l = this.shadowAttributes.length; i < l; i++) {
+ for (i = 0, l = me.shadowAttributes.length; i < l; i++) {
me.shadowGroups.push(surface.getGroup(me.seriesId + '-shadows' + i));
}
}
},
-
+
// @private makes an average of points when there are more data points than pixels to be rendered.
shrink: function(xValues, yValues, size) {
// Start at the 2nd point...
ySum = 0,
xRes = [xValues[0]],
yRes = [yValues[0]];
-
+
for (; i < len; ++i) {
xSum += xValues[i] || 0;
ySum += yValues[i] || 0;
};
},
-<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() {
var me = this,
chart = me.chart,
- store = chart.substore || chart.store,
- surface = chart.surface,
- chartBBox = chart.chartBBox,
+ chartAxes = chart.axes,
+ store = chart.getChartStore(),
+ storeCount = store.getCount(),
+ surface = me.chart.surface,
bbox = {},
group = me.group,
- gutterX = chart.maxGutter[0],
- gutterY = chart.maxGutter[1],
showMarkers = me.showMarkers,
markerGroup = me.markerGroup,
enableShadows = chart.shadow,
shadowGroups = me.shadowGroups,
- shadowAttributes = this.shadowAttributes,
+ shadowAttributes = me.shadowAttributes,
+ smooth = me.smooth,
lnsh = shadowGroups.length,
dummyPath = ["M"],
path = ["M"],
+ renderPath = ["M"],
+ smoothPath = ["M"],
markerIndex = chart.markerIndex,
axes = [].concat(me.axis),
- shadowGroup,
shadowBarAttr,
xValues = [],
+ xValueMap = {},
yValues = [],
+ yValueMap = {},
onbreak = false,
+ storeIndices = [],
markerStyle = me.markerStyle,
- seriesStyle = me.seriesStyle,
- seriesLabelStyle = me.seriesLabelStyle,
+ seriesStyle = me.style,
colorArrayStyle = me.colorArrayStyle,
colorArrayLength = colorArrayStyle && colorArrayStyle.length || 0,
- 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,
+ isNumber = Ext.isNumber,
+ seriesIdx = me.seriesIdx,
+ boundAxes = me.getAxesForXAndYFields(),
+ boundXAxis = boundAxes.xAxis,
+ boundYAxis = boundAxes.yAxis,
+ shadows, shadow, shindex, fromPath, fill, fillPath, rendererAttributes,
+ x, y, prevX, prevY, firstX, 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;
-
- //if store is empty then there's nothing to draw.
- if (!store || !store.getCount()) {
+ endLineStyle, type, count, items;
+
+ if (me.fireEvent('beforedraw', me) === false) {
+ return;
+ }
+
+ //if store is empty or the series is excluded in the legend then there's nothing to draw.
+ if (!storeCount || me.seriesIsHidden) {
+ items = this.items;
+ if (items) {
+ for (i = 0, ln = items.length; i < ln; ++i) {
+ if (items[i].sprite) {
+ items[i].sprite.hide(true);
+ }
+ }
+ }
return;
}
-
+
//prepare style objects for line and markers
- endMarkerStyle = Ext.apply(markerStyle, me.markerConfig);
+ endMarkerStyle = Ext.apply(markerStyle || {}, me.markerConfig);
type = endMarkerStyle.type;
delete endMarkerStyle.type;
- endLineStyle = Ext.apply(seriesStyle, me.style);
+ endLineStyle = seriesStyle;
//if no stroke with is specified force it to 0.5 because this is
//about making *lines*
if (!endLineStyle['stroke-width']) {
}, true);
}
}
-
+
me.unHighlightItem();
me.cleanHighlights();
me.setBBox();
bbox = me.bbox;
-
me.clipRect = [bbox.x, bbox.y, bbox.width, bbox.height];
-
- for (i = 0, ln = axes.length; i < ln; i++) {
- axis = chart.axes.get(axes[i]);
+ for (i = 0, ln = axes.length; i < ln; i++) {
+ axis = chartAxes.get(axes[i]);
if (axis) {
ends = axis.calcEnds();
if (axis.position == 'top' || axis.position == 'bottom') {
// 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 && !Ext.isNumber(minX)
- && (me.axis == 'bottom' || me.axis == 'top')) {
+ if (me.xField && !isNumber(minX) &&
+ (boundXAxis == 'bottom' || boundXAxis == 'top') &&
+ !chartAxes.get(boundXAxis)) {
axis = Ext.create('Ext.chart.axis.Axis', {
chart: chart,
fields: [].concat(me.xField)
minX = axis.from;
maxX = axis.to;
}
- if (me.yField && !Ext.isNumber(minY)
- && (me.axis == 'right' || me.axis == 'left')) {
+ if (me.yField && !isNumber(minY) &&
+ (boundYAxis == 'right' || boundYAxis == 'left') &&
+ !chartAxes.get(boundYAxis)) {
axis = Ext.create('Ext.chart.axis.Axis', {
chart: chart,
fields: [].concat(me.yField)
minY = axis.from;
maxY = axis.to;
}
-
if (isNaN(minX)) {
minX = 0;
- xScale = bbox.width / (store.getCount() - 1);
+ xScale = bbox.width / ((storeCount - 1) || 1);
}
else {
- xScale = bbox.width / (maxX - minX);
+ xScale = bbox.width / ((maxX - minX) || (storeCount -1) || 1);
}
if (isNaN(minY)) {
minY = 0;
- yScale = bbox.height / (store.getCount() - 1);
- }
+ yScale = bbox.height / ((storeCount - 1) || 1);
+ }
else {
- yScale = bbox.height / (maxY - minY);
+ yScale = bbox.height / ((maxY - minY) || (storeCount - 1) || 1);
}
- store.each(function(record, i) {
+ // Extract all x and y values from the store
+ me.eachRecord(function(record, i) {
xValue = record.get(me.xField);
+
+ // Ensure a value
+ if (typeof xValue == 'string' || typeof xValue == 'object' && !Ext.isDate(xValue)
+ //set as uniform distribution if the axis is a category axis.
+ || boundXAxis && chartAxes.get(boundXAxis) && chartAxes.get(boundXAxis).type == 'Category') {
+ if (xValue in xValueMap) {
+ xValue = xValueMap[xValue];
+ } else {
+ xValue = xValueMap[xValue] = i;
+ }
+ }
+
+ // Filter out values that don't fit within the pan/zoom buffer area
yValue = record.get(me.yField);
//skip undefined values
if (typeof yValue == 'undefined' || (typeof yValue == 'string' && !yValue)) {
return;
}
// Ensure a value
- if (typeof xValue == 'string' || typeof xValue == 'object'
+ if (typeof yValue == 'string' || typeof yValue == 'object' && !Ext.isDate(yValue)
//set as uniform distribution if the axis is a category axis.
- || (me.axis != 'top' && me.axis != 'bottom')) {
- xValue = i;
- }
- if (typeof yValue == 'string' || typeof yValue == 'object'
- //set as uniform distribution if the axis is a category axis.
- || (me.axis != 'left' && me.axis != 'right')) {
+ || boundYAxis && chartAxes.get(boundYAxis) && chartAxes.get(boundYAxis).type == 'Category') {
yValue = i;
}
+ storeIndices.push(i);
xValues.push(xValue);
yValues.push(yValue);
- }, me);
+ });
ln = xValues.length;
if (ln > bbox.width) {
me.items = [];
+ count = 0;
ln = xValues.length;
for (i = 0; i < ln; i++) {
xValue = xValues[i];
if (onbreak) {
onbreak = false;
path.push('M');
- }
+ }
path = path.concat([x, y]);
}
if ((typeof firstY == 'undefined') && (typeof y != 'undefined')) {
firstY = y;
+ firstX = x;
}
// If this is the first line, create a dummypath to animate in from.
if (!me.line || chart.resizing) {
}
}
if (showMarkers) {
- marker = markerGroup.getAt(i);
+ marker = markerGroup.getAt(count++);
if (!marker) {
marker = Ext.chart.Shape[type](surface, Ext.apply({
group: [group, markerGroup],
x: 0, y: 0,
translate: {
- x: prevX || x,
+ x: +(prevX || x),
y: prevY || (bbox.y + bbox.height / 2)
},
- value: '"' + xValue + ', ' + yValue + '"'
+ value: '"' + xValue + ', ' + yValue + '"',
+ zIndex: 4000
}, endMarkerStyle));
marker._to = {
translate: {
- x: x,
- y: y
+ x: +x,
+ y: +y
}
};
} else {
}, true);
marker._to = {
translate: {
- x: x, y: y
+ x: +x,
+ y: +y
}
};
}
value: [xValue, yValue],
point: [x, y],
sprite: marker,
- storeItem: store.getAt(i)
+ storeItem: store.getAt(storeIndices[i])
});
prevX = x;
prevY = y;
}
-
+
if (path.length <= 1) {
//nothing to be rendered
- return;
+ return;
}
-
+
if (me.smooth) {
- path = Ext.draw.Draw.smooth(path, 6);
+ 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 && me.previousPath) {
fromPath = me.previousPath;
- fromPath.splice(1, 2);
+ if (!smooth) {
+ Ext.Array.erase(fromPath, 1, 2);
+ }
} else {
fromPath = path;
}
path: dummyPath,
stroke: endLineStyle.stroke || endLineStyle.fill
}, endLineStyle || {}));
+
+ if (enableShadows) {
+ me.line.setAttributes(Ext.apply({}, me.shadowOptions), true);
+ }
+
//unset fill here (there's always a default fill withing the themes).
me.line.setAttributes({
- fill: 'none'
+ fill: 'none',
+ zIndex: 3000
});
if (!endLineStyle.stroke && colorArrayLength) {
me.line.setAttributes({
}
if (enableShadows) {
//create shadows
- shadows = me.line.shadows = [];
+ shadows = me.line.shadows = [];
for (shindex = 0; shindex < lnsh; shindex++) {
shadowBarAttr = shadowAttributes[shindex];
shadowBarAttr = Ext.apply({}, shadowBarAttr, { path: dummyPath });
- shadow = chart.surface.add(Ext.apply({}, {
+ shadow = surface.add(Ext.apply({}, {
type: 'path',
group: shadowGroups[shindex]
}, shadowBarAttr));
}
}
if (me.fill) {
- fillPath = path.concat([
+ fillPath = renderPath.concat([
["L", x, bbox.y + bbox.height],
- ["L", bbox.x, bbox.y + bbox.height],
- ["L", bbox.x, firstY]
+ ["L", firstX, bbox.y + bbox.height],
+ ["L", firstX, firstY]
]);
if (!me.fillPath) {
me.fillPath = surface.add({
group: group,
type: 'path',
opacity: endLineStyle.opacity || 0.3,
- fill: colorArrayStyle[seriesIdx % colorArrayLength] || endLineStyle.fill,
+ fill: endLineStyle.fill || colorArrayStyle[seriesIdx % colorArrayLength],
path: dummyPath
});
}
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
});
//fill should not be used here but when drawing the special fill path object
delete rendererAttributes.fill;
+ line.show(true);
if (chart.markerIndex && me.previousPath) {
me.animation = animation = me.onAnimate(line, {
to: rendererAttributes,
if (enableShadows) {
shadows = line.shadows;
for(j = 0; j < lnsh; j++) {
+ shadows[j].show(true);
if (chart.markerIndex && 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 }
});
}
}
}
//animate fill path
if (fill) {
+ me.fillPath.show(true);
me.onAnimate(me.fillPath, {
to: Ext.apply({}, {
path: fillPath,
- fill: colorArrayStyle[seriesIdx % colorArrayLength] || endLineStyle.fill
+ fill: endLineStyle.fill || colorArrayStyle[seriesIdx % colorArrayLength],
+ 'stroke-width': 0
}, endLineStyle || {})
});
}
//animate markers
if (showMarkers) {
+ count = 0;
for(i = 0; i < 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);
+ item.show(true);
}
}
}
- for(; i < markerCount; i++) {
- item = markerGroup.getAt(i);
+ for(; count < markerCount; count++) {
+ item = markerGroup.getAt(count);
item.hide(true);
}
// for(i = 0; i < (chart.markerIndex || 0)-1; i++) {
// }
}
} 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
});
shadows = me.line.shadows;
for(j = 0; j < lnsh; j++) {
shadows[j].setAttributes({
- path: path
+ path: renderPath,
+ hidden: false
}, true);
}
}
if (me.fill) {
me.fillPath.setAttributes({
- path: fillPath
+ path: fillPath,
+ hidden: false
}, true);
}
if (showMarkers) {
+ count = 0;
for(i = 0; i < 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);
+ item.show(true);
}
}
}
- for(; i < markerCount; i++) {
- item = markerGroup.getAt(i);
+ for(; count < 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();
me.renderCallouts();
+
+ me.fireEvent('draw', me);
},
-
+
// @private called when a label is to be created.
onCreateLabel: function(storeItem, item, i, display) {
var me = this,
'y': bbox.y + bbox.height / 2
}, endLabelStyle || {}));
},
-
+
// @private called when a label is to be created.
onPlaceLabel: function(label, storeItem, item, i, display, animate) {
var me = this,
y = item.point[1],
radius = item.sprite.attr.radius,
bb, width, height;
-
+
label.setAttributes({
text: format(storeItem.get(field)),
hidden: true
}, true);
-
+
if (display == 'rotate') {
label.setAttributes({
'text-anchor': 'start',
x = x < bbox.x? bbox.x : x;
x = (x + width > bbox.x + bbox.width)? (x - (x + width - bbox.x - bbox.width)) : x;
y = (y - height < bbox.y)? bbox.y + height : y;
-
+
} else if (display == 'under' || display == 'over') {
//TODO(nicolas): find out why width/height values in circle bounding boxes are undefined.
bb = item.sprite.getBBox();
y = y - height < bbox.y? bbox.y + height : y;
y = (y + height > bbox.y + bbox.height) ? (y - (y + height - bbox.y - bbox.height)) : y;
}
-
+
if (me.chart.animate && !me.chart.resizing) {
label.show(true);
me.onAnimate(label, {
x: x,
y: y
}, true);
- if (resizing) {
+ if (resizing && me.animation) {
me.animation.on('afteranimate', function() {
label.show(true);
});
highlightItem: function() {
var me = this;
me.callParent(arguments);
- if (this.line && !this.highlighted) {
- if (!('__strokeWidth' in this.line)) {
- this.line.__strokeWidth = this.line.attr['stroke-width'] || 0;
+ if (me.line && !me.highlighted) {
+ if (!('__strokeWidth' in me.line)) {
+ me.line.__strokeWidth = me.line.attr['stroke-width'] || 0;
}
- if (this.line.__anim) {
- this.line.__anim.paused = true;
+ if (me.line.__anim) {
+ me.line.__anim.paused = true;
}
- this.line.__anim = Ext.create('Ext.fx.Anim', {
- target: this.line,
+ me.line.__anim = Ext.create('Ext.fx.Anim', {
+ target: me.line,
to: {
- 'stroke-width': this.line.__strokeWidth + 3
+ 'stroke-width': me.line.__strokeWidth + 3
}
});
- this.highlighted = true;
+ me.highlighted = true;
}
},
unHighlightItem: function() {
var me = this;
me.callParent(arguments);
- if (this.line && this.highlighted) {
- this.line.__anim = Ext.create('Ext.fx.Anim', {
- target: this.line,
+ if (me.line && me.highlighted) {
+ me.line.__anim = Ext.create('Ext.fx.Anim', {
+ target: me.line,
to: {
- 'stroke-width': this.line.__strokeWidth
+ 'stroke-width': me.line.__strokeWidth
}
});
- this.highlighted = false;
+ me.highlighted = false;
}
},
if (!display) {
return;
}
-
+
var me = this,
chart = me.chart,
surface = chart.surface,
a = (next[1] - prev[1]) / (next[0] - prev[0]);
aprev = (cur[1] - prev[1]) / (cur[0] - prev[0]);
anext = (next[1] - cur[1]) / (next[0] - cur[0]);
-
+
norm = Math.sqrt(1 + a * a);
dir = [1 / norm, a / norm];
normal = [-dir[1], dir[0]];
-
+
//keep the label always on the outer part of the "elbow"
if (aprev > 0 && anext < 0 && normal[1] < 0
|| aprev < 0 && anext > 0 && normal[1] > 0) {
boxy = y - bbox.height /2 - offsetBox;
boxw = bbox.width + 2 * offsetBox;
boxh = bbox.height + 2 * offsetBox;
-
+
//now check if we're out of bounds and invert the normal vector correspondingly
//this may add new overlaps between labels (but labels won't be out of bounds).
if (boxx < clipRect[0] || (boxx + boxw) > (clipRect[0] + clipRect[2])) {
//update positions
x = cur[0] + normal[0] * offsetFromViz;
y = cur[1] + normal[1] * offsetFromViz;
-
+
//update box position and dimensions
boxx = x + (normal[0] > 0? 0 : -(bbox.width + 2 * offsetBox));
boxy = y - bbox.height /2 - offsetBox;
boxw = bbox.width + 2 * offsetBox;
boxh = bbox.height + 2 * offsetBox;
-
+
if (chart.animate) {
//set the line from the middle of the pie to the box.
me.onAnimate(callout.lines, {
callout[p].show(true);
}
},
-
+
isItemInPoint: function(x, y, item, i) {
var me = this,
items = me.items,
yIntersect,
dist1, dist2, dist, midx, midy,
sqrt = Math.sqrt, abs = Math.abs;
-
+
nextItem = items[i];
prevItem = i && items[i - 1];
-
+
if (i >= ln) {
prevItem = items[ln - 1];
}
dist1 = sqrt((x - x1) * (x - x1) + (y - y1) * (y - y1));
dist2 = sqrt((x - x2) * (x - x2) + (y - y2) * (y - y2));
dist = Math.min(dist1, dist2);
-
+
if (dist <= tolerance) {
return dist == dist1? prevItem : nextItem;
}
return false;
},
-
+
// @private toggle visibility of all series elements (markers, sprites).
toggleAll: function(show) {
var me = this,
i, ln, shadow, shadows;
if (!show) {
- Ext.chart.series.Line.superclass.hideAll.call(me);
+ Ext.chart.series.Cartesian.prototype.hideAll.call(me);
}
else {
- Ext.chart.series.Line.superclass.showAll.call(me);
+ Ext.chart.series.Cartesian.prototype.showAll.call(me);
}
if (me.line) {
me.line.setAttributes({
}, true);
}
},
-
+
// @private hide all series elements (markers, sprites).
hideAll: function() {
this.toggleAll(false);
},
-
+
// @private hide all series elements (markers, sprites).
showAll: function() {
this.toggleAll(true);
}
-});</pre></pre></body></html>
\ No newline at end of file
+});
+</pre>
+</body>
+</html>