| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688 | 
							- <!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-Scatter'>/**
 
- </span> * @class Ext.chart.series.Scatter
 
-  * @extends Ext.chart.series.Cartesian
 
-  *
 
-  * Creates a Scatter Chart. The scatter plot is useful when trying to display more than two variables in the same visualization.
 
-  * These variables can be mapped into x, y coordinates and also to an element's radius/size, color, etc.
 
-  * As with all other series, the Scatter Series must be appended in the *series* Chart array configuration. See the Chart
 
-  * documentation for more information on creating charts. A typical configuration object for the scatter could be:
 
-  *
 
-  *     @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 }
 
-  *         ]
 
-  *     });
 
-  *
 
-  *     Ext.create('Ext.chart.Chart', {
 
-  *         renderTo: Ext.getBody(),
 
-  *         width: 500,
 
-  *         height: 300,
 
-  *         animate: true,
 
-  *         theme:'Category2',
 
-  *         store: store,
 
-  *         axes: [{
 
-  *             type: 'Numeric',
 
-  *             position: 'left',
 
-  *             fields: ['data2', 'data3'],
 
-  *             title: 'Sample Values',
 
-  *             grid: true,
 
-  *             minimum: 0
 
-  *         }, {
 
-  *             type: 'Category',
 
-  *             position: 'bottom',
 
-  *             fields: ['name'],
 
-  *             title: 'Sample Metrics'
 
-  *         }],
 
-  *         series: [{
 
-  *             type: 'scatter',
 
-  *             markerConfig: {
 
-  *                 radius: 5,
 
-  *                 size: 5
 
-  *             },
 
-  *             axis: 'left',
 
-  *             xField: 'name',
 
-  *             yField: 'data2'
 
-  *         }, {
 
-  *             type: 'scatter',
 
-  *             markerConfig: {
 
-  *                 radius: 5,
 
-  *                 size: 5
 
-  *             },
 
-  *             axis: 'left',
 
-  *             xField: 'name',
 
-  *             yField: 'data3'
 
-  *         }]
 
-  *     });
 
-  *
 
-  * In this configuration we add three different categories of scatter series. Each of them is bound to a different field of the same data store,
 
-  * `data1`, `data2` and `data3` respectively. All x-fields for the series must be the same field, in this case `name`.
 
-  * Each scatter series has a different styling configuration for markers, specified by the `markerConfig` object. Finally we set the left axis as
 
-  * axis to show the current values of the elements.
 
-  *
 
-  * @xtype scatter
 
-  */
 
- Ext.define('Ext.chart.series.Scatter', {
 
-     /* Begin Definitions */
 
-     extend: 'Ext.chart.series.Cartesian',
 
-     requires: ['Ext.chart.axis.Axis', 'Ext.chart.Shape', 'Ext.fx.Anim'],
 
-     /* End Definitions */
 
-     type: 'scatter',
 
-     alias: 'series.scatter',
 
- <span id='Ext-chart-series-Scatter-cfg-markerConfig'>    /**
 
- </span>     * @cfg {Object} markerConfig
 
-      * The display style for the scatter series markers.
 
-      */
 
- <span id='Ext-chart-series-Scatter-cfg-style'>    /**
 
- </span>     * @cfg {Object} style
 
-      * Append styling properties to this object for it to override theme properties.
 
-      */
 
-     
 
- <span id='Ext-chart-series-Scatter-cfg-axis'>    /**
 
- </span>     * @cfg {String/Array} 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. If multiple axes are being used, they should both be specified in in the configuration.
 
-      */
 
-     constructor: function(config) {
 
-         this.callParent(arguments);
 
-         var me = this,
 
-             shadow = me.chart.shadow,
 
-             surface = me.chart.surface, i, l;
 
-         Ext.apply(me, config, {
 
-             style: {},
 
-             markerConfig: {},
 
-             shadowAttributes: [{
 
-                 "stroke-width": 6,
 
-                 "stroke-opacity": 0.05,
 
-                 stroke: 'rgb(0, 0, 0)'
 
-             }, {
 
-                 "stroke-width": 4,
 
-                 "stroke-opacity": 0.1,
 
-                 stroke: 'rgb(0, 0, 0)'
 
-             }, {
 
-                 "stroke-width": 2,
 
-                 "stroke-opacity": 0.15,
 
-                 stroke: 'rgb(0, 0, 0)'
 
-             }]
 
-         });
 
-         me.group = surface.getGroup(me.seriesId);
 
-         if (shadow) {
 
-             for (i = 0, l = me.shadowAttributes.length; i < l; i++) {
 
-                 me.shadowGroups.push(surface.getGroup(me.seriesId + '-shadows' + i));
 
-             }
 
-         }
 
-     },
 
-     // @private Get chart and data boundaries
 
-     getBounds: function() {
 
-         var me = this,
 
-             chart = me.chart,
 
-             store = chart.getChartStore(),
 
-             chartAxes = chart.axes,
 
-             boundAxes = me.getAxesForXAndYFields(),
 
-             boundXAxis = boundAxes.xAxis,
 
-             boundYAxis = boundAxes.yAxis,
 
-             bbox, xScale, yScale, ln, minX, minY, maxX, maxY, i, axis, ends;
 
-         me.setBBox();
 
-         bbox = me.bbox;
 
-         if (axis = chartAxes.get(boundXAxis)) {
 
-             ends = axis.applyData();
 
-             minX = ends.from;
 
-             maxX = ends.to;
 
-         }
 
-         if (axis = chartAxes.get(boundYAxis)) {
 
-             ends = axis.applyData();
 
-             minY = ends.from;
 
-             maxY = ends.to;
 
-         }
 
-         // If a field was specified without a corresponding axis, create one to get bounds
 
-         if (me.xField && !Ext.isNumber(minX)) {
 
-             axis = me.getMinMaxXValues();
 
-             minX = axis[0];
 
-             maxX = axis[1];
 
-         }
 
-         if (me.yField && !Ext.isNumber(minY)) {
 
-             axis = me.getMinMaxYValues();
 
-             minY = axis[0];
 
-             maxY = axis[1];
 
-         }
 
-         if (isNaN(minX)) {
 
-             minX = 0;
 
-             maxX = store.getCount() - 1;
 
-             xScale = bbox.width / (store.getCount() - 1);
 
-         }
 
-         else {
 
-             xScale = bbox.width / (maxX - minX);
 
-         }
 
-         if (isNaN(minY)) {
 
-             minY = 0;
 
-             maxY = store.getCount() - 1;
 
-             yScale = bbox.height / (store.getCount() - 1);
 
-         }
 
-         else {
 
-             yScale = bbox.height / (maxY - minY);
 
-         }
 
-         return {
 
-             bbox: bbox,
 
-             minX: minX,
 
-             minY: minY,
 
-             xScale: xScale,
 
-             yScale: yScale
 
-         };
 
-     },
 
-     // @private Build an array of paths for the chart
 
-     getPaths: function() {
 
-         var me = this,
 
-             chart = me.chart,
 
-             enableShadows = chart.shadow,
 
-             store = chart.getChartStore(),
 
-             data = store.data.items,
 
-             i, ln, record,
 
-             group = me.group,
 
-             bounds = me.bounds = me.getBounds(),
 
-             bbox = me.bbox,
 
-             xScale = bounds.xScale,
 
-             yScale = bounds.yScale,
 
-             minX = bounds.minX,
 
-             minY = bounds.minY,
 
-             boxX = bbox.x,
 
-             boxY = bbox.y,
 
-             boxHeight = bbox.height,
 
-             items = me.items = [],
 
-             attrs = [],
 
-             x, y, xValue, yValue, sprite;
 
-         for (i = 0, ln = data.length; i < ln; i++) {
 
-             record = data[i];
 
-             xValue = record.get(me.xField);
 
-             yValue = record.get(me.yField);
 
-             //skip undefined or null values
 
-             if (typeof yValue == 'undefined' || (typeof yValue == 'string' && !yValue)
 
-                 || xValue == null || yValue == null) {
 
-                 //<debug warn>
 
-                 if (Ext.isDefined(Ext.global.console)) {
 
-                     Ext.global.console.warn("[Ext.chart.series.Scatter]  Skipping a store element with a value which is either undefined or null  at ", record, xValue, yValue);
 
-                 }
 
-                 //</debug>
 
-                 continue;
 
-             }
 
-             // Ensure a value
 
-             if (typeof xValue == 'string' || typeof xValue == 'object' && !Ext.isDate(xValue)) {
 
-                 xValue = i;
 
-             }
 
-             if (typeof yValue == 'string' || typeof yValue == 'object' && !Ext.isDate(yValue)) {
 
-                 yValue = i;
 
-             }
 
-             x = boxX + (xValue - minX) * xScale;
 
-             y = boxY + boxHeight - (yValue - minY) * yScale;
 
-             attrs.push({
 
-                 x: x,
 
-                 y: y
 
-             });
 
-             me.items.push({
 
-                 series: me,
 
-                 value: [xValue, yValue],
 
-                 point: [x, y],
 
-                 storeItem: record
 
-             });
 
-             // When resizing, reset before animating
 
-             if (chart.animate && chart.resizing) {
 
-                 sprite = group.getAt(i);
 
-                 if (sprite) {
 
-                     me.resetPoint(sprite);
 
-                     if (enableShadows) {
 
-                         me.resetShadow(sprite);
 
-                     }
 
-                 }
 
-             }
 
-         }
 
-         return attrs;
 
-     },
 
-     // @private translate point to the center
 
-     resetPoint: function(sprite) {
 
-         var bbox = this.bbox;
 
-         sprite.setAttributes({
 
-             translate: {
 
-                 x: (bbox.x + bbox.width) / 2,
 
-                 y: (bbox.y + bbox.height) / 2
 
-             }
 
-         }, true);
 
-     },
 
-     // @private translate shadows of a sprite to the center
 
-     resetShadow: function(sprite) {
 
-         var me = this,
 
-             shadows = sprite.shadows,
 
-             shadowAttributes = me.shadowAttributes,
 
-             ln = me.shadowGroups.length,
 
-             bbox = me.bbox,
 
-             i, attr;
 
-         for (i = 0; i < ln; i++) {
 
-             attr = Ext.apply({}, shadowAttributes[i]);
 
-             // TODO: fix this with setAttributes
 
-             if (attr.translate) {
 
-                 attr.translate.x += (bbox.x + bbox.width) / 2;
 
-                 attr.translate.y += (bbox.y + bbox.height) / 2;
 
-             }
 
-             else {
 
-                 attr.translate = {
 
-                     x: (bbox.x + bbox.width) / 2,
 
-                     y: (bbox.y + bbox.height) / 2
 
-                 };
 
-             }
 
-             shadows[i].setAttributes(attr, true);
 
-         }
 
-     },
 
-     // @private create a new point
 
-     createPoint: function(attr, type) {
 
-         var me = this,
 
-             chart = me.chart,
 
-             group = me.group,
 
-             bbox = me.bbox;
 
-         return Ext.chart.Shape[type](chart.surface, Ext.apply({}, {
 
-             x: 0,
 
-             y: 0,
 
-             group: group,
 
-             translate: {
 
-                 x: (bbox.x + bbox.width) / 2,
 
-                 y: (bbox.y + bbox.height) / 2
 
-             }
 
-         }, attr));
 
-     },
 
-     // @private create a new set of shadows for a sprite
 
-     createShadow: function(sprite, endMarkerStyle, type) {
 
-         var me = this,
 
-             chart = me.chart,
 
-             shadowGroups = me.shadowGroups,
 
-             shadowAttributes = me.shadowAttributes,
 
-             lnsh = shadowGroups.length,
 
-             bbox = me.bbox,
 
-             i, shadow, shadows, attr;
 
-         sprite.shadows = shadows = [];
 
-         for (i = 0; i < lnsh; i++) {
 
-             attr = Ext.apply({}, shadowAttributes[i]);
 
-             if (attr.translate) {
 
-                 attr.translate.x += (bbox.x + bbox.width) / 2;
 
-                 attr.translate.y += (bbox.y + bbox.height) / 2;
 
-             }
 
-             else {
 
-                 Ext.apply(attr, {
 
-                     translate: {
 
-                         x: (bbox.x + bbox.width) / 2,
 
-                         y: (bbox.y + bbox.height) / 2
 
-                     }
 
-                 });
 
-             }
 
-             Ext.apply(attr, endMarkerStyle);
 
-             shadow = Ext.chart.Shape[type](chart.surface, Ext.apply({}, {
 
-                 x: 0,
 
-                 y: 0,
 
-                 group: shadowGroups[i]
 
-             }, attr));
 
-             shadows.push(shadow);
 
-         }
 
-     },
 
- <span id='Ext-chart-series-Scatter-method-drawSeries'>    /**
 
- </span>     * Draws the series for the current chart.
 
-      */
 
-     drawSeries: function() {
 
-         var me = this,
 
-             chart = me.chart,
 
-             store = chart.getChartStore(),
 
-             group = me.group,
 
-             enableShadows = chart.shadow,
 
-             shadowGroups = me.shadowGroups,
 
-             shadowAttributes = me.shadowAttributes,
 
-             lnsh = shadowGroups.length,
 
-             sprite, attrs, attr, ln, i, endMarkerStyle, shindex, type, shadows,
 
-             rendererAttributes, shadowAttribute;
 
-         endMarkerStyle = Ext.apply(me.markerStyle, me.markerConfig);
 
-         type = endMarkerStyle.type;
 
-         delete endMarkerStyle.type;
 
-         //if the store is empty then there's nothing to be rendered
 
-         if (!store || !store.getCount()) {
 
-             me.hide();
 
-             me.items = [];
 
-             return;
 
-         }
 
-         me.unHighlightItem();
 
-         me.cleanHighlights();
 
-         attrs = me.getPaths();
 
-         ln = attrs.length;
 
-         for (i = 0; i < ln; i++) {
 
-             attr = attrs[i];
 
-             sprite = group.getAt(i);
 
-             Ext.apply(attr, endMarkerStyle);
 
-             // Create a new sprite if needed (no height)
 
-             if (!sprite) {
 
-                 sprite = me.createPoint(attr, type);
 
-                 if (enableShadows) {
 
-                     me.createShadow(sprite, endMarkerStyle, type);
 
-                 }
 
-             }
 
-             shadows = sprite.shadows;
 
-             if (chart.animate) {
 
-                 rendererAttributes = me.renderer(sprite, store.getAt(i), { translate: attr }, i, store);
 
-                 sprite._to = rendererAttributes;
 
-                 me.onAnimate(sprite, {
 
-                     to: rendererAttributes
 
-                 });
 
-                 //animate shadows
 
-                 for (shindex = 0; shindex < lnsh; shindex++) {
 
-                     shadowAttribute = Ext.apply({}, shadowAttributes[shindex]);
 
-                     rendererAttributes = me.renderer(shadows[shindex], store.getAt(i), Ext.apply({}, { 
 
-                         hidden: false,
 
-                         translate: {
 
-                             x: attr.x + (shadowAttribute.translate? shadowAttribute.translate.x : 0),
 
-                             y: attr.y + (shadowAttribute.translate? shadowAttribute.translate.y : 0)
 
-                         }
 
-                     }, shadowAttribute), i, store);
 
-                     me.onAnimate(shadows[shindex], { to: rendererAttributes });
 
-                 }
 
-             }
 
-             else {
 
-                 rendererAttributes = me.renderer(sprite, store.getAt(i), { translate: attr }, i, store);
 
-                 sprite._to = rendererAttributes;
 
-                 sprite.setAttributes(rendererAttributes, true);
 
-                 //animate shadows
 
-                 for (shindex = 0; shindex < lnsh; shindex++) {
 
-                     shadowAttribute = Ext.apply({}, shadowAttributes[shindex]);
 
-                     rendererAttributes = me.renderer(shadows[shindex], store.getAt(i), Ext.apply({}, { 
 
-                         hidden: false,
 
-                         translate: {
 
-                             x: attr.x + (shadowAttribute.translate? shadowAttribute.translate.x : 0),
 
-                             y: attr.y + (shadowAttribute.translate? shadowAttribute.translate.y : 0)
 
-                         } 
 
-                     }, shadowAttribute), i, store);
 
-                     shadows[shindex].setAttributes(rendererAttributes, true);
 
-                 }
 
-             }
 
-             me.items[i].sprite = sprite;
 
-         }
 
-         // Hide unused sprites
 
-         ln = group.getCount();
 
-         for (i = attrs.length; i < ln; i++) {
 
-             group.getAt(i).hide(true);
 
-         }
 
-         me.renderLabels();
 
-         me.renderCallouts();
 
-     },
 
-     // @private callback for when creating a label sprite.
 
-     onCreateLabel: function(storeItem, item, i, display) {
 
-         var me = this,
 
-             group = me.labelsGroup,
 
-             config = me.label,
 
-             endLabelStyle = Ext.apply({}, config, me.seriesLabelStyle),
 
-             bbox = me.bbox;
 
-         return me.chart.surface.add(Ext.apply({
 
-             type: 'text',
 
-             group: group,
 
-             x: item.point[0],
 
-             y: bbox.y + bbox.height / 2
 
-         }, endLabelStyle));
 
-     },
 
-     // @private callback for when placing a label sprite.
 
-     onPlaceLabel: function(label, storeItem, item, i, display, animate) {
 
-         var me = this,
 
-             chart = me.chart,
 
-             resizing = chart.resizing,
 
-             config = me.label,
 
-             format = config.renderer,
 
-             field = config.field,
 
-             bbox = me.bbox,
 
-             x = item.point[0],
 
-             y = item.point[1],
 
-             radius = item.sprite.attr.radius,
 
-             bb, width, height, anim;
 
-         label.setAttributes({
 
-             text: format(storeItem.get(field)),
 
-             hidden: true
 
-         }, true);
 
-         if (display == 'rotate') {
 
-             label.setAttributes({
 
-                 'text-anchor': 'start',
 
-                 'rotation': {
 
-                     x: x,
 
-                     y: y,
 
-                     degrees: -45
 
-                 }
 
-             }, true);
 
-             //correct label position to fit into the box
 
-             bb = label.getBBox();
 
-             width = bb.width;
 
-             height = bb.height;
 
-             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();
 
-             bb.width = bb.width || (radius * 2);
 
-             bb.height = bb.height || (radius * 2);
 
-             y = y + (display == 'over'? -bb.height : bb.height);
 
-             //correct label position to fit into the box
 
-             bb = label.getBBox();
 
-             width = bb.width/2;
 
-             height = bb.height/2;
 
-             x = x - width < bbox.x ? bbox.x + width : 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;
 
-             y = (y + height > bbox.y + bbox.height) ? (y - (y + height - bbox.y - bbox.height)) : y;
 
-         }
 
-         if (!chart.animate) {
 
-             label.setAttributes({
 
-                 x: x,
 
-                 y: y
 
-             }, true);
 
-             label.show(true);
 
-         }
 
-         else {
 
-             if (resizing) {
 
-                 anim = item.sprite.getActiveAnimation();
 
-                 if (anim) {
 
-                     anim.on('afteranimate', function() {
 
-                         label.setAttributes({
 
-                             x: x,
 
-                             y: y
 
-                         }, true);
 
-                         label.show(true);
 
-                     });
 
-                 }
 
-                 else {
 
-                     label.show(true);
 
-                 }
 
-             }
 
-             else {
 
-                 me.onAnimate(label, {
 
-                     to: {
 
-                         x: x,
 
-                         y: y
 
-                     }
 
-                 });
 
-             }
 
-         }
 
-     },
 
-     // @private callback for when placing a callout sprite.
 
-     onPlaceCallout: function(callout, storeItem, item, i, display, animate, index) {
 
-         var me = this,
 
-             chart = me.chart,
 
-             surface = chart.surface,
 
-             resizing = chart.resizing,
 
-             config = me.callouts,
 
-             items = me.items,
 
-             cur = item.point,
 
-             normal,
 
-             bbox = callout.label.getBBox(),
 
-             offsetFromViz = 30,
 
-             offsetToSide = 10,
 
-             offsetBox = 3,
 
-             boxx, boxy, boxw, boxh,
 
-             p, clipRect = me.bbox,
 
-             x, y;
 
-         //position
 
-         normal = [Math.cos(Math.PI /4), -Math.sin(Math.PI /4)];
 
-         x = cur[0] + normal[0] * offsetFromViz;
 
-         y = cur[1] + normal[1] * offsetFromViz;
 
-         //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;
 
-         //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])) {
 
-             normal[0] *= -1;
 
-         }
 
-         if (boxy < clipRect[1] || (boxy + boxh) > (clipRect[1] + clipRect[3])) {
 
-             normal[1] *= -1;
 
-         }
 
-         //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, {
 
-                 to: {
 
-                     path: ["M", cur[0], cur[1], "L", x, y, "Z"]
 
-                 }
 
-             }, true);
 
-             //set box position
 
-             me.onAnimate(callout.box, {
 
-                 to: {
 
-                     x: boxx,
 
-                     y: boxy,
 
-                     width: boxw,
 
-                     height: boxh
 
-                 }
 
-             }, true);
 
-             //set text position
 
-             me.onAnimate(callout.label, {
 
-                 to: {
 
-                     x: x + (normal[0] > 0? offsetBox : -(bbox.width + offsetBox)),
 
-                     y: y
 
-                 }
 
-             }, true);
 
-         } else {
 
-             //set the line from the middle of the pie to the box.
 
-             callout.lines.setAttributes({
 
-                 path: ["M", cur[0], cur[1], "L", x, y, "Z"]
 
-             }, true);
 
-             //set box position
 
-             callout.box.setAttributes({
 
-                 x: boxx,
 
-                 y: boxy,
 
-                 width: boxw,
 
-                 height: boxh
 
-             }, true);
 
-             //set text position
 
-             callout.label.setAttributes({
 
-                 x: x + (normal[0] > 0? offsetBox : -(bbox.width + offsetBox)),
 
-                 y: y
 
-             }, true);
 
-         }
 
-         for (p in callout) {
 
-             callout[p].show(true);
 
-         }
 
-     },
 
-     // @private handles sprite animation for the series.
 
-     onAnimate: function(sprite, attr) {
 
-         sprite.show();
 
-         return this.callParent(arguments);
 
-     },
 
-     isItemInPoint: function(x, y, item) {
 
-         var point,
 
-             tolerance = 10,
 
-             abs = Math.abs;
 
-         function dist(point) {
 
-             var dx = abs(point[0] - x),
 
-                 dy = abs(point[1] - y);
 
-             return Math.sqrt(dx * dx + dy * dy);
 
-         }
 
-         point = item.point;
 
-         return (point[0] - tolerance <= x && point[0] + tolerance >= x &&
 
-             point[1] - tolerance <= y && point[1] + tolerance >= y);
 
-     }
 
- });
 
- </pre>
 
- </body>
 
- </html>
 
 
  |