highcharts-js-rails 0.1.9 → 0.1.10
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +6 -0
- data/highcharts-js-rails.gemspec +1 -1
- data/lib/highcharts/plot_options/plot_type.rb +2 -0
- data/lib/highcharts/plot_options.rb +4 -0
- data/vendor/assets/javascripts/highcharts/adapters/mootools.js +12 -6
- data/vendor/assets/javascripts/highcharts/adapters/prototype.js +5 -1
- data/vendor/assets/javascripts/highcharts/modules/canvas-tools.js +1 -1
- data/vendor/assets/javascripts/highcharts/modules/data.js +277 -0
- data/vendor/assets/javascripts/highcharts/modules/exporting.js +1 -1
- data/vendor/assets/javascripts/highcharts/themes/dark-blue.js +8 -8
- data/vendor/assets/javascripts/highcharts/themes/dark-green.js +7 -7
- data/vendor/assets/javascripts/highcharts/themes/gray.js +9 -9
- data/vendor/assets/javascripts/highcharts/themes/grid.js +1 -1
- data/vendor/assets/javascripts/highcharts-more.js +29 -19
- data/vendor/assets/javascripts/highcharts.js +1396 -1011
- metadata +10 -3
@@ -2,7 +2,7 @@
|
|
2
2
|
// @compilation_level SIMPLE_OPTIMIZATIONS
|
3
3
|
|
4
4
|
/**
|
5
|
-
* @license Highcharts JS v2.2
|
5
|
+
* @license Highcharts JS v2.3.2 (2012-08-31)
|
6
6
|
*
|
7
7
|
* (c) 2009-2011 Torstein Hønsi
|
8
8
|
*
|
@@ -32,7 +32,8 @@ var UNDEFINED,
|
|
32
32
|
|
33
33
|
// some variables
|
34
34
|
userAgent = navigator.userAgent,
|
35
|
-
|
35
|
+
isOpera = win.opera,
|
36
|
+
isIE = /msie/i.test(userAgent) && !isOpera,
|
36
37
|
docMode8 = doc.documentMode === 8,
|
37
38
|
isWebKit = /AppleWebKit/.test(userAgent),
|
38
39
|
isFirefox = /Firefox/.test(userAgent),
|
@@ -375,6 +376,23 @@ function pad(number, length) {
|
|
375
376
|
return new Array((length || 2) + 1 - String(number).length).join(0) + number;
|
376
377
|
}
|
377
378
|
|
379
|
+
/**
|
380
|
+
* Wrap a method with extended functionality, preserving the original function
|
381
|
+
* @param {Object} obj The context object that the method belongs to
|
382
|
+
* @param {String} method The name of the method to extend
|
383
|
+
* @param {Function} func A wrapper function callback. This function is called with the same arguments
|
384
|
+
* as the original function, except that the original function is unshifted and passed as the first
|
385
|
+
* argument.
|
386
|
+
*/
|
387
|
+
function wrap(obj, method, func) {
|
388
|
+
var proceed = obj[method];
|
389
|
+
obj[method] = function () {
|
390
|
+
var args = Array.prototype.slice.call(arguments);
|
391
|
+
args.unshift(proceed);
|
392
|
+
return func.apply(this, args);
|
393
|
+
};
|
394
|
+
}
|
395
|
+
|
378
396
|
/**
|
379
397
|
* Based on http://www.php.net/manual/en/function.strftime.php
|
380
398
|
* @param {String} format
|
@@ -836,6 +854,16 @@ function correctFloat(num) {
|
|
836
854
|
);
|
837
855
|
}
|
838
856
|
|
857
|
+
/**
|
858
|
+
* Set the global animation to either a given value, or fall back to the
|
859
|
+
* given chart's animation option
|
860
|
+
* @param {Object} animation
|
861
|
+
* @param {Object} chart
|
862
|
+
*/
|
863
|
+
function setAnimation(animation, chart) {
|
864
|
+
globalAnimation = pick(animation, chart.animation);
|
865
|
+
}
|
866
|
+
|
839
867
|
/**
|
840
868
|
* The time unit lookup
|
841
869
|
*/
|
@@ -947,28 +975,338 @@ pathAnim = {
|
|
947
975
|
}
|
948
976
|
};
|
949
977
|
|
950
|
-
|
951
|
-
/**
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
978
|
+
(function ($) {
|
979
|
+
/**
|
980
|
+
* The default HighchartsAdapter for jQuery
|
981
|
+
*/
|
982
|
+
win.HighchartsAdapter = win.HighchartsAdapter || ($ && {
|
983
|
+
|
984
|
+
/**
|
985
|
+
* Initialize the adapter by applying some extensions to jQuery
|
986
|
+
*/
|
987
|
+
init: function (pathAnim) {
|
988
|
+
|
989
|
+
// extend the animate function to allow SVG animations
|
990
|
+
var Fx = $.fx,
|
991
|
+
Step = Fx.step,
|
992
|
+
dSetter,
|
993
|
+
Tween = $.Tween,
|
994
|
+
propHooks = Tween && Tween.propHooks;
|
995
|
+
|
996
|
+
/*jslint unparam: true*//* allow unused param x in this function */
|
997
|
+
$.extend($.easing, {
|
998
|
+
easeOutQuad: function (x, t, b, c, d) {
|
999
|
+
return -c * (t /= d) * (t - 2) + b;
|
1000
|
+
}
|
1001
|
+
});
|
1002
|
+
/*jslint unparam: false*/
|
1003
|
+
|
1004
|
+
|
1005
|
+
// extend some methods to check for elem.attr, which means it is a Highcharts SVG object
|
1006
|
+
$.each(['cur', '_default', 'width', 'height'], function (i, fn) {
|
1007
|
+
var obj = Step,
|
1008
|
+
base,
|
1009
|
+
elem;
|
1010
|
+
|
1011
|
+
// Handle different parent objects
|
1012
|
+
if (fn === 'cur') {
|
1013
|
+
obj = Fx.prototype; // 'cur', the getter, relates to Fx.prototype
|
1014
|
+
|
1015
|
+
} else if (fn === '_default' && Tween) { // jQuery 1.8 model
|
1016
|
+
obj = propHooks[fn];
|
1017
|
+
fn = 'set';
|
1018
|
+
}
|
1019
|
+
|
1020
|
+
// Overwrite the method
|
1021
|
+
base = obj[fn];
|
1022
|
+
if (base) { // step.width and step.height don't exist in jQuery < 1.7
|
1023
|
+
|
1024
|
+
// create the extended function replacement
|
1025
|
+
obj[fn] = function (fx) {
|
1026
|
+
|
1027
|
+
// Fx.prototype.cur does not use fx argument
|
1028
|
+
fx = i ? fx : this;
|
1029
|
+
|
1030
|
+
// shortcut
|
1031
|
+
elem = fx.elem;
|
1032
|
+
|
1033
|
+
// Fx.prototype.cur returns the current value. The other ones are setters
|
1034
|
+
// and returning a value has no effect.
|
1035
|
+
return elem.attr ? // is SVG element wrapper
|
1036
|
+
elem.attr(fx.prop, fn === 'cur' ? UNDEFINED : fx.now) : // apply the SVG wrapper's method
|
1037
|
+
base.apply(this, arguments); // use jQuery's built-in method
|
1038
|
+
};
|
1039
|
+
}
|
1040
|
+
});
|
1041
|
+
|
1042
|
+
|
1043
|
+
// Define the setter function for d (path definitions)
|
1044
|
+
dSetter = function (fx) {
|
1045
|
+
var elem = fx.elem,
|
1046
|
+
ends;
|
1047
|
+
|
1048
|
+
// Normally start and end should be set in state == 0, but sometimes,
|
1049
|
+
// for reasons unknown, this doesn't happen. Perhaps state == 0 is skipped
|
1050
|
+
// in these cases
|
1051
|
+
if (!fx.started) {
|
1052
|
+
ends = pathAnim.init(elem, elem.d, elem.toD);
|
1053
|
+
fx.start = ends[0];
|
1054
|
+
fx.end = ends[1];
|
1055
|
+
fx.started = true;
|
1056
|
+
}
|
1057
|
+
|
1058
|
+
|
1059
|
+
// interpolate each value of the path
|
1060
|
+
elem.attr('d', pathAnim.step(fx.start, fx.end, fx.pos, elem.toD));
|
1061
|
+
};
|
1062
|
+
|
1063
|
+
// jQuery 1.8 style
|
1064
|
+
if (Tween) {
|
1065
|
+
propHooks.d = {
|
1066
|
+
set: dSetter
|
1067
|
+
};
|
1068
|
+
// pre 1.8
|
1069
|
+
} else {
|
1070
|
+
// animate paths
|
1071
|
+
Step.d = dSetter;
|
1072
|
+
}
|
1073
|
+
|
1074
|
+
/**
|
1075
|
+
* Utility for iterating over an array. Parameters are reversed compared to jQuery.
|
1076
|
+
* @param {Array} arr
|
1077
|
+
* @param {Function} fn
|
1078
|
+
*/
|
1079
|
+
this.each = Array.prototype.forEach ?
|
1080
|
+
function (arr, fn) { // modern browsers
|
1081
|
+
return Array.prototype.forEach.call(arr, fn);
|
1082
|
+
|
1083
|
+
} :
|
1084
|
+
function (arr, fn) { // legacy
|
1085
|
+
var i = 0,
|
1086
|
+
len = arr.length;
|
1087
|
+
for (; i < len; i++) {
|
1088
|
+
if (fn.call(arr[i], arr[i], i, arr) === false) {
|
1089
|
+
return i;
|
1090
|
+
}
|
1091
|
+
}
|
1092
|
+
};
|
1093
|
+
|
1094
|
+
// Register Highcharts as a jQuery plugin
|
1095
|
+
// TODO: MooTools and prototype as well?
|
1096
|
+
// TODO: StockChart
|
1097
|
+
/*$.fn.highcharts = function(options, callback) {
|
1098
|
+
options.chart = merge(options.chart, { renderTo: this[0] });
|
1099
|
+
this.chart = new Chart(options, callback);
|
1100
|
+
return this;
|
1101
|
+
};*/
|
1102
|
+
},
|
1103
|
+
|
1104
|
+
/**
|
1105
|
+
* Downloads a script and executes a callback when done.
|
1106
|
+
* @param {String} scriptLocation
|
1107
|
+
* @param {Function} callback
|
1108
|
+
*/
|
1109
|
+
getScript: $.getScript,
|
1110
|
+
|
1111
|
+
/**
|
1112
|
+
* Return the index of an item in an array, or -1 if not found
|
1113
|
+
*/
|
1114
|
+
inArray: $.inArray,
|
1115
|
+
|
1116
|
+
/**
|
1117
|
+
* A direct link to jQuery methods. MooTools and Prototype adapters must be implemented for each case of method.
|
1118
|
+
* @param {Object} elem The HTML element
|
1119
|
+
* @param {String} method Which method to run on the wrapped element
|
1120
|
+
*/
|
1121
|
+
adapterRun: function (elem, method) {
|
1122
|
+
return $(elem)[method]();
|
1123
|
+
},
|
1124
|
+
|
1125
|
+
/**
|
1126
|
+
* Filter an array
|
1127
|
+
*/
|
1128
|
+
grep: $.grep,
|
1129
|
+
|
1130
|
+
/**
|
1131
|
+
* Map an array
|
1132
|
+
* @param {Array} arr
|
1133
|
+
* @param {Function} fn
|
1134
|
+
*/
|
1135
|
+
map: function (arr, fn) {
|
1136
|
+
//return jQuery.map(arr, fn);
|
1137
|
+
var results = [],
|
1138
|
+
i = 0,
|
1139
|
+
len = arr.length;
|
1140
|
+
for (; i < len; i++) {
|
1141
|
+
results[i] = fn.call(arr[i], arr[i], i, arr);
|
1142
|
+
}
|
1143
|
+
return results;
|
1144
|
+
|
1145
|
+
},
|
1146
|
+
|
1147
|
+
/**
|
1148
|
+
* Deep merge two objects and return a third object
|
1149
|
+
*/
|
1150
|
+
merge: function () {
|
1151
|
+
var args = arguments;
|
1152
|
+
return $.extend(true, null, args[0], args[1], args[2], args[3]);
|
1153
|
+
},
|
1154
|
+
|
1155
|
+
/**
|
1156
|
+
* Get the position of an element relative to the top left of the page
|
1157
|
+
*/
|
1158
|
+
offset: function (el) {
|
1159
|
+
return $(el).offset();
|
1160
|
+
},
|
1161
|
+
|
1162
|
+
/**
|
1163
|
+
* Add an event listener
|
1164
|
+
* @param {Object} el A HTML element or custom object
|
1165
|
+
* @param {String} event The event type
|
1166
|
+
* @param {Function} fn The event handler
|
1167
|
+
*/
|
1168
|
+
addEvent: function (el, event, fn) {
|
1169
|
+
$(el).bind(event, fn);
|
1170
|
+
},
|
1171
|
+
|
1172
|
+
/**
|
1173
|
+
* Remove event added with addEvent
|
1174
|
+
* @param {Object} el The object
|
1175
|
+
* @param {String} eventType The event type. Leave blank to remove all events.
|
1176
|
+
* @param {Function} handler The function to remove
|
1177
|
+
*/
|
1178
|
+
removeEvent: function (el, eventType, handler) {
|
1179
|
+
// workaround for jQuery issue with unbinding custom events:
|
1180
|
+
// http://forum.jQuery.com/topic/javascript-error-when-unbinding-a-custom-event-using-jQuery-1-4-2
|
1181
|
+
var func = doc.removeEventListener ? 'removeEventListener' : 'detachEvent';
|
1182
|
+
if (doc[func] && !el[func]) {
|
1183
|
+
el[func] = function () {};
|
1184
|
+
}
|
1185
|
+
|
1186
|
+
$(el).unbind(eventType, handler);
|
1187
|
+
},
|
1188
|
+
|
1189
|
+
/**
|
1190
|
+
* Fire an event on a custom object
|
1191
|
+
* @param {Object} el
|
1192
|
+
* @param {String} type
|
1193
|
+
* @param {Object} eventArguments
|
1194
|
+
* @param {Function} defaultFunction
|
1195
|
+
*/
|
1196
|
+
fireEvent: function (el, type, eventArguments, defaultFunction) {
|
1197
|
+
var event = $.Event(type),
|
1198
|
+
detachedType = 'detached' + type,
|
1199
|
+
defaultPrevented;
|
1200
|
+
|
1201
|
+
// Remove warnings in Chrome when accessing layerX and layerY. Although Highcharts
|
1202
|
+
// never uses these properties, Chrome includes them in the default click event and
|
1203
|
+
// raises the warning when they are copied over in the extend statement below.
|
1204
|
+
//
|
1205
|
+
// To avoid problems in IE (see #1010) where we cannot delete the properties and avoid
|
1206
|
+
// testing if they are there (warning in chrome) the only option is to test if running IE.
|
1207
|
+
if (!isIE && eventArguments) {
|
1208
|
+
delete eventArguments.layerX;
|
1209
|
+
delete eventArguments.layerY;
|
1210
|
+
}
|
1211
|
+
|
1212
|
+
extend(event, eventArguments);
|
1213
|
+
|
1214
|
+
// Prevent jQuery from triggering the object method that is named the
|
1215
|
+
// same as the event. For example, if the event is 'select', jQuery
|
1216
|
+
// attempts calling el.select and it goes into a loop.
|
1217
|
+
if (el[type]) {
|
1218
|
+
el[detachedType] = el[type];
|
1219
|
+
el[type] = null;
|
1220
|
+
}
|
1221
|
+
|
1222
|
+
// Wrap preventDefault and stopPropagation in try/catch blocks in
|
1223
|
+
// order to prevent JS errors when cancelling events on non-DOM
|
1224
|
+
// objects. #615.
|
1225
|
+
/*jslint unparam: true*/
|
1226
|
+
$.each(['preventDefault', 'stopPropagation'], function (i, fn) {
|
1227
|
+
var base = event[fn];
|
1228
|
+
event[fn] = function () {
|
1229
|
+
try {
|
1230
|
+
base.call(event);
|
1231
|
+
} catch (e) {
|
1232
|
+
if (fn === 'preventDefault') {
|
1233
|
+
defaultPrevented = true;
|
1234
|
+
}
|
1235
|
+
}
|
1236
|
+
};
|
1237
|
+
});
|
1238
|
+
/*jslint unparam: false*/
|
1239
|
+
|
1240
|
+
// trigger it
|
1241
|
+
$(el).trigger(event);
|
1242
|
+
|
1243
|
+
// attach the method
|
1244
|
+
if (el[detachedType]) {
|
1245
|
+
el[type] = el[detachedType];
|
1246
|
+
el[detachedType] = null;
|
1247
|
+
}
|
1248
|
+
|
1249
|
+
if (defaultFunction && !event.isDefaultPrevented() && !defaultPrevented) {
|
1250
|
+
defaultFunction(event);
|
1251
|
+
}
|
1252
|
+
},
|
1253
|
+
|
1254
|
+
/**
|
1255
|
+
* Extension method needed for MooTools
|
1256
|
+
*/
|
1257
|
+
washMouseEvent: function (e) {
|
1258
|
+
var ret = e.originalEvent || e;
|
1259
|
+
|
1260
|
+
// computed by jQuery, needed by IE8
|
1261
|
+
ret.pageX = e.pageX;
|
1262
|
+
ret.pageY = e.pageY;
|
1263
|
+
|
1264
|
+
return ret;
|
1265
|
+
},
|
1266
|
+
|
1267
|
+
/**
|
1268
|
+
* Animate a HTML element or SVG element wrapper
|
1269
|
+
* @param {Object} el
|
1270
|
+
* @param {Object} params
|
1271
|
+
* @param {Object} options jQuery-like animation options: duration, easing, callback
|
1272
|
+
*/
|
1273
|
+
animate: function (el, params, options) {
|
1274
|
+
var $el = $(el);
|
1275
|
+
if (params.d) {
|
1276
|
+
el.toD = params.d; // keep the array form for paths, used in $.fx.step.d
|
1277
|
+
params.d = 1; // because in jQuery, animating to an array has a different meaning
|
1278
|
+
}
|
1279
|
+
|
1280
|
+
$el.stop();
|
1281
|
+
$el.animate(params, options);
|
1282
|
+
|
1283
|
+
},
|
1284
|
+
/**
|
1285
|
+
* Stop running animation
|
1286
|
+
*/
|
1287
|
+
stop: function (el) {
|
1288
|
+
$(el).stop();
|
1289
|
+
}
|
1290
|
+
});
|
1291
|
+
}(win.jQuery));
|
961
1292
|
|
962
1293
|
|
963
1294
|
// check for a custom HighchartsAdapter defined prior to this file
|
964
1295
|
var globalAdapter = win.HighchartsAdapter,
|
965
|
-
adapter = globalAdapter || {}
|
1296
|
+
adapter = globalAdapter || {};
|
1297
|
+
|
1298
|
+
// Initialize the adapter
|
1299
|
+
if (globalAdapter) {
|
1300
|
+
globalAdapter.init.call(globalAdapter, pathAnim);
|
1301
|
+
}
|
1302
|
+
|
966
1303
|
|
967
1304
|
// Utility functions. If the HighchartsAdapter is not defined, adapter is an empty object
|
968
1305
|
// and all the utility functions will be null. In that case they are populated by the
|
969
1306
|
// default adapters below.
|
970
|
-
|
1307
|
+
var adapterRun = adapter.adapterRun,
|
971
1308
|
getScript = adapter.getScript,
|
1309
|
+
inArray = adapter.inArray,
|
972
1310
|
each = adapter.each,
|
973
1311
|
grep = adapter.grep,
|
974
1312
|
offset = adapter.offset,
|
@@ -981,281 +1319,8 @@ var globalAdapter = win.HighchartsAdapter,
|
|
981
1319
|
animate = adapter.animate,
|
982
1320
|
stop = adapter.stop;
|
983
1321
|
|
984
|
-
/*
|
985
|
-
* Define the adapter for frameworks. If an external adapter is not defined,
|
986
|
-
* Highcharts reverts to the built-in jQuery adapter.
|
987
|
-
*/
|
988
|
-
if (globalAdapter && globalAdapter.init) {
|
989
|
-
// Initialize the adapter with the pathAnim object that takes care
|
990
|
-
// of path animations.
|
991
|
-
globalAdapter.init(pathAnim);
|
992
|
-
}
|
993
|
-
if (!globalAdapter && win.jQuery) {
|
994
|
-
var jQ = jQuery;
|
995
|
-
|
996
|
-
/**
|
997
|
-
* Downloads a script and executes a callback when done.
|
998
|
-
* @param {String} scriptLocation
|
999
|
-
* @param {Function} callback
|
1000
|
-
*/
|
1001
|
-
getScript = jQ.getScript;
|
1002
|
-
|
1003
|
-
/**
|
1004
|
-
* A direct link to jQuery methods. MooTools and Prototype adapters must be implemented for each case of method.
|
1005
|
-
* @param {Object} elem The HTML element
|
1006
|
-
* @param {String} method Which method to run on the wrapped element
|
1007
|
-
*/
|
1008
|
-
adapterRun = function (elem, method) {
|
1009
|
-
return jQ(elem)[method]();
|
1010
|
-
};
|
1011
|
-
|
1012
|
-
/**
|
1013
|
-
* Utility for iterating over an array. Parameters are reversed compared to jQuery.
|
1014
|
-
* @param {Array} arr
|
1015
|
-
* @param {Function} fn
|
1016
|
-
*/
|
1017
|
-
each = function (arr, fn) {
|
1018
|
-
var i = 0,
|
1019
|
-
len = arr.length;
|
1020
|
-
for (; i < len; i++) {
|
1021
|
-
if (fn.call(arr[i], arr[i], i, arr) === false) {
|
1022
|
-
return i;
|
1023
|
-
}
|
1024
|
-
}
|
1025
|
-
};
|
1026
|
-
|
1027
|
-
/**
|
1028
|
-
* Filter an array
|
1029
|
-
*/
|
1030
|
-
grep = jQ.grep;
|
1031
|
-
|
1032
|
-
/**
|
1033
|
-
* Map an array
|
1034
|
-
* @param {Array} arr
|
1035
|
-
* @param {Function} fn
|
1036
|
-
*/
|
1037
|
-
map = function (arr, fn) {
|
1038
|
-
//return jQuery.map(arr, fn);
|
1039
|
-
var results = [],
|
1040
|
-
i = 0,
|
1041
|
-
len = arr.length;
|
1042
|
-
for (; i < len; i++) {
|
1043
|
-
results[i] = fn.call(arr[i], arr[i], i, arr);
|
1044
|
-
}
|
1045
|
-
return results;
|
1046
|
-
|
1047
|
-
};
|
1048
|
-
|
1049
|
-
/**
|
1050
|
-
* Deep merge two objects and return a third object
|
1051
|
-
*/
|
1052
|
-
merge = function () {
|
1053
|
-
var args = arguments;
|
1054
|
-
return jQ.extend(true, null, args[0], args[1], args[2], args[3]);
|
1055
|
-
};
|
1056
|
-
|
1057
|
-
/**
|
1058
|
-
* Get the position of an element relative to the top left of the page
|
1059
|
-
*/
|
1060
|
-
offset = function (el) {
|
1061
|
-
return jQ(el).offset();
|
1062
|
-
};
|
1063
|
-
|
1064
|
-
/**
|
1065
|
-
* Add an event listener
|
1066
|
-
* @param {Object} el A HTML element or custom object
|
1067
|
-
* @param {String} event The event type
|
1068
|
-
* @param {Function} fn The event handler
|
1069
|
-
*/
|
1070
|
-
addEvent = function (el, event, fn) {
|
1071
|
-
jQ(el).bind(event, fn);
|
1072
|
-
};
|
1073
|
-
|
1074
|
-
/**
|
1075
|
-
* Remove event added with addEvent
|
1076
|
-
* @param {Object} el The object
|
1077
|
-
* @param {String} eventType The event type. Leave blank to remove all events.
|
1078
|
-
* @param {Function} handler The function to remove
|
1079
|
-
*/
|
1080
|
-
removeEvent = function (el, eventType, handler) {
|
1081
|
-
// workaround for jQuery issue with unbinding custom events:
|
1082
|
-
// http://forum.jquery.com/topic/javascript-error-when-unbinding-a-custom-event-using-jquery-1-4-2
|
1083
|
-
var func = doc.removeEventListener ? 'removeEventListener' : 'detachEvent';
|
1084
|
-
if (doc[func] && !el[func]) {
|
1085
|
-
el[func] = function () {};
|
1086
|
-
}
|
1087
|
-
|
1088
|
-
jQ(el).unbind(eventType, handler);
|
1089
|
-
};
|
1090
|
-
|
1091
|
-
/**
|
1092
|
-
* Fire an event on a custom object
|
1093
|
-
* @param {Object} el
|
1094
|
-
* @param {String} type
|
1095
|
-
* @param {Object} eventArguments
|
1096
|
-
* @param {Function} defaultFunction
|
1097
|
-
*/
|
1098
|
-
fireEvent = function (el, type, eventArguments, defaultFunction) {
|
1099
|
-
var event = jQ.Event(type),
|
1100
|
-
detachedType = 'detached' + type,
|
1101
|
-
defaultPrevented;
|
1102
|
-
|
1103
|
-
// Remove warnings in Chrome when accessing layerX and layerY. Although Highcharts
|
1104
|
-
// never uses these properties, Chrome includes them in the default click event and
|
1105
|
-
// raises the warning when they are copied over in the extend statement below.
|
1106
|
-
//
|
1107
|
-
// To avoid problems in IE (see #1010) where we cannot delete the properties and avoid
|
1108
|
-
// testing if they are there (warning in chrome) the only option is to test if running IE.
|
1109
|
-
if (!isIE && eventArguments) {
|
1110
|
-
delete eventArguments.layerX;
|
1111
|
-
delete eventArguments.layerY;
|
1112
|
-
}
|
1113
|
-
|
1114
|
-
extend(event, eventArguments);
|
1115
|
-
|
1116
|
-
// Prevent jQuery from triggering the object method that is named the
|
1117
|
-
// same as the event. For example, if the event is 'select', jQuery
|
1118
|
-
// attempts calling el.select and it goes into a loop.
|
1119
|
-
if (el[type]) {
|
1120
|
-
el[detachedType] = el[type];
|
1121
|
-
el[type] = null;
|
1122
|
-
}
|
1123
|
-
|
1124
|
-
// Wrap preventDefault and stopPropagation in try/catch blocks in
|
1125
|
-
// order to prevent JS errors when cancelling events on non-DOM
|
1126
|
-
// objects. #615.
|
1127
|
-
each(['preventDefault', 'stopPropagation'], function (fn) {
|
1128
|
-
var base = event[fn];
|
1129
|
-
event[fn] = function () {
|
1130
|
-
try {
|
1131
|
-
base.call(event);
|
1132
|
-
} catch (e) {
|
1133
|
-
if (fn === 'preventDefault') {
|
1134
|
-
defaultPrevented = true;
|
1135
|
-
}
|
1136
|
-
}
|
1137
|
-
};
|
1138
|
-
});
|
1139
|
-
|
1140
|
-
// trigger it
|
1141
|
-
jQ(el).trigger(event);
|
1142
|
-
|
1143
|
-
// attach the method
|
1144
|
-
if (el[detachedType]) {
|
1145
|
-
el[type] = el[detachedType];
|
1146
|
-
el[detachedType] = null;
|
1147
|
-
}
|
1148
|
-
|
1149
|
-
if (defaultFunction && !event.isDefaultPrevented() && !defaultPrevented) {
|
1150
|
-
defaultFunction(event);
|
1151
|
-
}
|
1152
|
-
};
|
1153
|
-
|
1154
|
-
/**
|
1155
|
-
* Extension method needed for MooTools
|
1156
|
-
*/
|
1157
|
-
washMouseEvent = function (e) {
|
1158
|
-
return e;
|
1159
|
-
};
|
1160
|
-
|
1161
|
-
/**
|
1162
|
-
* Animate a HTML element or SVG element wrapper
|
1163
|
-
* @param {Object} el
|
1164
|
-
* @param {Object} params
|
1165
|
-
* @param {Object} options jQuery-like animation options: duration, easing, callback
|
1166
|
-
*/
|
1167
|
-
animate = function (el, params, options) {
|
1168
|
-
var $el = jQ(el);
|
1169
|
-
if (params.d) {
|
1170
|
-
el.toD = params.d; // keep the array form for paths, used in jQ.fx.step.d
|
1171
|
-
params.d = 1; // because in jQuery, animating to an array has a different meaning
|
1172
|
-
}
|
1173
|
-
|
1174
|
-
$el.stop();
|
1175
|
-
$el.animate(params, options);
|
1176
|
-
|
1177
|
-
};
|
1178
|
-
/**
|
1179
|
-
* Stop running animation
|
1180
|
-
*/
|
1181
|
-
stop = function (el) {
|
1182
|
-
jQ(el).stop();
|
1183
|
-
};
|
1184
|
-
|
1185
|
-
|
1186
|
-
//=== Extend jQuery on init
|
1187
|
-
|
1188
|
-
/*jslint unparam: true*//* allow unused param x in this function */
|
1189
|
-
jQ.extend(jQ.easing, {
|
1190
|
-
easeOutQuad: function (x, t, b, c, d) {
|
1191
|
-
return -c * (t /= d) * (t - 2) + b;
|
1192
|
-
}
|
1193
|
-
});
|
1194
|
-
/*jslint unparam: false*/
|
1195
|
-
|
1196
|
-
// extend the animate function to allow SVG animations
|
1197
|
-
var jFx = jQ.fx,
|
1198
|
-
jStep = jFx.step;
|
1199
|
-
|
1200
|
-
// extend some methods to check for elem.attr, which means it is a Highcharts SVG object
|
1201
|
-
each(['cur', '_default', 'width', 'height'], function (fn, i) {
|
1202
|
-
var obj = jStep,
|
1203
|
-
base,
|
1204
|
-
elem;
|
1205
|
-
|
1206
|
-
// Handle different parent objects
|
1207
|
-
if (fn === 'cur') {
|
1208
|
-
obj = jFx.prototype; // 'cur', the getter, relates to jFx.prototype
|
1209
|
-
|
1210
|
-
} else if (fn === '_default' && jQ.Tween) { // jQuery 1.8 model
|
1211
|
-
obj = jQ.Tween.propHooks[fn];
|
1212
|
-
fn = 'set';
|
1213
|
-
}
|
1214
|
-
|
1215
|
-
// Overwrite the method
|
1216
|
-
base = obj[fn];
|
1217
|
-
if (base) { // step.width and step.height don't exist in jQuery < 1.7
|
1218
|
-
|
1219
|
-
// create the extended function replacement
|
1220
|
-
obj[fn] = function (fx) {
|
1221
|
-
|
1222
|
-
// jFx.prototype.cur does not use fx argument
|
1223
|
-
fx = i ? fx : this;
|
1224
|
-
|
1225
|
-
// shortcut
|
1226
|
-
elem = fx.elem;
|
1227
|
-
|
1228
|
-
// jFX.prototype.cur returns the current value. The other ones are setters
|
1229
|
-
// and returning a value has no effect.
|
1230
|
-
return elem.attr ? // is SVG element wrapper
|
1231
|
-
elem.attr(fx.prop, fn === 'cur' ? UNDEFINED : fx.now) : // apply the SVG wrapper's method
|
1232
|
-
base.apply(this, arguments); // use jQuery's built-in method
|
1233
|
-
};
|
1234
|
-
}
|
1235
|
-
});
|
1236
|
-
|
1237
|
-
// animate paths
|
1238
|
-
jStep.d = function (fx) {
|
1239
|
-
var elem = fx.elem;
|
1240
1322
|
|
1241
1323
|
|
1242
|
-
// Normally start and end should be set in state == 0, but sometimes,
|
1243
|
-
// for reasons unknown, this doesn't happen. Perhaps state == 0 is skipped
|
1244
|
-
// in these cases
|
1245
|
-
if (!fx.started) {
|
1246
|
-
var ends = pathAnim.init(elem, elem.d, elem.toD);
|
1247
|
-
fx.start = ends[0];
|
1248
|
-
fx.end = ends[1];
|
1249
|
-
fx.started = true;
|
1250
|
-
}
|
1251
|
-
|
1252
|
-
|
1253
|
-
// interpolate each value of the path
|
1254
|
-
elem.attr('d', pathAnim.step(fx.start, fx.end, fx.pos, elem.toD));
|
1255
|
-
|
1256
|
-
};
|
1257
|
-
}
|
1258
|
-
|
1259
1324
|
/* ****************************************************************************
|
1260
1325
|
* Handle the options *
|
1261
1326
|
*****************************************************************************/
|
@@ -1288,13 +1353,15 @@ defaultOptions = {
|
|
1288
1353
|
shortMonths: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
|
1289
1354
|
weekdays: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
|
1290
1355
|
decimalPoint: '.',
|
1356
|
+
numericSymbols: ['k', 'M', 'G', 'T', 'P', 'E'], // SI prefixes used in axis labels
|
1291
1357
|
resetZoom: 'Reset zoom',
|
1292
1358
|
resetZoomTitle: 'Reset zoom level 1:1',
|
1293
1359
|
thousandsSep: ','
|
1294
1360
|
},
|
1295
1361
|
global: {
|
1296
1362
|
useUTC: true,
|
1297
|
-
canvasToolsURL: 'http://code.highcharts.com/2.2
|
1363
|
+
canvasToolsURL: 'http://code.highcharts.com/2.3.2/modules/canvas-tools.js',
|
1364
|
+
VMLRadialGradientURL: 'http://code.highcharts.com/2.3.2/gfx/vml-radial-gradient.png'
|
1298
1365
|
},
|
1299
1366
|
chart: {
|
1300
1367
|
//animation: true,
|
@@ -1393,6 +1460,7 @@ defaultOptions = {
|
|
1393
1460
|
//fillColor: null,
|
1394
1461
|
states: { // states for a single point
|
1395
1462
|
hover: {
|
1463
|
+
enabled: true
|
1396
1464
|
//radius: base + 2
|
1397
1465
|
},
|
1398
1466
|
select: {
|
@@ -1838,7 +1906,7 @@ SVGElement.prototype = {
|
|
1838
1906
|
value = hash[key];
|
1839
1907
|
|
1840
1908
|
// check for a specific attribute setter
|
1841
|
-
result = attrSetters[key] && attrSetters[key](value, key);
|
1909
|
+
result = attrSetters[key] && attrSetters[key].call(wrapper, value, key);
|
1842
1910
|
|
1843
1911
|
if (result !== false) {
|
1844
1912
|
if (result !== UNDEFINED) {
|
@@ -1995,7 +2063,10 @@ SVGElement.prototype = {
|
|
1995
2063
|
|
1996
2064
|
|
1997
2065
|
if (key === 'text') {
|
1998
|
-
//
|
2066
|
+
// Delete bBox memo when the text changes
|
2067
|
+
if (value !== wrapper.textStr) {
|
2068
|
+
delete wrapper.bBox;
|
2069
|
+
}
|
1999
2070
|
wrapper.textStr = value;
|
2000
2071
|
if (wrapper.added) {
|
2001
2072
|
renderer.buildText(wrapper);
|
@@ -2010,25 +2081,6 @@ SVGElement.prototype = {
|
|
2010
2081
|
|
2011
2082
|
}
|
2012
2083
|
|
2013
|
-
// Workaround for our #732, WebKit's issue https://bugs.webkit.org/show_bug.cgi?id=78385
|
2014
|
-
// TODO: If the WebKit team fix this bug before the final release of Chrome 18, remove the workaround.
|
2015
|
-
if (isWebKit && /Chrome\/(18|19)/.test(userAgent)) {
|
2016
|
-
if (nodeName === 'text' && (hash.x !== UNDEFINED || hash.y !== UNDEFINED)) {
|
2017
|
-
var parent = element.parentNode,
|
2018
|
-
next = element.nextSibling;
|
2019
|
-
|
2020
|
-
if (parent) {
|
2021
|
-
parent.removeChild(element);
|
2022
|
-
if (next) {
|
2023
|
-
parent.insertBefore(element, next);
|
2024
|
-
} else {
|
2025
|
-
parent.appendChild(element);
|
2026
|
-
}
|
2027
|
-
}
|
2028
|
-
}
|
2029
|
-
}
|
2030
|
-
// End of workaround for #732
|
2031
|
-
|
2032
2084
|
return ret;
|
2033
2085
|
},
|
2034
2086
|
|
@@ -2055,7 +2107,7 @@ SVGElement.prototype = {
|
|
2055
2107
|
* @param {String} id
|
2056
2108
|
*/
|
2057
2109
|
clip: function (clipRect) {
|
2058
|
-
return this.attr('clip-path', 'url(' + this.renderer.url + '#' + clipRect.id + ')');
|
2110
|
+
return this.attr('clip-path', clipRect ? 'url(' + this.renderer.url + '#' + clipRect.id + ')' : NONE);
|
2059
2111
|
},
|
2060
2112
|
|
2061
2113
|
/**
|
@@ -2121,7 +2173,7 @@ SVGElement.prototype = {
|
|
2121
2173
|
|
2122
2174
|
// store object
|
2123
2175
|
elemWrapper.styles = styles;
|
2124
|
-
|
2176
|
+
|
2125
2177
|
// serialize and set style attribute
|
2126
2178
|
if (isIE && !hasSVG) { // legacy IE doesn't support setting style attribute
|
2127
2179
|
if (textWidth) {
|
@@ -2229,14 +2281,14 @@ SVGElement.prototype = {
|
|
2229
2281
|
* @return {Object} A hash containing values for x, y, width and height
|
2230
2282
|
*/
|
2231
2283
|
|
2232
|
-
htmlGetBBox: function (
|
2284
|
+
htmlGetBBox: function () {
|
2233
2285
|
var wrapper = this,
|
2234
2286
|
element = wrapper.element,
|
2235
2287
|
bBox = wrapper.bBox;
|
2236
2288
|
|
2237
2289
|
// faking getBBox in exported SVG in legacy IE
|
2238
|
-
if (!bBox
|
2239
|
-
// faking getBBox in exported SVG in legacy IE
|
2290
|
+
if (!bBox) {
|
2291
|
+
// faking getBBox in exported SVG in legacy IE (is this a duplicate of the fix for #1079?)
|
2240
2292
|
if (element.nodeName === 'text') {
|
2241
2293
|
element.style.position = ABSOLUTE;
|
2242
2294
|
}
|
@@ -2310,25 +2362,34 @@ SVGElement.prototype = {
|
|
2310
2362
|
textWidth = pInt(wrapper.textWidth),
|
2311
2363
|
xCorr = wrapper.xCorr || 0,
|
2312
2364
|
yCorr = wrapper.yCorr || 0,
|
2313
|
-
currentTextTransform = [rotation, align, elem.innerHTML, wrapper.textWidth].join(',')
|
2365
|
+
currentTextTransform = [rotation, align, elem.innerHTML, wrapper.textWidth].join(','),
|
2366
|
+
rotationStyle = {},
|
2367
|
+
prefix;
|
2314
2368
|
|
2315
2369
|
if (currentTextTransform !== wrapper.cTT) { // do the calculations and DOM access only if properties changed
|
2316
2370
|
|
2317
2371
|
if (defined(rotation)) {
|
2318
|
-
|
2319
|
-
|
2320
|
-
|
2321
|
-
|
2322
|
-
|
2323
|
-
|
2324
|
-
|
2325
|
-
|
2326
|
-
|
2327
|
-
|
2328
|
-
|
2329
|
-
|
2330
|
-
|
2331
|
-
|
2372
|
+
|
2373
|
+
if (renderer.isSVG) { // #916
|
2374
|
+
prefix = isIE ? '-ms' : isWebKit ? '-webkit' : isFirefox ? '-moz' : isOpera ? '-o' : '';
|
2375
|
+
rotationStyle[prefix + '-transform'] = rotationStyle.transform = 'rotate(' + rotation + 'deg)';
|
2376
|
+
|
2377
|
+
} else {
|
2378
|
+
radians = rotation * deg2rad; // deg to rad
|
2379
|
+
costheta = mathCos(radians);
|
2380
|
+
sintheta = mathSin(radians);
|
2381
|
+
|
2382
|
+
// Adjust for alignment and rotation. Rotation of useHTML content is not yet implemented
|
2383
|
+
// but it can probably be implemented for Firefox 3.5+ on user request. FF3.5+
|
2384
|
+
// has support for CSS3 transform. The getBBox method also needs to be updated
|
2385
|
+
// to compensate for the rotation, like it currently does for SVG.
|
2386
|
+
// Test case: http://highcharts.com/tests/?file=text-rotation
|
2387
|
+
rotationStyle.filter = rotation ? ['progid:DXImageTransform.Microsoft.Matrix(M11=', costheta,
|
2388
|
+
', M12=', -sintheta, ', M21=', sintheta, ', M22=', costheta,
|
2389
|
+
', sizingMethod=\'auto expand\')'].join('') : NONE;
|
2390
|
+
}
|
2391
|
+
|
2392
|
+
css(elem, rotationStyle);
|
2332
2393
|
}
|
2333
2394
|
|
2334
2395
|
width = pick(wrapper.elemWidth, elem.offsetWidth);
|
@@ -2484,50 +2545,61 @@ SVGElement.prototype = {
|
|
2484
2545
|
/**
|
2485
2546
|
* Get the bounding box (width, height, x and y) for the element
|
2486
2547
|
*/
|
2487
|
-
getBBox: function (
|
2548
|
+
getBBox: function () {
|
2488
2549
|
var wrapper = this,
|
2489
|
-
bBox,
|
2550
|
+
bBox = wrapper.bBox,
|
2551
|
+
renderer = wrapper.renderer,
|
2490
2552
|
width,
|
2491
2553
|
height,
|
2492
2554
|
rotation = wrapper.rotation,
|
2493
2555
|
element = wrapper.element,
|
2494
2556
|
rad = rotation * deg2rad;
|
2495
2557
|
|
2496
|
-
|
2497
|
-
|
2498
|
-
|
2558
|
+
if (!bBox) {
|
2559
|
+
// SVG elements
|
2560
|
+
if (element.namespaceURI === SVG_NS || renderer.forExport) {
|
2561
|
+
try { // Fails in Firefox if the container has display: none.
|
2562
|
+
|
2563
|
+
bBox = element.getBBox ?
|
2564
|
+
// SVG: use extend because IE9 is not allowed to change width and height in case
|
2565
|
+
// of rotation (below)
|
2566
|
+
extend({}, element.getBBox()) :
|
2567
|
+
// Canvas renderer and legacy IE in export mode
|
2568
|
+
{
|
2569
|
+
width: element.offsetWidth,
|
2570
|
+
height: element.offsetHeight
|
2571
|
+
};
|
2572
|
+
} catch (e) {}
|
2573
|
+
|
2574
|
+
// If the bBox is not set, the try-catch block above failed. The other condition
|
2575
|
+
// is for Opera that returns a width of -Infinity on hidden elements.
|
2576
|
+
if (!bBox || bBox.width < 0) {
|
2577
|
+
bBox = { width: 0, height: 0 };
|
2578
|
+
}
|
2579
|
+
|
2580
|
+
|
2581
|
+
// VML Renderer or useHTML within SVG
|
2582
|
+
} else {
|
2583
|
+
|
2584
|
+
bBox = wrapper.htmlGetBBox();
|
2499
2585
|
|
2500
|
-
bBox = element.getBBox ?
|
2501
|
-
// SVG: use extend because IE9 is not allowed to change width and height in case
|
2502
|
-
// of rotation (below)
|
2503
|
-
extend({}, element.getBBox()) :
|
2504
|
-
// Canvas renderer and legacy IE in export mode
|
2505
|
-
{
|
2506
|
-
width: element.offsetWidth,
|
2507
|
-
height: element.offsetHeight
|
2508
|
-
};
|
2509
|
-
} catch (e) {}
|
2510
|
-
|
2511
|
-
// If the bBox is not set, the try-catch block above failed. The other condition
|
2512
|
-
// is for Opera that returns a width of -Infinity on hidden elements.
|
2513
|
-
if (!bBox || bBox.width < 0) {
|
2514
|
-
bBox = { width: 0, height: 0 };
|
2515
2586
|
}
|
2516
2587
|
|
2517
|
-
|
2518
|
-
|
2519
|
-
|
2520
|
-
|
2521
|
-
|
2522
|
-
|
2523
|
-
|
2588
|
+
// True SVG elements as well as HTML elements in modern browsers using the .useHTML option
|
2589
|
+
// need to compensated for rotation
|
2590
|
+
if (renderer.isSVG) {
|
2591
|
+
width = bBox.width;
|
2592
|
+
height = bBox.height;
|
2593
|
+
|
2594
|
+
// Adjust for rotated text
|
2595
|
+
if (rotation) {
|
2596
|
+
bBox.width = mathAbs(height * mathSin(rad)) + mathAbs(width * mathCos(rad));
|
2597
|
+
bBox.height = mathAbs(height * mathCos(rad)) + mathAbs(width * mathSin(rad));
|
2598
|
+
}
|
2524
2599
|
}
|
2525
|
-
|
2526
|
-
|
2527
|
-
} else {
|
2528
|
-
bBox = wrapper.htmlGetBBox(refresh);
|
2600
|
+
|
2601
|
+
wrapper.bBox = bBox;
|
2529
2602
|
}
|
2530
|
-
|
2531
2603
|
return bBox;
|
2532
2604
|
},
|
2533
2605
|
|
@@ -2544,7 +2616,7 @@ SVGElement.prototype = {
|
|
2544
2616
|
hide: function () {
|
2545
2617
|
return this.attr({ visibility: HIDDEN });
|
2546
2618
|
},
|
2547
|
-
|
2619
|
+
|
2548
2620
|
/**
|
2549
2621
|
* Add the element
|
2550
2622
|
* @param {Object|Undefined} parent Can be an element, an element wrapper or undefined
|
@@ -2562,6 +2634,10 @@ SVGElement.prototype = {
|
|
2562
2634
|
otherZIndex,
|
2563
2635
|
i,
|
2564
2636
|
inserted;
|
2637
|
+
|
2638
|
+
if (parent) {
|
2639
|
+
this.parentGroup = parent;
|
2640
|
+
}
|
2565
2641
|
|
2566
2642
|
// mark as inverted
|
2567
2643
|
this.parentInverted = parent && parent.inverted;
|
@@ -2688,27 +2764,34 @@ SVGElement.prototype = {
|
|
2688
2764
|
|
2689
2765
|
/**
|
2690
2766
|
* Add a shadow to the element. Must be done after the element is added to the DOM
|
2691
|
-
* @param {Boolean}
|
2767
|
+
* @param {Boolean|Object} shadowOptions
|
2692
2768
|
*/
|
2693
|
-
shadow: function (
|
2769
|
+
shadow: function (shadowOptions, group, cutOff) {
|
2694
2770
|
var shadows = [],
|
2695
2771
|
i,
|
2696
2772
|
shadow,
|
2697
2773
|
element = this.element,
|
2698
2774
|
strokeWidth,
|
2775
|
+
shadowWidth,
|
2776
|
+
shadowElementOpacity,
|
2699
2777
|
|
2700
2778
|
// compensate for inverted plot area
|
2701
|
-
transform
|
2779
|
+
transform;
|
2702
2780
|
|
2703
2781
|
|
2704
|
-
if (
|
2705
|
-
|
2782
|
+
if (shadowOptions) {
|
2783
|
+
shadowWidth = pick(shadowOptions.width, 3);
|
2784
|
+
shadowElementOpacity = (shadowOptions.opacity || 0.15) / shadowWidth;
|
2785
|
+
transform = this.parentInverted ?
|
2786
|
+
'(-1,-1)' :
|
2787
|
+
'(' + (shadowOptions.offsetX || 1) + ', ' + (shadowOptions.offsetY || 1) + ')';
|
2788
|
+
for (i = 1; i <= shadowWidth; i++) {
|
2706
2789
|
shadow = element.cloneNode(0);
|
2707
|
-
strokeWidth =
|
2790
|
+
strokeWidth = (shadowWidth * 2) + 1 - (2 * i);
|
2708
2791
|
attr(shadow, {
|
2709
2792
|
'isShadow': 'true',
|
2710
|
-
'stroke':
|
2711
|
-
'stroke-opacity':
|
2793
|
+
'stroke': shadowOptions.color || 'black',
|
2794
|
+
'stroke-opacity': shadowElementOpacity * i,
|
2712
2795
|
'stroke-width': strokeWidth,
|
2713
2796
|
'transform': 'translate' + transform,
|
2714
2797
|
'fill': NONE
|
@@ -2768,8 +2851,15 @@ SVGRenderer.prototype = {
|
|
2768
2851
|
renderer.box = boxWrapper.element;
|
2769
2852
|
renderer.boxWrapper = boxWrapper;
|
2770
2853
|
renderer.alignedObjects = [];
|
2771
|
-
|
2772
|
-
|
2854
|
+
|
2855
|
+
// Page url used for internal references. #24, #672, #1070
|
2856
|
+
renderer.url = (isFirefox || isWebKit) && doc.getElementsByTagName('base').length ?
|
2857
|
+
loc.href
|
2858
|
+
.replace(/#.*?$/, '') // remove the hash
|
2859
|
+
.replace(/([\('\)])/g, '\\$1') // escape parantheses and quotes
|
2860
|
+
.replace(/ /g, '%20') : // replace spaces (needed for Safari only)
|
2861
|
+
'';
|
2862
|
+
|
2773
2863
|
renderer.defs = this.createElement('defs').add();
|
2774
2864
|
renderer.forExport = forExport;
|
2775
2865
|
renderer.gradients = {}; // Object where gradient SvgElements are stored
|
@@ -2884,7 +2974,9 @@ SVGRenderer.prototype = {
|
|
2884
2974
|
|
2885
2975
|
// Needed in IE9 because it doesn't report tspan's offsetHeight (#893)
|
2886
2976
|
function getLineHeightByBBox(lineNo) {
|
2887
|
-
linePositions[lineNo] = textNode.getBBox
|
2977
|
+
linePositions[lineNo] = textNode.getBBox ?
|
2978
|
+
textNode.getBBox().height :
|
2979
|
+
wrapper.renderer.fontMetrics(textNode.style.fontSize).h; // #990
|
2888
2980
|
return mathRound(linePositions[lineNo] - (linePositions[lineNo - 1] || 0));
|
2889
2981
|
}
|
2890
2982
|
|
@@ -2987,6 +3079,7 @@ SVGRenderer.prototype = {
|
|
2987
3079
|
rest = [];
|
2988
3080
|
|
2989
3081
|
while (words.length || rest.length) {
|
3082
|
+
delete wrapper.bBox; // delete cache
|
2990
3083
|
actualWidth = wrapper.getBBox().width;
|
2991
3084
|
tooLong = actualWidth > width;
|
2992
3085
|
if (!tooLong || words.length === 1) { // new line needed
|
@@ -3131,7 +3224,8 @@ SVGRenderer.prototype = {
|
|
3131
3224
|
// points format: [M, 0, 0, L, 100, 0]
|
3132
3225
|
// normalize to a crisp line
|
3133
3226
|
if (points[1] === points[4]) {
|
3134
|
-
|
3227
|
+
// Substract due to #1129. Now bottom and left axis gridlines behave the same.
|
3228
|
+
points[1] = points[4] = mathRound(points[1]) - (width % 2 / 2);
|
3135
3229
|
}
|
3136
3230
|
if (points[2] === points[5]) {
|
3137
3231
|
points[2] = points[5] = mathRound(points[2]) + (width % 2 / 2);
|
@@ -3649,6 +3743,13 @@ SVGRenderer.prototype = {
|
|
3649
3743
|
fontFamily: defaultChartStyle.fontFamily,
|
3650
3744
|
fontSize: defaultChartStyle.fontSize
|
3651
3745
|
});
|
3746
|
+
|
3747
|
+
// Prevent wrapping from creating false offsetWidths in export in legacy IE (#1079, #1063)
|
3748
|
+
if (!hasSVG && renderer.forExport) {
|
3749
|
+
wrapper.css({
|
3750
|
+
position: ABSOLUTE
|
3751
|
+
});
|
3752
|
+
}
|
3652
3753
|
|
3653
3754
|
wrapper.x = x;
|
3654
3755
|
wrapper.y = y;
|
@@ -3673,6 +3774,9 @@ SVGRenderer.prototype = {
|
|
3673
3774
|
|
3674
3775
|
// Text setter
|
3675
3776
|
attrSetters.text = function (value) {
|
3777
|
+
if (value !== element.innerHTML) {
|
3778
|
+
delete this.bBox;
|
3779
|
+
}
|
3676
3780
|
element.innerHTML = value;
|
3677
3781
|
return false;
|
3678
3782
|
};
|
@@ -3708,33 +3812,55 @@ SVGRenderer.prototype = {
|
|
3708
3812
|
wrapper.add = function (svgGroupWrapper) {
|
3709
3813
|
|
3710
3814
|
var htmlGroup,
|
3711
|
-
|
3712
|
-
|
3815
|
+
container = renderer.box.parentNode,
|
3816
|
+
parentGroup,
|
3817
|
+
parents = [];
|
3713
3818
|
|
3714
3819
|
// Create a mock group to hold the HTML elements
|
3715
3820
|
if (svgGroupWrapper) {
|
3716
3821
|
htmlGroup = svgGroupWrapper.div;
|
3717
3822
|
if (!htmlGroup) {
|
3718
|
-
|
3719
|
-
|
3720
|
-
|
3721
|
-
|
3722
|
-
|
3723
|
-
|
3724
|
-
|
3725
|
-
|
3726
|
-
|
3727
|
-
|
3728
|
-
|
3729
|
-
|
3730
|
-
|
3731
|
-
|
3732
|
-
|
3733
|
-
|
3734
|
-
|
3735
|
-
|
3736
|
-
|
3737
|
-
}
|
3823
|
+
|
3824
|
+
// Read the parent chain into an array and read from top down
|
3825
|
+
parentGroup = svgGroupWrapper;
|
3826
|
+
while (parentGroup) {
|
3827
|
+
|
3828
|
+
parents.push(parentGroup);
|
3829
|
+
|
3830
|
+
// Move up to the next parent group
|
3831
|
+
parentGroup = parentGroup.parentGroup;
|
3832
|
+
}
|
3833
|
+
|
3834
|
+
// Ensure dynamically updating position when any parent is translated
|
3835
|
+
each(parents.reverse(), function (parentGroup) {
|
3836
|
+
var htmlGroupStyle;
|
3837
|
+
|
3838
|
+
// Create a HTML div and append it to the parent div to emulate
|
3839
|
+
// the SVG group structure
|
3840
|
+
htmlGroup = parentGroup.div = parentGroup.div || createElement(DIV, {
|
3841
|
+
className: attr(parentGroup.element, 'class')
|
3842
|
+
}, {
|
3843
|
+
position: ABSOLUTE,
|
3844
|
+
left: (parentGroup.translateX || 0) + PX,
|
3845
|
+
top: (parentGroup.translateY || 0) + PX
|
3846
|
+
}, htmlGroup || container); // the top group is appended to container
|
3847
|
+
|
3848
|
+
// Shortcut
|
3849
|
+
htmlGroupStyle = htmlGroup.style;
|
3850
|
+
|
3851
|
+
// Set listeners to update the HTML div's position whenever the SVG group
|
3852
|
+
// position is changed
|
3853
|
+
extend(parentGroup.attrSetters, {
|
3854
|
+
translateX: function (value) {
|
3855
|
+
htmlGroupStyle.left = value + PX;
|
3856
|
+
},
|
3857
|
+
translateY: function (value) {
|
3858
|
+
htmlGroupStyle.top = value + PX;
|
3859
|
+
},
|
3860
|
+
visibility: function (value, key) {
|
3861
|
+
htmlGroupStyle[key] = value;
|
3862
|
+
}
|
3863
|
+
});
|
3738
3864
|
});
|
3739
3865
|
|
3740
3866
|
}
|
@@ -3794,8 +3920,8 @@ SVGRenderer.prototype = {
|
|
3794
3920
|
text = renderer.text('', 0, 0, useHTML)
|
3795
3921
|
.attr({
|
3796
3922
|
zIndex: 1
|
3797
|
-
})
|
3798
|
-
|
3923
|
+
}),
|
3924
|
+
//.add(wrapper),
|
3799
3925
|
box,
|
3800
3926
|
bBox,
|
3801
3927
|
alignFactor = 0,
|
@@ -3819,7 +3945,7 @@ SVGRenderer.prototype = {
|
|
3819
3945
|
style = text.element.style;
|
3820
3946
|
|
3821
3947
|
bBox = (width === undefined || height === undefined || wrapper.styles.textAlign) &&
|
3822
|
-
text.getBBox(
|
3948
|
+
text.getBBox();
|
3823
3949
|
wrapper.width = (width || bBox.width || 0) + 2 * padding;
|
3824
3950
|
wrapper.height = (height || bBox.height || 0) + 2 * padding;
|
3825
3951
|
|
@@ -3889,6 +4015,7 @@ SVGRenderer.prototype = {
|
|
3889
4015
|
}
|
3890
4016
|
|
3891
4017
|
function getSizeAfterAdd() {
|
4018
|
+
text.add(wrapper);
|
3892
4019
|
wrapper.attr({
|
3893
4020
|
text: str, // alignment is available now
|
3894
4021
|
x: x,
|
@@ -4115,11 +4242,6 @@ var VMLElement = {
|
|
4115
4242
|
renderer.invertChild(element, parentNode);
|
4116
4243
|
}
|
4117
4244
|
|
4118
|
-
// issue #140 workaround - related to #61 and #74
|
4119
|
-
if (docMode8 && parentNode.gVis === HIDDEN) {
|
4120
|
-
css(element, { visibility: HIDDEN });
|
4121
|
-
}
|
4122
|
-
|
4123
4245
|
// append it
|
4124
4246
|
parentNode.appendChild(element);
|
4125
4247
|
|
@@ -4135,26 +4257,6 @@ var VMLElement = {
|
|
4135
4257
|
return wrapper;
|
4136
4258
|
},
|
4137
4259
|
|
4138
|
-
/**
|
4139
|
-
* In IE8 documentMode 8, we need to recursively set the visibility down in the DOM
|
4140
|
-
* tree for nested groups. Related to #61, #586.
|
4141
|
-
*/
|
4142
|
-
toggleChildren: function (element, visibility) {
|
4143
|
-
var childNodes = element.childNodes,
|
4144
|
-
i = childNodes.length;
|
4145
|
-
|
4146
|
-
while (i--) {
|
4147
|
-
|
4148
|
-
// apply the visibility
|
4149
|
-
css(childNodes[i], { visibility: visibility });
|
4150
|
-
|
4151
|
-
// we have a nested group, apply it to its children again
|
4152
|
-
if (childNodes[i].nodeName === 'DIV') {
|
4153
|
-
this.toggleChildren(childNodes[i], visibility);
|
4154
|
-
}
|
4155
|
-
}
|
4156
|
-
},
|
4157
|
-
|
4158
4260
|
/**
|
4159
4261
|
* VML always uses htmlUpdateTransform
|
4160
4262
|
*/
|
@@ -4203,7 +4305,7 @@ var VMLElement = {
|
|
4203
4305
|
skipAttr = false;
|
4204
4306
|
|
4205
4307
|
// check for a specific attribute setter
|
4206
|
-
result = attrSetters[key] && attrSetters[key](value, key);
|
4308
|
+
result = attrSetters[key] && attrSetters[key].call(wrapper, value, key);
|
4207
4309
|
|
4208
4310
|
if (result !== false && value !== null) { // #620
|
4209
4311
|
|
@@ -4258,24 +4360,33 @@ var VMLElement = {
|
|
4258
4360
|
}
|
4259
4361
|
skipAttr = true;
|
4260
4362
|
|
4261
|
-
//
|
4262
|
-
} else if (key === '
|
4263
|
-
|
4264
|
-
//
|
4265
|
-
if (
|
4266
|
-
|
4267
|
-
|
4268
|
-
|
4269
|
-
value = null;
|
4363
|
+
// handle visibility
|
4364
|
+
} else if (key === 'visibility') {
|
4365
|
+
|
4366
|
+
// let the shadow follow the main element
|
4367
|
+
if (shadows) {
|
4368
|
+
i = shadows.length;
|
4369
|
+
while (i--) {
|
4370
|
+
shadows[i].style[key] = value;
|
4270
4371
|
}
|
4271
4372
|
}
|
4373
|
+
|
4374
|
+
// Instead of toggling the visibility CSS property, move the div out of the viewport.
|
4375
|
+
// This works around #61 and #586
|
4376
|
+
if (nodeName === 'DIV') {
|
4377
|
+
value = value === HIDDEN ? '-999em' : 0;
|
4378
|
+
key = 'top';
|
4379
|
+
}
|
4380
|
+
|
4381
|
+
elemStyle[key] = value;
|
4382
|
+
skipAttr = true;
|
4383
|
+
|
4384
|
+
// directly mapped to css
|
4385
|
+
} else if (key === 'zIndex') {
|
4272
4386
|
|
4273
4387
|
if (value) {
|
4274
4388
|
elemStyle[key] = value;
|
4275
4389
|
}
|
4276
|
-
|
4277
|
-
|
4278
|
-
|
4279
4390
|
skipAttr = true;
|
4280
4391
|
|
4281
4392
|
// width and height
|
@@ -4298,7 +4409,6 @@ var VMLElement = {
|
|
4298
4409
|
|
4299
4410
|
// x and y
|
4300
4411
|
} else if (key === 'x' || key === 'y') {
|
4301
|
-
|
4302
4412
|
wrapper[key] = value; // used in getter
|
4303
4413
|
elemStyle[{ x: 'left', y: 'top' }[key]] = value;
|
4304
4414
|
|
@@ -4340,7 +4450,7 @@ var VMLElement = {
|
|
4340
4450
|
} else {
|
4341
4451
|
element.filled = value !== NONE ? true : false;
|
4342
4452
|
|
4343
|
-
value = renderer.color(value, element, key);
|
4453
|
+
value = renderer.color(value, element, key, wrapper);
|
4344
4454
|
|
4345
4455
|
key = 'fillcolor';
|
4346
4456
|
}
|
@@ -4348,6 +4458,9 @@ var VMLElement = {
|
|
4348
4458
|
// rotation on VML elements
|
4349
4459
|
} else if (nodeName === 'shape' && key === 'rotation') {
|
4350
4460
|
wrapper[key] = value;
|
4461
|
+
// Correction for the 1x1 size of the shape container. Used in gauge needles.
|
4462
|
+
element.style.left = -mathRound(mathSin(value * deg2rad) + 1) + PX;
|
4463
|
+
element.style.top = mathRound(mathCos(value * deg2rad)) + PX;
|
4351
4464
|
|
4352
4465
|
// translation for animation
|
4353
4466
|
} else if (key === 'translateX' || key === 'translateY' || key === 'rotation') {
|
@@ -4363,16 +4476,6 @@ var VMLElement = {
|
|
4363
4476
|
skipAttr = true;
|
4364
4477
|
}
|
4365
4478
|
|
4366
|
-
// let the shadow follow the main element
|
4367
|
-
if (shadows && key === 'visibility') {
|
4368
|
-
i = shadows.length;
|
4369
|
-
while (i--) {
|
4370
|
-
shadows[i].style[key] = value;
|
4371
|
-
}
|
4372
|
-
}
|
4373
|
-
|
4374
|
-
|
4375
|
-
|
4376
4479
|
if (!skipAttr) {
|
4377
4480
|
if (docMode8) { // IE8 setAttribute bug
|
4378
4481
|
element[key] = value;
|
@@ -4394,21 +4497,32 @@ var VMLElement = {
|
|
4394
4497
|
*/
|
4395
4498
|
clip: function (clipRect) {
|
4396
4499
|
var wrapper = this,
|
4397
|
-
clipMembers
|
4500
|
+
clipMembers,
|
4398
4501
|
element = wrapper.element,
|
4399
|
-
parentNode = element.parentNode
|
4400
|
-
|
4401
|
-
|
4402
|
-
|
4403
|
-
|
4404
|
-
|
4405
|
-
|
4406
|
-
|
4407
|
-
|
4408
|
-
|
4502
|
+
parentNode = element.parentNode,
|
4503
|
+
cssRet;
|
4504
|
+
|
4505
|
+
if (clipRect) {
|
4506
|
+
clipMembers = clipRect.members;
|
4507
|
+
clipMembers.push(wrapper);
|
4508
|
+
wrapper.destroyClip = function () {
|
4509
|
+
erase(clipMembers, wrapper);
|
4510
|
+
};
|
4511
|
+
// Issue #863 workaround - related to #140, #61, #74
|
4512
|
+
if (parentNode && parentNode.className === 'highcharts-tracker' && !docMode8) {
|
4513
|
+
css(element, { visibility: HIDDEN });
|
4514
|
+
}
|
4515
|
+
cssRet = clipRect.getCSS(wrapper);
|
4516
|
+
|
4517
|
+
} else {
|
4518
|
+
if (wrapper.destroyClip) {
|
4519
|
+
wrapper.destroyClip();
|
4520
|
+
}
|
4521
|
+
cssRet = { clip: docMode8 ? 'inherit' : 'rect(auto)' }; // #1214
|
4409
4522
|
}
|
4410
4523
|
|
4411
|
-
return wrapper.css(
|
4524
|
+
return wrapper.css(cssRet);
|
4525
|
+
|
4412
4526
|
},
|
4413
4527
|
|
4414
4528
|
/**
|
@@ -4424,8 +4538,7 @@ var VMLElement = {
|
|
4424
4538
|
safeRemoveChild: function (element) {
|
4425
4539
|
// discardElement will detach the node from its parent before attaching it
|
4426
4540
|
// to the garbage bin. Therefore it is important that the node is attached and have parent.
|
4427
|
-
|
4428
|
-
if (parentNode) {
|
4541
|
+
if (element.parentNode) {
|
4429
4542
|
discardElement(element);
|
4430
4543
|
}
|
4431
4544
|
},
|
@@ -4434,13 +4547,11 @@ var VMLElement = {
|
|
4434
4547
|
* Extend element.destroy by removing it from the clip members array
|
4435
4548
|
*/
|
4436
4549
|
destroy: function () {
|
4437
|
-
|
4438
|
-
|
4439
|
-
if (wrapper.destroyClip) {
|
4440
|
-
wrapper.destroyClip();
|
4550
|
+
if (this.destroyClip) {
|
4551
|
+
this.destroyClip();
|
4441
4552
|
}
|
4442
4553
|
|
4443
|
-
return SVGElement.prototype.destroy.apply(
|
4554
|
+
return SVGElement.prototype.destroy.apply(this);
|
4444
4555
|
},
|
4445
4556
|
|
4446
4557
|
/**
|
@@ -4491,9 +4602,9 @@ var VMLElement = {
|
|
4491
4602
|
|
4492
4603
|
/**
|
4493
4604
|
* Apply a drop shadow by copying elements and giving them different strokes
|
4494
|
-
* @param {Boolean}
|
4605
|
+
* @param {Boolean|Object} shadowOptions
|
4495
4606
|
*/
|
4496
|
-
shadow: function (
|
4607
|
+
shadow: function (shadowOptions, group, cutOff) {
|
4497
4608
|
var shadows = [],
|
4498
4609
|
i,
|
4499
4610
|
element = this.element,
|
@@ -4503,7 +4614,9 @@ var VMLElement = {
|
|
4503
4614
|
markup,
|
4504
4615
|
path = element.path,
|
4505
4616
|
strokeWidth,
|
4506
|
-
modifiedPath
|
4617
|
+
modifiedPath,
|
4618
|
+
shadowWidth,
|
4619
|
+
shadowElementOpacity;
|
4507
4620
|
|
4508
4621
|
// some times empty paths are not strings
|
4509
4622
|
if (path && typeof path.value !== 'string') {
|
@@ -4511,24 +4624,26 @@ var VMLElement = {
|
|
4511
4624
|
}
|
4512
4625
|
modifiedPath = path;
|
4513
4626
|
|
4514
|
-
if (
|
4627
|
+
if (shadowOptions) {
|
4628
|
+
shadowWidth = pick(shadowOptions.width, 3);
|
4629
|
+
shadowElementOpacity = (shadowOptions.opacity || 0.15) / shadowWidth;
|
4515
4630
|
for (i = 1; i <= 3; i++) {
|
4516
4631
|
|
4517
|
-
strokeWidth =
|
4632
|
+
strokeWidth = (shadowWidth * 2) + 1 - (2 * i);
|
4518
4633
|
|
4519
4634
|
// Cut off shadows for stacked column items
|
4520
4635
|
if (cutOff) {
|
4521
4636
|
modifiedPath = this.cutOffPath(path.value, strokeWidth + 0.5);
|
4522
4637
|
}
|
4523
4638
|
|
4524
|
-
markup = ['<shape isShadow="true" strokeweight="',
|
4639
|
+
markup = ['<shape isShadow="true" strokeweight="', strokeWidth,
|
4525
4640
|
'" filled="false" path="', modifiedPath,
|
4526
4641
|
'" coordsize="10 10" style="', element.style.cssText, '" />'];
|
4527
4642
|
|
4528
4643
|
shadow = createElement(renderer.prepVML(markup),
|
4529
4644
|
null, {
|
4530
|
-
left: pInt(elemStyle.left) + 1,
|
4531
|
-
top: pInt(elemStyle.top) + 1
|
4645
|
+
left: pInt(elemStyle.left) + (shadowOptions.offsetX || 1),
|
4646
|
+
top: pInt(elemStyle.top) + (shadowOptions.offsetY || 1)
|
4532
4647
|
}
|
4533
4648
|
);
|
4534
4649
|
if (cutOff) {
|
@@ -4536,7 +4651,7 @@ var VMLElement = {
|
|
4536
4651
|
}
|
4537
4652
|
|
4538
4653
|
// apply the opacity
|
4539
|
-
markup = ['<stroke color="black" opacity="',
|
4654
|
+
markup = ['<stroke color="', shadowOptions.color || 'black', '" opacity="', shadowElementOpacity * i, '"/>'];
|
4540
4655
|
createElement(renderer.prepVML(markup), null, null, shadow);
|
4541
4656
|
|
4542
4657
|
|
@@ -4631,15 +4746,16 @@ var VMLRendererExtension = { // inherit SVGRenderer
|
|
4631
4746
|
clipRect: function (x, y, width, height) {
|
4632
4747
|
|
4633
4748
|
// create a dummy element
|
4634
|
-
var clipRect = this.createElement()
|
4635
|
-
|
4749
|
+
var clipRect = this.createElement(),
|
4750
|
+
isObj = isObject(x);
|
4751
|
+
|
4636
4752
|
// mimic a rectangle with its style object for automatic updating in attr
|
4637
4753
|
return extend(clipRect, {
|
4638
4754
|
members: [],
|
4639
|
-
left: x,
|
4640
|
-
top: y,
|
4641
|
-
width: width,
|
4642
|
-
height: height,
|
4755
|
+
left: isObj ? x.x : x,
|
4756
|
+
top: isObj ? x.y : y,
|
4757
|
+
width: isObj ? x.width : width,
|
4758
|
+
height: isObj ? x.height : height,
|
4643
4759
|
getCSS: function (wrapper) {
|
4644
4760
|
var inverted = wrapper.inverted,
|
4645
4761
|
rect = this,
|
@@ -4683,8 +4799,9 @@ var VMLRendererExtension = { // inherit SVGRenderer
|
|
4683
4799
|
*
|
4684
4800
|
* @param {Object} color The color or config object
|
4685
4801
|
*/
|
4686
|
-
color: function (color, elem, prop) {
|
4687
|
-
var
|
4802
|
+
color: function (color, elem, prop, wrapper) {
|
4803
|
+
var renderer = this,
|
4804
|
+
colorObject,
|
4688
4805
|
regexRgba = /^rgba/,
|
4689
4806
|
markup,
|
4690
4807
|
fillType,
|
@@ -4707,7 +4824,6 @@ var VMLRendererExtension = { // inherit SVGRenderer
|
|
4707
4824
|
y1,
|
4708
4825
|
x2,
|
4709
4826
|
y2,
|
4710
|
-
angle,
|
4711
4827
|
opacity1,
|
4712
4828
|
opacity2,
|
4713
4829
|
color1,
|
@@ -4716,7 +4832,14 @@ var VMLRendererExtension = { // inherit SVGRenderer
|
|
4716
4832
|
stops = color.stops,
|
4717
4833
|
firstStop,
|
4718
4834
|
lastStop,
|
4719
|
-
colors = []
|
4835
|
+
colors = [],
|
4836
|
+
addFillNode = function () {
|
4837
|
+
// Add the fill subnode. When colors attribute is used, the meanings of opacity and o:opacity2
|
4838
|
+
// are reversed.
|
4839
|
+
markup = ['<fill colors="' + colors.join(',') + '" opacity="', opacity2, '" o:opacity2="', opacity1,
|
4840
|
+
'" type="', fillType, '" ', fillAttr, 'focus="100%" method="any" />'];
|
4841
|
+
createElement(renderer.prepVML(markup), null, null, elem);
|
4842
|
+
};
|
4720
4843
|
|
4721
4844
|
// Extend from 0 to 1
|
4722
4845
|
firstStop = stops[0];
|
@@ -4758,65 +4881,67 @@ var VMLRendererExtension = { // inherit SVGRenderer
|
|
4758
4881
|
}
|
4759
4882
|
});
|
4760
4883
|
|
4761
|
-
// Handle linear gradient angle
|
4762
|
-
if (fillType === 'gradient') {
|
4763
|
-
x1 = gradient.x1 || gradient[0] || 0;
|
4764
|
-
y1 = gradient.y1 || gradient[1] || 0;
|
4765
|
-
x2 = gradient.x2 || gradient[2] || 0;
|
4766
|
-
y2 = gradient.y2 || gradient[3] || 0;
|
4767
|
-
angle = 90 - math.atan(
|
4768
|
-
(y2 - y1) / // y vector
|
4769
|
-
(x2 - x1) // x vector
|
4770
|
-
) * 180 / mathPI;
|
4771
|
-
|
4772
|
-
// Radial (circular) gradient
|
4773
|
-
} else {
|
4774
|
-
// pie: http://jsfiddle.net/highcharts/66g8H/
|
4775
|
-
// reference: http://jsfiddle.net/highcharts/etznJ/
|
4776
|
-
// http://jsfiddle.net/highcharts/XRbCc/
|
4777
|
-
// http://jsfiddle.net/highcharts/F3fwR/
|
4778
|
-
// TODO:
|
4779
|
-
// - correct for radialRefeence
|
4780
|
-
// - check whether gradient stops are supported
|
4781
|
-
// - add global option for gradient image (must relate to version)
|
4782
|
-
var r = gradient.r,
|
4783
|
-
size = r * 2,
|
4784
|
-
cx = gradient.cx,
|
4785
|
-
cy = gradient.cy;
|
4786
|
-
//radialReference = elem.radialReference;
|
4787
|
-
|
4788
|
-
//if (radialReference) {
|
4789
|
-
// Try setting pixel size, or other way to adjust the gradient size to the bounding box
|
4790
|
-
//}
|
4791
|
-
fillAttr = 'src="http://code.highcharts.com/gfx/radial-gradient.png" ' +
|
4792
|
-
'size="' + size + ',' + size + '" ' +
|
4793
|
-
'origin="0.5,0.5" ' +
|
4794
|
-
'position="' + cx + ',' + cy + '" ' +
|
4795
|
-
'color2="' + color2 + '" ';
|
4796
|
-
|
4797
|
-
// The fill element's color attribute is broken in IE8 standards mode, so we
|
4798
|
-
// need to set the parent shape's fillcolor attribute instead.
|
4799
|
-
ret = color1;
|
4800
|
-
}
|
4801
|
-
|
4802
|
-
|
4803
|
-
|
4804
4884
|
// Apply the gradient to fills only.
|
4805
4885
|
if (prop === 'fill') {
|
4806
4886
|
|
4807
|
-
//
|
4808
|
-
|
4809
|
-
|
4810
|
-
|
4811
|
-
|
4812
|
-
|
4887
|
+
// Handle linear gradient angle
|
4888
|
+
if (fillType === 'gradient') {
|
4889
|
+
x1 = gradient.x1 || gradient[0] || 0;
|
4890
|
+
y1 = gradient.y1 || gradient[1] || 0;
|
4891
|
+
x2 = gradient.x2 || gradient[2] || 0;
|
4892
|
+
y2 = gradient.y2 || gradient[3] || 0;
|
4893
|
+
fillAttr = 'angle="' + (90 - math.atan(
|
4894
|
+
(y2 - y1) / // y vector
|
4895
|
+
(x2 - x1) // x vector
|
4896
|
+
) * 180 / mathPI) + '"';
|
4897
|
+
|
4898
|
+
addFillNode();
|
4899
|
+
|
4900
|
+
// Radial (circular) gradient
|
4901
|
+
} else {
|
4902
|
+
|
4903
|
+
var r = gradient.r,
|
4904
|
+
sizex = r * 2,
|
4905
|
+
sizey = r * 2,
|
4906
|
+
cx = gradient.cx,
|
4907
|
+
cy = gradient.cy,
|
4908
|
+
radialReference = elem.radialReference,
|
4909
|
+
bBox,
|
4910
|
+
applyRadialGradient = function () {
|
4911
|
+
if (radialReference) {
|
4912
|
+
bBox = wrapper.getBBox();
|
4913
|
+
cx += (radialReference[0] - bBox.x) / bBox.width - 0.5;
|
4914
|
+
cy += (radialReference[1] - bBox.y) / bBox.height - 0.5;
|
4915
|
+
sizex *= radialReference[2] / bBox.width;
|
4916
|
+
sizey *= radialReference[2] / bBox.height;
|
4917
|
+
}
|
4918
|
+
fillAttr = 'src="' + defaultOptions.global.VMLRadialGradientURL + '" ' +
|
4919
|
+
'size="' + sizex + ',' + sizey + '" ' +
|
4920
|
+
'origin="0.5,0.5" ' +
|
4921
|
+
'position="' + cx + ',' + cy + '" ' +
|
4922
|
+
'color2="' + color2 + '" ';
|
4923
|
+
|
4924
|
+
addFillNode();
|
4925
|
+
};
|
4926
|
+
|
4927
|
+
// Apply radial gradient
|
4928
|
+
if (wrapper.added) {
|
4929
|
+
applyRadialGradient();
|
4930
|
+
} else {
|
4931
|
+
// We need to know the bounding box to get the size and position right
|
4932
|
+
addEvent(wrapper, 'add', applyRadialGradient);
|
4933
|
+
}
|
4934
|
+
|
4935
|
+
// The fill element's color attribute is broken in IE8 standards mode, so we
|
4936
|
+
// need to set the parent shape's fillcolor attribute instead.
|
4937
|
+
ret = color1;
|
4938
|
+
}
|
4813
4939
|
|
4814
4940
|
// Gradients are not supported for VML stroke, return the first color. #722.
|
4815
4941
|
} else {
|
4816
4942
|
ret = stopColor;
|
4817
4943
|
}
|
4818
4944
|
|
4819
|
-
|
4820
4945
|
// if the color is an rgba color, split it and add a fill node
|
4821
4946
|
// to hold the opacity component
|
4822
4947
|
} else if (regexRgba.test(color) && elem.tagName !== 'IMG') {
|
@@ -5021,11 +5146,12 @@ var VMLRendererExtension = { // inherit SVGRenderer
|
|
5021
5146
|
y + radius * sinEnd // end y
|
5022
5147
|
];
|
5023
5148
|
|
5024
|
-
if (options.open) {
|
5149
|
+
if (options.open && !innerRadius) {
|
5025
5150
|
ret.push(
|
5151
|
+
'e',
|
5026
5152
|
M,
|
5027
|
-
x - innerRadius,
|
5028
|
-
y - innerRadius
|
5153
|
+
x,// - innerRadius,
|
5154
|
+
y// - innerRadius
|
5029
5155
|
);
|
5030
5156
|
}
|
5031
5157
|
|
@@ -5303,7 +5429,7 @@ Tick.prototype = {
|
|
5303
5429
|
.attr(attr)
|
5304
5430
|
// without position absolute, IE export sometimes is wrong
|
5305
5431
|
.css(css)
|
5306
|
-
.add(axis.
|
5432
|
+
.add(axis.labelGroup) :
|
5307
5433
|
null;
|
5308
5434
|
|
5309
5435
|
// update
|
@@ -5322,7 +5448,7 @@ Tick.prototype = {
|
|
5322
5448
|
var label = this.label,
|
5323
5449
|
axis = this.axis;
|
5324
5450
|
return label ?
|
5325
|
-
((this.labelBBox = label.getBBox(
|
5451
|
+
((this.labelBBox = label.getBBox()))[axis.horiz ? 'height' : 'width'] :
|
5326
5452
|
0;
|
5327
5453
|
},
|
5328
5454
|
|
@@ -5363,7 +5489,7 @@ Tick.prototype = {
|
|
5363
5489
|
plotLeft = chart.plotLeft,
|
5364
5490
|
plotRight = plotLeft + axis.len,
|
5365
5491
|
neighbour = axis.ticks[tickPositions[index + (isFirst ? 1 : -1)]],
|
5366
|
-
neighbourEdge = neighbour && neighbour.label.xy.x + neighbour.getLabelSides()[isFirst ? 0 : 1];
|
5492
|
+
neighbourEdge = neighbour && neighbour.label.xy && neighbour.label.xy.x + neighbour.getLabelSides()[isFirst ? 0 : 1];
|
5367
5493
|
|
5368
5494
|
if ((isFirst && !reversed) || (isLast && reversed)) {
|
5369
5495
|
// Is the label spilling out to the left of the plot area?
|
@@ -5496,7 +5622,7 @@ Tick.prototype = {
|
|
5496
5622
|
step = labelOptions.step,
|
5497
5623
|
attribs,
|
5498
5624
|
show = true,
|
5499
|
-
tickmarkOffset =
|
5625
|
+
tickmarkOffset = axis.tickmarkOffset,
|
5500
5626
|
xy = tick.getPosition(horiz, pos, tickmarkOffset, old),
|
5501
5627
|
x = xy.x,
|
5502
5628
|
y = xy.y,
|
@@ -5534,7 +5660,7 @@ Tick.prototype = {
|
|
5534
5660
|
}
|
5535
5661
|
|
5536
5662
|
// create the tick mark
|
5537
|
-
if (tickWidth) {
|
5663
|
+
if (tickWidth && tickLength) {
|
5538
5664
|
|
5539
5665
|
// negate the length
|
5540
5666
|
if (tickPosition === 'inside') {
|
@@ -6139,6 +6265,8 @@ Axis.prototype = {
|
|
6139
6265
|
// Tick intervals
|
6140
6266
|
//axis.tickInterval = UNDEFINED;
|
6141
6267
|
//axis.minorTickInterval = UNDEFINED;
|
6268
|
+
|
6269
|
+
axis.tickmarkOffset = (options.categories && options.tickmarkPlacement === 'between') ? 0.5 : 0;
|
6142
6270
|
|
6143
6271
|
// Major ticks
|
6144
6272
|
axis.ticks = {};
|
@@ -6231,7 +6359,10 @@ Axis.prototype = {
|
|
6231
6359
|
this.isXAxis ? {} : this.defaultYAxisOptions,
|
6232
6360
|
[this.defaultTopAxisOptions, this.defaultRightAxisOptions,
|
6233
6361
|
this.defaultBottomAxisOptions, this.defaultLeftAxisOptions][this.side],
|
6234
|
-
|
6362
|
+
merge(
|
6363
|
+
defaultOptions[this.isXAxis ? 'xAxis' : 'yAxis'], // if set in setOptions (#1053)
|
6364
|
+
userOptions
|
6365
|
+
)
|
6235
6366
|
);
|
6236
6367
|
},
|
6237
6368
|
|
@@ -6242,29 +6373,43 @@ Axis.prototype = {
|
|
6242
6373
|
defaultLabelFormatter: function () {
|
6243
6374
|
var axis = this.axis,
|
6244
6375
|
value = this.value,
|
6245
|
-
categories = axis.categories,
|
6246
|
-
tickInterval = axis.tickInterval,
|
6376
|
+
categories = axis.categories,
|
6247
6377
|
dateTimeLabelFormat = this.dateTimeLabelFormat,
|
6248
|
-
|
6378
|
+
numericSymbols = defaultOptions.lang.numericSymbols,
|
6379
|
+
i = numericSymbols && numericSymbols.length,
|
6380
|
+
multi,
|
6381
|
+
ret,
|
6382
|
+
|
6383
|
+
// make sure the same symbol is added for all labels on a linear axis
|
6384
|
+
numericSymbolDetector = axis.isLog ? value : axis.tickInterval;
|
6249
6385
|
|
6250
6386
|
if (categories) {
|
6251
6387
|
ret = value;
|
6252
6388
|
|
6253
6389
|
} else if (dateTimeLabelFormat) { // datetime axis
|
6254
6390
|
ret = dateFormat(dateTimeLabelFormat, value);
|
6391
|
+
|
6392
|
+
} else if (i && numericSymbolDetector >= 1000) {
|
6393
|
+
// Decide whether we should add a numeric symbol like k (thousands) or M (millions).
|
6394
|
+
// If we are to enable this in tooltip or other places as well, we can move this
|
6395
|
+
// logic to the numberFormatter and enable it by a parameter.
|
6396
|
+
while (i-- && ret === UNDEFINED) {
|
6397
|
+
multi = Math.pow(1000, i + 1);
|
6398
|
+
if (numericSymbolDetector >= multi && numericSymbols[i] !== null) {
|
6399
|
+
ret = numberFormat(value / multi, -1) + numericSymbols[i];
|
6400
|
+
}
|
6401
|
+
}
|
6402
|
+
}
|
6403
|
+
|
6404
|
+
if (ret === UNDEFINED) {
|
6405
|
+
if (value >= 1000) { // add thousands separators
|
6406
|
+
ret = numberFormat(value, 0);
|
6255
6407
|
|
6256
|
-
|
6257
|
-
|
6258
|
-
|
6259
|
-
} else if (tickInterval % 1000 === 0) { // use k abbreviation
|
6260
|
-
ret = (value / 1000) + 'k';
|
6261
|
-
|
6262
|
-
} else if (value >= 1000) { // add thousands separators
|
6263
|
-
ret = numberFormat(value, 0);
|
6264
|
-
|
6265
|
-
} else { // small numbers
|
6266
|
-
ret = numberFormat(value, -1);
|
6408
|
+
} else { // small numbers
|
6409
|
+
ret = numberFormat(value, -1);
|
6410
|
+
}
|
6267
6411
|
}
|
6412
|
+
|
6268
6413
|
return ret;
|
6269
6414
|
},
|
6270
6415
|
|
@@ -6278,6 +6423,8 @@ Axis.prototype = {
|
|
6278
6423
|
posStack = [],
|
6279
6424
|
negStack = [],
|
6280
6425
|
i;
|
6426
|
+
|
6427
|
+
axis.hasVisibleSeries = false;
|
6281
6428
|
|
6282
6429
|
// reset dataMin and dataMax in case we're redrawing
|
6283
6430
|
axis.dataMin = axis.dataMax = null;
|
@@ -6303,6 +6450,8 @@ Axis.prototype = {
|
|
6303
6450
|
activeYData = [],
|
6304
6451
|
activeCounter = 0;
|
6305
6452
|
|
6453
|
+
axis.hasVisibleSeries = true;
|
6454
|
+
|
6306
6455
|
// Validate threshold in logarithmic axes
|
6307
6456
|
if (axis.isLog && threshold <= 0) {
|
6308
6457
|
threshold = seriesOptions.threshold = null;
|
@@ -6444,13 +6593,14 @@ Axis.prototype = {
|
|
6444
6593
|
}
|
6445
6594
|
}
|
6446
6595
|
});
|
6596
|
+
|
6447
6597
|
},
|
6448
6598
|
|
6449
6599
|
/**
|
6450
6600
|
* Translate from axis value to pixel position on the chart, or back
|
6451
6601
|
*
|
6452
6602
|
*/
|
6453
|
-
translate: function (val, backwards, cvsCoord, old, handleLog) {
|
6603
|
+
translate: function (val, backwards, cvsCoord, old, handleLog, pointPlacementBetween) {
|
6454
6604
|
var axis = this,
|
6455
6605
|
axisLength = axis.len,
|
6456
6606
|
sign = 1,
|
@@ -6487,7 +6637,8 @@ Axis.prototype = {
|
|
6487
6637
|
val = axis.val2lin(val);
|
6488
6638
|
}
|
6489
6639
|
|
6490
|
-
returnValue = sign * (val - localMin) * localA + cvsOffset + (sign * axis.minPixelPadding)
|
6640
|
+
returnValue = sign * (val - localMin) * localA + cvsOffset + (sign * axis.minPixelPadding) +
|
6641
|
+
(pointPlacementBetween ? localA * axis.pointRange / 2 : 0);
|
6491
6642
|
}
|
6492
6643
|
|
6493
6644
|
return returnValue;
|
@@ -6809,17 +6960,38 @@ Axis.prototype = {
|
|
6809
6960
|
range = axis.max - axis.min,
|
6810
6961
|
pointRange = 0,
|
6811
6962
|
closestPointRange,
|
6812
|
-
|
6963
|
+
minPointOffset = 0,
|
6964
|
+
pointRangePadding = 0,
|
6813
6965
|
transA = axis.transA;
|
6814
6966
|
|
6815
6967
|
// adjust translation for padding
|
6816
6968
|
if (axis.isXAxis) {
|
6817
6969
|
if (axis.isLinked) {
|
6818
|
-
|
6970
|
+
minPointOffset = axis.linkedParent.minPointOffset;
|
6819
6971
|
} else {
|
6820
6972
|
each(axis.series, function (series) {
|
6821
|
-
|
6822
|
-
|
6973
|
+
var seriesPointRange = series.pointRange,
|
6974
|
+
pointPlacement = series.options.pointPlacement,
|
6975
|
+
seriesClosestPointRange = series.closestPointRange;
|
6976
|
+
|
6977
|
+
pointRange = mathMax(pointRange, seriesPointRange);
|
6978
|
+
|
6979
|
+
// minPointOffset is the value padding to the left of the axis in order to make
|
6980
|
+
// room for points with a pointRange, typically columns. When the pointPlacement option
|
6981
|
+
// is 'between' or 'on', this padding does not apply.
|
6982
|
+
minPointOffset = mathMax(
|
6983
|
+
minPointOffset,
|
6984
|
+
pointPlacement ? 0 : seriesPointRange / 2
|
6985
|
+
);
|
6986
|
+
|
6987
|
+
// Determine the total padding needed to the length of the axis to make room for the
|
6988
|
+
// pointRange. If the series' pointPlacement is 'on', no padding is added.
|
6989
|
+
pointRangePadding = mathMax(
|
6990
|
+
pointRangePadding,
|
6991
|
+
pointPlacement === 'on' ? 0 : seriesPointRange
|
6992
|
+
);
|
6993
|
+
|
6994
|
+
// Set the closestPointRange
|
6823
6995
|
if (!series.noSharedTooltip && defined(seriesClosestPointRange)) {
|
6824
6996
|
closestPointRange = defined(closestPointRange) ?
|
6825
6997
|
mathMin(closestPointRange, seriesClosestPointRange) :
|
@@ -6827,6 +6999,9 @@ Axis.prototype = {
|
|
6827
6999
|
}
|
6828
7000
|
});
|
6829
7001
|
}
|
7002
|
+
|
7003
|
+
// Record minPointOffse
|
7004
|
+
axis.minPointOffset = minPointOffset;
|
6830
7005
|
|
6831
7006
|
// pointRange means the width reserved for each point, like in a column chart
|
6832
7007
|
axis.pointRange = pointRange;
|
@@ -6839,9 +7014,10 @@ Axis.prototype = {
|
|
6839
7014
|
|
6840
7015
|
// secondary values
|
6841
7016
|
axis.oldTransA = transA;
|
6842
|
-
axis.translationSlope = axis.transA = transA = axis.len / ((range +
|
7017
|
+
//axis.translationSlope = axis.transA = transA = axis.len / ((range + (2 * minPointOffset)) || 1);
|
7018
|
+
axis.translationSlope = axis.transA = transA = axis.len / ((range + pointRangePadding) || 1);
|
6843
7019
|
axis.transB = axis.horiz ? axis.left : axis.bottom; // translation addend
|
6844
|
-
axis.minPixelPadding = transA *
|
7020
|
+
axis.minPixelPadding = transA * minPointOffset;
|
6845
7021
|
},
|
6846
7022
|
|
6847
7023
|
/**
|
@@ -6863,6 +7039,7 @@ Axis.prototype = {
|
|
6863
7039
|
length,
|
6864
7040
|
linkedParentExtremes,
|
6865
7041
|
tickIntervalOption = options.tickInterval,
|
7042
|
+
minTickIntervalOption = options.minTickInterval,
|
6866
7043
|
tickPixelIntervalOption = options.tickPixelInterval,
|
6867
7044
|
tickPositions,
|
6868
7045
|
categories = axis.categories;
|
@@ -6936,9 +7113,9 @@ Axis.prototype = {
|
|
6936
7113
|
}
|
6937
7114
|
|
6938
7115
|
// set the translation factor used in translate function
|
6939
|
-
axis.setAxisTranslation();
|
7116
|
+
axis.setAxisTranslation(secondPass);
|
6940
7117
|
|
6941
|
-
// hook for ordinal axes
|
7118
|
+
// hook for ordinal axes and radial axes
|
6942
7119
|
if (axis.beforeSetTickPositions) {
|
6943
7120
|
axis.beforeSetTickPositions();
|
6944
7121
|
}
|
@@ -6947,11 +7124,16 @@ Axis.prototype = {
|
|
6947
7124
|
if (axis.postProcessTickInterval) {
|
6948
7125
|
axis.tickInterval = axis.postProcessTickInterval(axis.tickInterval);
|
6949
7126
|
}
|
7127
|
+
|
7128
|
+
// Before normalizing the tick interval, handle minimum tick interval. This applies only if tickInterval is not defined.
|
7129
|
+
if (!tickIntervalOption && axis.tickInterval < minTickIntervalOption) {
|
7130
|
+
axis.tickInterval = minTickIntervalOption;
|
7131
|
+
}
|
6950
7132
|
|
6951
7133
|
// for linear axes, get magnitude and normalize the interval
|
6952
7134
|
if (!isDatetimeAxis && !isLog) { // linear
|
6953
7135
|
magnitude = math.pow(10, mathFloor(math.log(axis.tickInterval) / math.LN10));
|
6954
|
-
if (!
|
7136
|
+
if (!tickIntervalOption) {
|
6955
7137
|
axis.tickInterval = normalizeTickInterval(axis.tickInterval, null, magnitude, options);
|
6956
7138
|
}
|
6957
7139
|
}
|
@@ -6985,17 +7167,18 @@ Axis.prototype = {
|
|
6985
7167
|
|
6986
7168
|
// reset min/max or remove extremes based on start/end on tick
|
6987
7169
|
var roundedMin = tickPositions[0],
|
6988
|
-
roundedMax = tickPositions[tickPositions.length - 1]
|
7170
|
+
roundedMax = tickPositions[tickPositions.length - 1],
|
7171
|
+
minPointOffset = axis.minPointOffset || 0;
|
6989
7172
|
|
6990
7173
|
if (options.startOnTick) {
|
6991
7174
|
axis.min = roundedMin;
|
6992
|
-
} else if (axis.min > roundedMin) {
|
7175
|
+
} else if (axis.min - minPointOffset > roundedMin) {
|
6993
7176
|
tickPositions.shift();
|
6994
7177
|
}
|
6995
7178
|
|
6996
7179
|
if (options.endOnTick) {
|
6997
7180
|
axis.max = roundedMax;
|
6998
|
-
} else if (axis.max < roundedMax) {
|
7181
|
+
} else if (axis.max + minPointOffset < roundedMax) {
|
6999
7182
|
tickPositions.pop();
|
7000
7183
|
}
|
7001
7184
|
|
@@ -7161,6 +7344,15 @@ Axis.prototype = {
|
|
7161
7344
|
});
|
7162
7345
|
},
|
7163
7346
|
|
7347
|
+
/**
|
7348
|
+
* Overridable method for zooming chart. Pulled out in a separate method to allow overriding
|
7349
|
+
* in stock charts.
|
7350
|
+
*/
|
7351
|
+
zoom: function (newMin, newMax) {
|
7352
|
+
this.setExtremes(newMin, newMax, false, UNDEFINED, { trigger: 'zoom' });
|
7353
|
+
return true;
|
7354
|
+
},
|
7355
|
+
|
7164
7356
|
/**
|
7165
7357
|
* Update the axis metrics
|
7166
7358
|
*/
|
@@ -7257,17 +7449,21 @@ Axis.prototype = {
|
|
7257
7449
|
|
7258
7450
|
|
7259
7451
|
// For reuse in Axis.render
|
7260
|
-
axis.hasData = hasData = axis.
|
7452
|
+
axis.hasData = hasData = (axis.hasVisibleSeries || (defined(axis.min) && defined(axis.max) && !!tickPositions));
|
7261
7453
|
axis.showAxis = showAxis = hasData || pick(options.showEmpty, true);
|
7262
|
-
|
7454
|
+
|
7455
|
+
|
7263
7456
|
// Create the axisGroup and gridGroup elements on first iteration
|
7264
7457
|
if (!axis.axisGroup) {
|
7265
|
-
axis.axisGroup = renderer.g('axis')
|
7266
|
-
.attr({ zIndex: options.zIndex || 7 })
|
7267
|
-
.add();
|
7268
7458
|
axis.gridGroup = renderer.g('grid')
|
7269
7459
|
.attr({ zIndex: options.gridZIndex || 1 })
|
7270
7460
|
.add();
|
7461
|
+
axis.axisGroup = renderer.g('axis')
|
7462
|
+
.attr({ zIndex: options.zIndex || 2 })
|
7463
|
+
.add();
|
7464
|
+
axis.labelGroup = renderer.g('axis-labels')
|
7465
|
+
.attr({ zIndex: labelOptions.zIndex || 7 })
|
7466
|
+
.add();
|
7271
7467
|
}
|
7272
7468
|
|
7273
7469
|
if (hasData || axis.isLinked) {
|
@@ -7361,6 +7557,8 @@ Axis.prototype = {
|
|
7361
7557
|
horiz = this.horiz,
|
7362
7558
|
lineLeft = this.left + (opposite ? this.width : 0) + offset,
|
7363
7559
|
lineTop = chart.chartHeight - this.bottom - (opposite ? this.height : 0) + offset;
|
7560
|
+
|
7561
|
+
this.lineTop = lineTop; // used by flag series
|
7364
7562
|
|
7365
7563
|
return chart.renderer.crispLine([
|
7366
7564
|
M,
|
@@ -7438,6 +7636,7 @@ Axis.prototype = {
|
|
7438
7636
|
alternateBands = axis.alternateBands,
|
7439
7637
|
stackLabelOptions = options.stackLabels,
|
7440
7638
|
alternateGridColor = options.alternateGridColor,
|
7639
|
+
tickmarkOffset = axis.tickmarkOffset,
|
7441
7640
|
lineWidth = options.lineWidth,
|
7442
7641
|
linePath,
|
7443
7642
|
hasRendered = chart.hasRendered,
|
@@ -7500,8 +7699,8 @@ Axis.prototype = {
|
|
7500
7699
|
if (!alternateBands[pos]) {
|
7501
7700
|
alternateBands[pos] = new PlotLineOrBand(axis);
|
7502
7701
|
}
|
7503
|
-
from = pos;
|
7504
|
-
to = tickPositions[i + 1] !== UNDEFINED ? tickPositions[i + 1] : axis.max;
|
7702
|
+
from = pos + tickmarkOffset; // #949
|
7703
|
+
to = tickPositions[i + 1] !== UNDEFINED ? tickPositions[i + 1] + tickmarkOffset : axis.max;
|
7505
7704
|
alternateBands[pos].options = {
|
7506
7705
|
from: isLog ? lin2log(from) : from,
|
7507
7706
|
to: isLog ? lin2log(to) : to,
|
@@ -7549,14 +7748,13 @@ Axis.prototype = {
|
|
7549
7748
|
'stroke-width': lineWidth,
|
7550
7749
|
zIndex: 7
|
7551
7750
|
})
|
7552
|
-
.add();
|
7751
|
+
.add(axis.axisGroup);
|
7553
7752
|
} else {
|
7554
7753
|
axis.axisLine.animate({ d: linePath });
|
7555
7754
|
}
|
7556
7755
|
|
7557
7756
|
// show or hide the line depending on options.showEmpty
|
7558
7757
|
axis.axisLine[showAxis ? 'show' : 'hide']();
|
7559
|
-
|
7560
7758
|
}
|
7561
7759
|
|
7562
7760
|
if (axisTitle && showAxis) {
|
@@ -7618,15 +7816,14 @@ Axis.prototype = {
|
|
7618
7816
|
* Update the axis title by options
|
7619
7817
|
*/
|
7620
7818
|
setTitle: function (newTitleOptions, redraw) {
|
7621
|
-
var
|
7622
|
-
|
7623
|
-
|
7624
|
-
axisTitle;
|
7819
|
+
var chart = this.chart,
|
7820
|
+
options = this.options,
|
7821
|
+
axisTitle = this.axisTitle;
|
7625
7822
|
|
7626
7823
|
options.title = merge(options.title, newTitleOptions);
|
7627
7824
|
|
7628
|
-
|
7629
|
-
|
7825
|
+
this.axisTitle = axisTitle && axisTitle.destroy(); // #922
|
7826
|
+
this.isDirty = true;
|
7630
7827
|
|
7631
7828
|
if (pick(redraw, true)) {
|
7632
7829
|
chart.redraw();
|
@@ -7711,7 +7908,7 @@ Axis.prototype = {
|
|
7711
7908
|
});
|
7712
7909
|
|
7713
7910
|
// Destroy local variables
|
7714
|
-
each(['stackTotalGroup', 'axisLine', 'axisGroup', 'gridGroup', 'axisTitle'], function (prop) {
|
7911
|
+
each(['stackTotalGroup', 'axisLine', 'axisGroup', 'gridGroup', 'labelGroup', 'axisTitle'], function (prop) {
|
7715
7912
|
if (axis[prop]) {
|
7716
7913
|
axis[prop] = axis[prop].destroy();
|
7717
7914
|
}
|
@@ -7729,16 +7926,12 @@ Axis.prototype = {
|
|
7729
7926
|
function Tooltip(chart, options) {
|
7730
7927
|
var borderWidth = options.borderWidth,
|
7731
7928
|
style = options.style,
|
7732
|
-
shared = options.shared,
|
7733
7929
|
padding = pInt(style.padding);
|
7734
7930
|
|
7735
7931
|
// Save the chart and options
|
7736
7932
|
this.chart = chart;
|
7737
7933
|
this.options = options;
|
7738
7934
|
|
7739
|
-
// remove padding CSS and apply padding on box instead
|
7740
|
-
style.padding = 0;
|
7741
|
-
|
7742
7935
|
// Keep track of the current series
|
7743
7936
|
//this.currentSeries = UNDEFINED;
|
7744
7937
|
|
@@ -7746,17 +7939,16 @@ function Tooltip(chart, options) {
|
|
7746
7939
|
this.crosshairs = [];
|
7747
7940
|
|
7748
7941
|
// Current values of x and y when animating
|
7749
|
-
this.
|
7750
|
-
this.currentY = 0;
|
7942
|
+
this.now = { x: 0, y: 0 };
|
7751
7943
|
|
7752
7944
|
// The tooltipTick function, initialized to nothing
|
7753
7945
|
//this.tooltipTick = UNDEFINED;
|
7754
7946
|
|
7755
7947
|
// The tooltip is initially hidden
|
7756
|
-
this.
|
7948
|
+
this.isHidden = true;
|
7757
7949
|
|
7758
7950
|
// create the label
|
7759
|
-
this.label = chart.renderer.label('', 0, 0,
|
7951
|
+
this.label = chart.renderer.label('', 0, 0, options.shape, null, null, options.useHTML, null, 'tooltip')
|
7760
7952
|
.attr({
|
7761
7953
|
padding: padding,
|
7762
7954
|
fill: options.backgroundColor,
|
@@ -7765,6 +7957,7 @@ function Tooltip(chart, options) {
|
|
7765
7957
|
zIndex: 8
|
7766
7958
|
})
|
7767
7959
|
.css(style)
|
7960
|
+
.css({ padding: 0 }) // Remove it from VML, the padding is applied as an attribute instead (#1117)
|
7768
7961
|
.hide()
|
7769
7962
|
.add();
|
7770
7963
|
|
@@ -7775,7 +7968,7 @@ function Tooltip(chart, options) {
|
|
7775
7968
|
}
|
7776
7969
|
|
7777
7970
|
// Public property for getting the shared state.
|
7778
|
-
this.shared = shared;
|
7971
|
+
this.shared = options.shared;
|
7779
7972
|
}
|
7780
7973
|
|
7781
7974
|
Tooltip.prototype = {
|
@@ -7798,24 +7991,30 @@ Tooltip.prototype = {
|
|
7798
7991
|
/**
|
7799
7992
|
* Provide a soft movement for the tooltip
|
7800
7993
|
*
|
7801
|
-
* @param {Number}
|
7802
|
-
* @param {Number}
|
7994
|
+
* @param {Number} x
|
7995
|
+
* @param {Number} y
|
7803
7996
|
* @private
|
7804
7997
|
*/
|
7805
|
-
move: function (
|
7806
|
-
var tooltip = this
|
7998
|
+
move: function (x, y, anchorX, anchorY) {
|
7999
|
+
var tooltip = this,
|
8000
|
+
now = tooltip.now,
|
8001
|
+
animate = tooltip.options.animation !== false && !tooltip.isHidden;
|
7807
8002
|
|
7808
8003
|
// get intermediate values for animation
|
7809
|
-
|
7810
|
-
|
8004
|
+
extend(now, {
|
8005
|
+
x: animate ? (2 * now.x + x) / 3 : x,
|
8006
|
+
y: animate ? (now.y + y) / 2 : y,
|
8007
|
+
anchorX: animate ? (2 * now.anchorX + anchorX) / 3 : anchorX,
|
8008
|
+
anchorY: animate ? (now.anchorY + anchorY) / 2 : anchorY
|
8009
|
+
});
|
7811
8010
|
|
7812
8011
|
// move to the intermediate value
|
7813
|
-
tooltip.label.attr(
|
8012
|
+
tooltip.label.attr(now);
|
7814
8013
|
|
7815
8014
|
// run on next tick of the mouse tracker
|
7816
|
-
if (mathAbs(
|
8015
|
+
if (animate && (mathAbs(x - now.x) > 1 || mathAbs(y - now.y) > 1)) {
|
7817
8016
|
tooltip.tooltipTick = function () {
|
7818
|
-
tooltip.move(
|
8017
|
+
tooltip.move(x, y, anchorX, anchorY);
|
7819
8018
|
};
|
7820
8019
|
} else {
|
7821
8020
|
tooltip.tooltipTick = null;
|
@@ -7826,7 +8025,7 @@ Tooltip.prototype = {
|
|
7826
8025
|
* Hide the tooltip
|
7827
8026
|
*/
|
7828
8027
|
hide: function () {
|
7829
|
-
if (!this.
|
8028
|
+
if (!this.isHidden) {
|
7830
8029
|
var hoverPoints = this.chart.hoverPoints;
|
7831
8030
|
|
7832
8031
|
this.label.hide();
|
@@ -7839,7 +8038,7 @@ Tooltip.prototype = {
|
|
7839
8038
|
}
|
7840
8039
|
|
7841
8040
|
this.chart.hoverPoints = null;
|
7842
|
-
this.
|
8041
|
+
this.isHidden = true;
|
7843
8042
|
}
|
7844
8043
|
},
|
7845
8044
|
|
@@ -7863,7 +8062,8 @@ Tooltip.prototype = {
|
|
7863
8062
|
chart = this.chart,
|
7864
8063
|
inverted = chart.inverted,
|
7865
8064
|
plotX = 0,
|
7866
|
-
plotY = 0
|
8065
|
+
plotY = 0,
|
8066
|
+
yAxis;
|
7867
8067
|
|
7868
8068
|
points = splat(points);
|
7869
8069
|
|
@@ -7873,8 +8073,10 @@ Tooltip.prototype = {
|
|
7873
8073
|
// When shared, use the average position
|
7874
8074
|
if (!ret) {
|
7875
8075
|
each(points, function (point) {
|
8076
|
+
yAxis = point.series.yAxis;
|
7876
8077
|
plotX += point.plotX;
|
7877
|
-
plotY += point.plotLow ? (point.plotLow + point.plotHigh) / 2 : point.plotY
|
8078
|
+
plotY += (point.plotLow ? (point.plotLow + point.plotHigh) / 2 : point.plotY) +
|
8079
|
+
(!inverted && yAxis ? yAxis.top - chart.plotTop : 0); // #1151
|
7878
8080
|
});
|
7879
8081
|
|
7880
8082
|
plotX /= points.length;
|
@@ -8002,12 +8204,13 @@ Tooltip.prototype = {
|
|
8002
8204
|
if (shared && !(point.series && point.series.noSharedTooltip)) {
|
8003
8205
|
|
8004
8206
|
// hide previous hoverPoints and set new
|
8207
|
+
|
8208
|
+
chart.hoverPoints = point;
|
8005
8209
|
if (hoverPoints) {
|
8006
8210
|
each(hoverPoints, function (point) {
|
8007
8211
|
point.setState();
|
8008
8212
|
});
|
8009
8213
|
}
|
8010
|
-
chart.hoverPoints = point;
|
8011
8214
|
|
8012
8215
|
each(point, function (item) {
|
8013
8216
|
item.setState(HOVER_STATE);
|
@@ -8041,7 +8244,7 @@ Tooltip.prototype = {
|
|
8041
8244
|
} else {
|
8042
8245
|
|
8043
8246
|
// show it
|
8044
|
-
if (tooltip.
|
8247
|
+
if (tooltip.isHidden) {
|
8045
8248
|
label.show();
|
8046
8249
|
}
|
8047
8250
|
|
@@ -8064,10 +8267,15 @@ Tooltip.prototype = {
|
|
8064
8267
|
);
|
8065
8268
|
|
8066
8269
|
// do the move
|
8067
|
-
tooltip.move(
|
8270
|
+
tooltip.move(
|
8271
|
+
mathRound(placedTooltipPoint.x),
|
8272
|
+
mathRound(placedTooltipPoint.y),
|
8273
|
+
x + chart.plotLeft,
|
8274
|
+
y + chart.plotTop
|
8275
|
+
);
|
8068
8276
|
|
8069
8277
|
|
8070
|
-
tooltip.
|
8278
|
+
tooltip.isHidden = false;
|
8071
8279
|
}
|
8072
8280
|
|
8073
8281
|
// crosshairs
|
@@ -8176,16 +8384,9 @@ MouseTracker.prototype = {
|
|
8176
8384
|
e.target = e.srcElement;
|
8177
8385
|
}
|
8178
8386
|
|
8179
|
-
//
|
8180
|
-
|
8181
|
-
|
8182
|
-
}
|
8183
|
-
|
8184
|
-
// The same for MooTools. It renames e.pageX to e.page.x. #445.
|
8185
|
-
if (e.event) {
|
8186
|
-
e = e.event;
|
8187
|
-
}
|
8188
|
-
|
8387
|
+
// Framework specific normalizing (#1165)
|
8388
|
+
e = washMouseEvent(e);
|
8389
|
+
|
8189
8390
|
// iOS
|
8190
8391
|
ePos = e.touches ? e.touches.item(0) : e;
|
8191
8392
|
|
@@ -8204,7 +8405,6 @@ MouseTracker.prototype = {
|
|
8204
8405
|
return extend(e, {
|
8205
8406
|
chartX: mathRound(chartX),
|
8206
8407
|
chartY: mathRound(chartY)
|
8207
|
-
|
8208
8408
|
});
|
8209
8409
|
},
|
8210
8410
|
|
@@ -8227,15 +8427,26 @@ MouseTracker.prototype = {
|
|
8227
8427
|
coordinates[isXAxis ? 'xAxis' : 'yAxis'].push({
|
8228
8428
|
axis: axis,
|
8229
8429
|
value: axis.translate(
|
8230
|
-
isHorizontal ?
|
8430
|
+
(isHorizontal ?
|
8231
8431
|
e.chartX - chart.plotLeft :
|
8232
|
-
|
8432
|
+
axis.top + axis.len - e.chartY) - axis.minPixelPadding, // #1051
|
8233
8433
|
true
|
8234
8434
|
)
|
8235
8435
|
});
|
8236
8436
|
});
|
8237
8437
|
return coordinates;
|
8238
8438
|
},
|
8439
|
+
|
8440
|
+
/**
|
8441
|
+
* Return the index in the tooltipPoints array, corresponding to pixel position in
|
8442
|
+
* the plot area.
|
8443
|
+
*/
|
8444
|
+
getIndex: function (e) {
|
8445
|
+
var chart = this.chart;
|
8446
|
+
return chart.inverted ?
|
8447
|
+
chart.plotHeight + chart.plotTop - e.chartY :
|
8448
|
+
e.chartX - chart.plotLeft;
|
8449
|
+
},
|
8239
8450
|
|
8240
8451
|
/**
|
8241
8452
|
* With line type charts with a single tracker, get the point closest to the mouse
|
@@ -8244,6 +8455,7 @@ MouseTracker.prototype = {
|
|
8244
8455
|
var mouseTracker = this,
|
8245
8456
|
chart = mouseTracker.chart,
|
8246
8457
|
series = chart.series,
|
8458
|
+
tooltip = chart.tooltip,
|
8247
8459
|
point,
|
8248
8460
|
points,
|
8249
8461
|
hoverPoint = chart.hoverPoint,
|
@@ -8251,11 +8463,10 @@ MouseTracker.prototype = {
|
|
8251
8463
|
i,
|
8252
8464
|
j,
|
8253
8465
|
distance = chart.chartWidth,
|
8254
|
-
|
8255
|
-
index = chart.inverted ? chart.plotHeight + chart.plotTop - e.chartY : e.chartX - chart.plotLeft;
|
8466
|
+
index = mouseTracker.getIndex(e);
|
8256
8467
|
|
8257
8468
|
// shared tooltip
|
8258
|
-
if (
|
8469
|
+
if (tooltip && mouseTracker.options.tooltip.shared && !(hoverSeries && hoverSeries.noSharedTooltip)) {
|
8259
8470
|
points = [];
|
8260
8471
|
|
8261
8472
|
// loop over all series and find the ones with points closest to the mouse
|
@@ -8265,7 +8476,7 @@ MouseTracker.prototype = {
|
|
8265
8476
|
series[j].options.enableMouseTracking !== false &&
|
8266
8477
|
!series[j].noSharedTooltip && series[j].tooltipPoints.length) {
|
8267
8478
|
point = series[j].tooltipPoints[index];
|
8268
|
-
point._dist = mathAbs(index - point.plotX);
|
8479
|
+
point._dist = mathAbs(index - point[series[j].xAxis.tooltipPosName || 'plotX']);
|
8269
8480
|
distance = mathMin(distance, point._dist);
|
8270
8481
|
points.push(point);
|
8271
8482
|
}
|
@@ -8279,7 +8490,7 @@ MouseTracker.prototype = {
|
|
8279
8490
|
}
|
8280
8491
|
// refresh the tooltip if necessary
|
8281
8492
|
if (points.length && (points[0].plotX !== mouseTracker.hoverX)) {
|
8282
|
-
|
8493
|
+
tooltip.refresh(points, e);
|
8283
8494
|
mouseTracker.hoverX = points[0].plotX;
|
8284
8495
|
}
|
8285
8496
|
}
|
@@ -8304,14 +8515,16 @@ MouseTracker.prototype = {
|
|
8304
8515
|
|
8305
8516
|
/**
|
8306
8517
|
* Reset the tracking by hiding the tooltip, the hover series state and the hover point
|
8518
|
+
*
|
8519
|
+
* @param allowMove {Boolean} Instead of destroying the tooltip altogether, allow moving it if possible
|
8307
8520
|
*/
|
8308
8521
|
resetTracker: function (allowMove) {
|
8309
8522
|
var mouseTracker = this,
|
8310
8523
|
chart = mouseTracker.chart,
|
8311
8524
|
hoverSeries = chart.hoverSeries,
|
8312
8525
|
hoverPoint = chart.hoverPoint,
|
8313
|
-
|
8314
|
-
|
8526
|
+
tooltip = chart.tooltip,
|
8527
|
+
tooltipPoints = tooltip && tooltip.shared ? chart.hoverPoints : hoverPoint;
|
8315
8528
|
|
8316
8529
|
// Narrow in allowMove
|
8317
8530
|
allowMove = allowMove && tooltip && tooltipPoints;
|
@@ -8390,9 +8603,10 @@ MouseTracker.prototype = {
|
|
8390
8603
|
1
|
8391
8604
|
),
|
8392
8605
|
selectionMax = axis.translate(
|
8393
|
-
isHorizontal ?
|
8394
|
-
|
8395
|
-
|
8606
|
+
(isHorizontal ?
|
8607
|
+
selectionLeft + selectionBox.width :
|
8608
|
+
chart.plotHeight - selectionTop) -
|
8609
|
+
2 * axis.minPixelPadding, // #875
|
8396
8610
|
true,
|
8397
8611
|
0,
|
8398
8612
|
0,
|
@@ -8432,7 +8646,7 @@ MouseTracker.prototype = {
|
|
8432
8646
|
mouseTracker.hideTooltipOnMouseMove = function (e) {
|
8433
8647
|
|
8434
8648
|
// Get e.pageX and e.pageY back in MooTools
|
8435
|
-
washMouseEvent(e);
|
8649
|
+
e = washMouseEvent(e);
|
8436
8650
|
|
8437
8651
|
// If we're outside, hide the tooltip
|
8438
8652
|
if (mouseTracker.chartPosition && chart.hoverSeries && chart.hoverSeries.isCartesian &&
|
@@ -8574,8 +8788,10 @@ MouseTracker.prototype = {
|
|
8574
8788
|
}
|
8575
8789
|
}
|
8576
8790
|
|
8577
|
-
}
|
8578
|
-
|
8791
|
+
}
|
8792
|
+
|
8793
|
+
// Show the tooltip and run mouse over events (#977)
|
8794
|
+
if (!isOutsidePlot) {
|
8579
8795
|
mouseTracker.onmousemove(e);
|
8580
8796
|
}
|
8581
8797
|
|
@@ -8706,7 +8922,12 @@ MouseTracker.prototype = {
|
|
8706
8922
|
chart.tooltip = new Tooltip(chart, options);
|
8707
8923
|
|
8708
8924
|
// set the fixed interval ticking for the smooth tooltip
|
8709
|
-
this.tooltipInterval = setInterval(function () {
|
8925
|
+
this.tooltipInterval = setInterval(function () {
|
8926
|
+
// The interval function may still be running during destroy, so check that the chart is really there before calling.
|
8927
|
+
if (chart && chart.tooltip) {
|
8928
|
+
chart.tooltip.tick();
|
8929
|
+
}
|
8930
|
+
}, 32);
|
8710
8931
|
}
|
8711
8932
|
|
8712
8933
|
this.setDOMEvents();
|
@@ -9101,7 +9322,7 @@ Legend.prototype = {
|
|
9101
9322
|
|
9102
9323
|
// sort by legendIndex
|
9103
9324
|
stableSort(allItems, function (a, b) {
|
9104
|
-
return (a.options.legendIndex || 0) - (b.options.legendIndex || 0);
|
9325
|
+
return ((a.options && a.options.legendIndex) || 0) - ((b.options && b.options.legendIndex) || 0);
|
9105
9326
|
});
|
9106
9327
|
|
9107
9328
|
// reversed legend
|
@@ -9202,7 +9423,7 @@ Legend.prototype = {
|
|
9202
9423
|
optionsY = options.y,
|
9203
9424
|
alignTop = options.verticalAlign === 'top',
|
9204
9425
|
spaceHeight = chart.spacingBox.height + (alignTop ? -optionsY : optionsY) - this.padding,
|
9205
|
-
maxHeight = options.maxHeight,
|
9426
|
+
maxHeight = options.maxHeight,
|
9206
9427
|
clipHeight,
|
9207
9428
|
clipRect = this.clipRect,
|
9208
9429
|
navOptions = options.navigation,
|
@@ -9433,10 +9654,8 @@ Chart.prototype = {
|
|
9433
9654
|
redraw = pick(redraw, true); // defaults to true
|
9434
9655
|
|
9435
9656
|
fireEvent(chart, 'addSeries', { options: options }, function () {
|
9436
|
-
chart.initSeries(options);
|
9437
|
-
|
9438
|
-
//series.isDirty = true;
|
9439
|
-
|
9657
|
+
series = chart.initSeries(options);
|
9658
|
+
|
9440
9659
|
chart.isDirtyLegend = true; // the series array is out of sync with the display
|
9441
9660
|
if (redraw) {
|
9442
9661
|
chart.redraw();
|
@@ -9450,10 +9669,14 @@ Chart.prototype = {
|
|
9450
9669
|
/**
|
9451
9670
|
* Check whether a given point is within the plot area
|
9452
9671
|
*
|
9453
|
-
* @param {Number}
|
9454
|
-
* @param {Number}
|
9672
|
+
* @param {Number} plotX Pixel x relative to the plot area
|
9673
|
+
* @param {Number} plotY Pixel y relative to the plot area
|
9674
|
+
* @param {Boolean} inverted Whether the chart is inverted
|
9455
9675
|
*/
|
9456
|
-
isInsidePlot: function (
|
9676
|
+
isInsidePlot: function (plotX, plotY, inverted) {
|
9677
|
+
var x = inverted ? plotY : plotX,
|
9678
|
+
y = inverted ? plotX : plotY;
|
9679
|
+
|
9457
9680
|
return x >= 0 &&
|
9458
9681
|
x <= this.plotWidth &&
|
9459
9682
|
y >= 0 &&
|
@@ -9489,7 +9712,6 @@ Chart.prototype = {
|
|
9489
9712
|
isDirtyBox = chart.isDirtyBox, // todo: check if it has actually changed?
|
9490
9713
|
seriesLength = series.length,
|
9491
9714
|
i = seriesLength,
|
9492
|
-
clipRect = chart.clipRect,
|
9493
9715
|
serie,
|
9494
9716
|
renderer = chart.renderer,
|
9495
9717
|
isHiddenChart = renderer.isHidden();
|
@@ -9571,16 +9793,6 @@ Chart.prototype = {
|
|
9571
9793
|
// the plot areas size has changed
|
9572
9794
|
if (isDirtyBox) {
|
9573
9795
|
chart.drawChartBox();
|
9574
|
-
|
9575
|
-
// move clip rect
|
9576
|
-
if (clipRect) {
|
9577
|
-
stop(clipRect);
|
9578
|
-
clipRect.animate({ // for chart resize
|
9579
|
-
width: chart.plotSizeX,
|
9580
|
-
height: chart.plotSizeY + 1
|
9581
|
-
});
|
9582
|
-
}
|
9583
|
-
|
9584
9796
|
}
|
9585
9797
|
|
9586
9798
|
|
@@ -9784,19 +9996,17 @@ Chart.prototype = {
|
|
9784
9996
|
btnOptions = chart.options.chart.resetZoomButton,
|
9785
9997
|
theme = btnOptions.theme,
|
9786
9998
|
states = theme.states,
|
9787
|
-
|
9788
|
-
|
9789
|
-
y: chart.plotTop,
|
9790
|
-
width: chart.plotWidth,
|
9791
|
-
height: chart.plotHeight
|
9792
|
-
};
|
9999
|
+
alignTo = btnOptions.relativeTo === 'chart' ? null : 'plotBox';
|
10000
|
+
|
9793
10001
|
this.resetZoomButton = chart.renderer.button(lang.resetZoom, null, null, function () { chart.zoomOut(); }, theme, states && states.hover)
|
9794
10002
|
.attr({
|
9795
10003
|
align: btnOptions.position.align,
|
9796
10004
|
title: lang.resetZoomTitle
|
9797
10005
|
})
|
9798
10006
|
.add()
|
9799
|
-
.align(btnOptions.position, false,
|
10007
|
+
.align(btnOptions.position, false, chart[alignTo]);
|
10008
|
+
this.resetZoomButton.alignTo = alignTo;
|
10009
|
+
|
9800
10010
|
},
|
9801
10011
|
|
9802
10012
|
/**
|
@@ -9818,22 +10028,12 @@ Chart.prototype = {
|
|
9818
10028
|
*/
|
9819
10029
|
zoom: function (event) {
|
9820
10030
|
var chart = this,
|
9821
|
-
|
9822
|
-
|
9823
|
-
// add button to reset selection
|
9824
|
-
var hasZoomed;
|
9825
|
-
|
9826
|
-
if (chart.resetZoomEnabled !== false && !chart.resetZoomButton) { // hook for Stock charts etc.
|
9827
|
-
chart.showResetZoom();
|
9828
|
-
}
|
10031
|
+
hasZoomed;
|
9829
10032
|
|
9830
10033
|
// if zoom is called with no arguments, reset the axes
|
9831
10034
|
if (!event || event.resetSelection) {
|
9832
10035
|
each(chart.axes, function (axis) {
|
9833
|
-
|
9834
|
-
axis.setExtremes(null, null, false);
|
9835
|
-
hasZoomed = true;
|
9836
|
-
}
|
10036
|
+
hasZoomed = axis.zoom();
|
9837
10037
|
});
|
9838
10038
|
} else { // else, zoom in on all axes
|
9839
10039
|
each(event.xAxis.concat(event.yAxis), function (axisData) {
|
@@ -9841,16 +10041,21 @@ Chart.prototype = {
|
|
9841
10041
|
|
9842
10042
|
// don't zoom more than minRange
|
9843
10043
|
if (chart.tracker[axis.isXAxis ? 'zoomX' : 'zoomY']) {
|
9844
|
-
axis.
|
9845
|
-
hasZoomed = true;
|
10044
|
+
hasZoomed = axis.zoom(axisData.min, axisData.max);
|
9846
10045
|
}
|
9847
10046
|
});
|
9848
10047
|
}
|
10048
|
+
|
10049
|
+
// Show the Reset zoom button
|
10050
|
+
if (!chart.resetZoomButton) {
|
10051
|
+
chart.showResetZoom();
|
10052
|
+
}
|
10053
|
+
|
9849
10054
|
|
9850
10055
|
// Redraw
|
9851
10056
|
if (hasZoomed) {
|
9852
10057
|
chart.redraw(
|
9853
|
-
pick(
|
10058
|
+
pick(chart.options.chart.animation, chart.pointCount < 100) // animation
|
9854
10059
|
);
|
9855
10060
|
}
|
9856
10061
|
},
|
@@ -9879,7 +10084,7 @@ Chart.prototype = {
|
|
9879
10084
|
}
|
9880
10085
|
|
9881
10086
|
if (xAxis.series.length && newMin > mathMin(extremes.dataMin, extremes.min) && newMax < mathMax(extremes.dataMax, extremes.max)) {
|
9882
|
-
xAxis.setExtremes(newMin, newMax, true, false);
|
10087
|
+
xAxis.setExtremes(newMin, newMax, true, false, { trigger: 'pan' });
|
9883
10088
|
}
|
9884
10089
|
|
9885
10090
|
chart.mouseDownX = chartX; // set new reference for next run
|
@@ -9913,8 +10118,9 @@ Chart.prototype = {
|
|
9913
10118
|
chartTitleOptions = arr[2];
|
9914
10119
|
|
9915
10120
|
if (title && titleOptions) {
|
9916
|
-
title = title.destroy(); // remove old
|
10121
|
+
chart[name] = title = title.destroy(); // remove old
|
9917
10122
|
}
|
10123
|
+
|
9918
10124
|
if (chartTitleOptions && chartTitleOptions.text && !title) {
|
9919
10125
|
chart[name] = chart.renderer.text(
|
9920
10126
|
chartTitleOptions.text,
|
@@ -10040,7 +10246,8 @@ Chart.prototype = {
|
|
10040
10246
|
width: chartWidth + PX,
|
10041
10247
|
height: chartHeight + PX,
|
10042
10248
|
textAlign: 'left',
|
10043
|
-
lineHeight: 'normal' // #427
|
10249
|
+
lineHeight: 'normal', // #427
|
10250
|
+
zIndex: 0 // #1072
|
10044
10251
|
}, optionsChart.style),
|
10045
10252
|
chart.renderToClone || renderTo
|
10046
10253
|
);
|
@@ -10200,19 +10407,6 @@ Chart.prototype = {
|
|
10200
10407
|
});
|
10201
10408
|
},
|
10202
10409
|
|
10203
|
-
/**
|
10204
|
-
* Fires endResize event on chart instance.
|
10205
|
-
*/
|
10206
|
-
fireEndResize: function () {
|
10207
|
-
var chart = this;
|
10208
|
-
|
10209
|
-
if (chart) {
|
10210
|
-
fireEvent(chart, 'endResize', null, function () {
|
10211
|
-
chart.isResizing -= 1;
|
10212
|
-
});
|
10213
|
-
}
|
10214
|
-
},
|
10215
|
-
|
10216
10410
|
/**
|
10217
10411
|
* Resize the chart to a given width and height
|
10218
10412
|
* @param {Number} width
|
@@ -10225,10 +10419,20 @@ Chart.prototype = {
|
|
10225
10419
|
chartWidth,
|
10226
10420
|
chartHeight,
|
10227
10421
|
spacingBox,
|
10422
|
+
resetZoomButton = chart.resetZoomButton,
|
10228
10423
|
chartTitle = chart.title,
|
10229
|
-
chartSubtitle = chart.subtitle
|
10424
|
+
chartSubtitle = chart.subtitle,
|
10425
|
+
fireEndResize;
|
10230
10426
|
|
10427
|
+
// Handle the isResizing counter
|
10231
10428
|
chart.isResizing += 1;
|
10429
|
+
fireEndResize = function () {
|
10430
|
+
if (chart) {
|
10431
|
+
fireEvent(chart, 'endResize', null, function () {
|
10432
|
+
chart.isResizing -= 1;
|
10433
|
+
});
|
10434
|
+
}
|
10435
|
+
};
|
10232
10436
|
|
10233
10437
|
// set the animation for the current process
|
10234
10438
|
setAnimation(animation, chart);
|
@@ -10277,6 +10481,11 @@ Chart.prototype = {
|
|
10277
10481
|
if (chartSubtitle) {
|
10278
10482
|
chartSubtitle.align(null, null, spacingBox);
|
10279
10483
|
}
|
10484
|
+
|
10485
|
+
// Move resize button (#1115)
|
10486
|
+
if (resetZoomButton) {
|
10487
|
+
resetZoomButton.align(null, null, chart[resetZoomButton.alignTo]);
|
10488
|
+
}
|
10280
10489
|
|
10281
10490
|
chart.redraw(animation);
|
10282
10491
|
|
@@ -10287,9 +10496,9 @@ Chart.prototype = {
|
|
10287
10496
|
// fire endResize and set isResizing back
|
10288
10497
|
// If animation is disabled, fire without delay
|
10289
10498
|
if (globalAnimation === false) {
|
10290
|
-
|
10499
|
+
fireEndResize();
|
10291
10500
|
} else { // else set a timeout with the animation duration
|
10292
|
-
setTimeout(
|
10501
|
+
setTimeout(fireEndResize, (globalAnimation && globalAnimation.duration) || 500);
|
10293
10502
|
}
|
10294
10503
|
},
|
10295
10504
|
|
@@ -10306,22 +10515,42 @@ Chart.prototype = {
|
|
10306
10515
|
spacingTop = optionsChart.spacingTop,
|
10307
10516
|
spacingRight = optionsChart.spacingRight,
|
10308
10517
|
spacingBottom = optionsChart.spacingBottom,
|
10309
|
-
spacingLeft = optionsChart.spacingLeft
|
10518
|
+
spacingLeft = optionsChart.spacingLeft,
|
10519
|
+
plotLeft,
|
10520
|
+
plotTop,
|
10521
|
+
plotWidth,
|
10522
|
+
plotHeight,
|
10523
|
+
plotBorderWidth;
|
10310
10524
|
|
10311
|
-
chart.plotLeft = mathRound(chart.plotLeft);
|
10312
|
-
chart.plotTop = mathRound(chart.plotTop);
|
10313
|
-
chart.plotWidth = mathRound(chartWidth -
|
10314
|
-
chart.plotHeight = mathRound(chartHeight -
|
10525
|
+
chart.plotLeft = plotLeft = mathRound(chart.plotLeft);
|
10526
|
+
chart.plotTop = plotTop = mathRound(chart.plotTop);
|
10527
|
+
chart.plotWidth = plotWidth = mathRound(chartWidth - plotLeft - chart.marginRight);
|
10528
|
+
chart.plotHeight = plotHeight = mathRound(chartHeight - plotTop - chart.marginBottom);
|
10315
10529
|
|
10316
|
-
chart.plotSizeX = inverted ?
|
10317
|
-
chart.plotSizeY = inverted ?
|
10530
|
+
chart.plotSizeX = inverted ? plotHeight : plotWidth;
|
10531
|
+
chart.plotSizeY = inverted ? plotWidth : plotHeight;
|
10532
|
+
|
10533
|
+
chart.plotBorderWidth = plotBorderWidth = optionsChart.plotBorderWidth || 0;
|
10318
10534
|
|
10535
|
+
// Set boxes used for alignment
|
10319
10536
|
chart.spacingBox = {
|
10320
10537
|
x: spacingLeft,
|
10321
10538
|
y: spacingTop,
|
10322
10539
|
width: chartWidth - spacingLeft - spacingRight,
|
10323
10540
|
height: chartHeight - spacingTop - spacingBottom
|
10324
10541
|
};
|
10542
|
+
chart.plotBox = {
|
10543
|
+
x: plotLeft,
|
10544
|
+
y: plotTop,
|
10545
|
+
width: plotWidth,
|
10546
|
+
height: plotHeight
|
10547
|
+
};
|
10548
|
+
chart.clipBox = {
|
10549
|
+
x: plotBorderWidth / 2,
|
10550
|
+
y: plotBorderWidth / 2,
|
10551
|
+
width: chart.plotSizeX - plotBorderWidth,
|
10552
|
+
height: chart.plotSizeY - plotBorderWidth
|
10553
|
+
};
|
10325
10554
|
|
10326
10555
|
each(chart.axes, function (axis) {
|
10327
10556
|
axis.setAxisSize();
|
@@ -10364,14 +10593,16 @@ Chart.prototype = {
|
|
10364
10593
|
chartBackgroundColor = optionsChart.backgroundColor,
|
10365
10594
|
plotBackgroundColor = optionsChart.plotBackgroundColor,
|
10366
10595
|
plotBackgroundImage = optionsChart.plotBackgroundImage,
|
10596
|
+
plotBorderWidth = optionsChart.plotBorderWidth || 0,
|
10367
10597
|
mgn,
|
10368
10598
|
bgAttr,
|
10369
|
-
|
10370
|
-
|
10371
|
-
|
10372
|
-
|
10373
|
-
|
10374
|
-
|
10599
|
+
plotLeft = chart.plotLeft,
|
10600
|
+
plotTop = chart.plotTop,
|
10601
|
+
plotWidth = chart.plotWidth,
|
10602
|
+
plotHeight = chart.plotHeight,
|
10603
|
+
plotBox = chart.plotBox,
|
10604
|
+
clipRect = chart.clipRect,
|
10605
|
+
clipBox = chart.clipBox;
|
10375
10606
|
|
10376
10607
|
// Chart area
|
10377
10608
|
mgn = chartBorderWidth + (optionsChart.shadow ? 8 : 0);
|
@@ -10391,6 +10622,7 @@ Chart.prototype = {
|
|
10391
10622
|
.attr(bgAttr)
|
10392
10623
|
.add()
|
10393
10624
|
.shadow(optionsChart.shadow);
|
10625
|
+
|
10394
10626
|
} else { // resize
|
10395
10627
|
chartBackground.animate(
|
10396
10628
|
chartBackground.crisp(null, null, null, chartWidth - mgn, chartHeight - mgn)
|
@@ -10402,38 +10634,48 @@ Chart.prototype = {
|
|
10402
10634
|
// Plot background
|
10403
10635
|
if (plotBackgroundColor) {
|
10404
10636
|
if (!plotBackground) {
|
10405
|
-
chart.plotBackground = renderer.rect(
|
10637
|
+
chart.plotBackground = renderer.rect(plotLeft, plotTop, plotWidth, plotHeight, 0)
|
10406
10638
|
.attr({
|
10407
10639
|
fill: plotBackgroundColor
|
10408
10640
|
})
|
10409
10641
|
.add()
|
10410
10642
|
.shadow(optionsChart.plotShadow);
|
10411
10643
|
} else {
|
10412
|
-
plotBackground.animate(
|
10644
|
+
plotBackground.animate(plotBox);
|
10413
10645
|
}
|
10414
10646
|
}
|
10415
10647
|
if (plotBackgroundImage) {
|
10416
10648
|
if (!plotBGImage) {
|
10417
|
-
chart.plotBGImage = renderer.image(plotBackgroundImage,
|
10649
|
+
chart.plotBGImage = renderer.image(plotBackgroundImage, plotLeft, plotTop, plotWidth, plotHeight)
|
10418
10650
|
.add();
|
10419
10651
|
} else {
|
10420
|
-
plotBGImage.animate(
|
10652
|
+
plotBGImage.animate(plotBox);
|
10421
10653
|
}
|
10422
10654
|
}
|
10655
|
+
|
10656
|
+
// Plot clip
|
10657
|
+
if (!clipRect) {
|
10658
|
+
chart.clipRect = renderer.clipRect(clipBox);
|
10659
|
+
} else {
|
10660
|
+
clipRect.animate({
|
10661
|
+
width: clipBox.width,
|
10662
|
+
height: clipBox.height
|
10663
|
+
});
|
10664
|
+
}
|
10423
10665
|
|
10424
10666
|
// Plot area border
|
10425
|
-
if (
|
10667
|
+
if (plotBorderWidth) {
|
10426
10668
|
if (!plotBorder) {
|
10427
|
-
chart.plotBorder = renderer.rect(
|
10669
|
+
chart.plotBorder = renderer.rect(plotLeft, plotTop, plotWidth, plotHeight, 0, plotBorderWidth)
|
10428
10670
|
.attr({
|
10429
10671
|
stroke: optionsChart.plotBorderColor,
|
10430
|
-
'stroke-width':
|
10431
|
-
zIndex:
|
10672
|
+
'stroke-width': plotBorderWidth,
|
10673
|
+
zIndex: 1
|
10432
10674
|
})
|
10433
10675
|
.add();
|
10434
10676
|
} else {
|
10435
10677
|
plotBorder.animate(
|
10436
|
-
plotBorder.crisp(null,
|
10678
|
+
plotBorder.crisp(null, plotLeft, plotTop, plotWidth, plotHeight)
|
10437
10679
|
);
|
10438
10680
|
}
|
10439
10681
|
}
|
@@ -10544,8 +10786,8 @@ Chart.prototype = {
|
|
10544
10786
|
|
10545
10787
|
// Labels
|
10546
10788
|
if (labels.items) {
|
10547
|
-
each(labels.items, function () {
|
10548
|
-
var style = extend(labels.style,
|
10789
|
+
each(labels.items, function (label) {
|
10790
|
+
var style = extend(labels.style, label.style),
|
10549
10791
|
x = pInt(style.left) + chart.plotLeft,
|
10550
10792
|
y = pInt(style.top) + chart.plotTop + 12;
|
10551
10793
|
|
@@ -10554,7 +10796,7 @@ Chart.prototype = {
|
|
10554
10796
|
delete style.top;
|
10555
10797
|
|
10556
10798
|
renderer.text(
|
10557
|
-
|
10799
|
+
label.html,
|
10558
10800
|
x,
|
10559
10801
|
y
|
10560
10802
|
)
|
@@ -10837,10 +11079,7 @@ Point.prototype = {
|
|
10837
11079
|
|
10838
11080
|
if (series.options.colorByPoint) {
|
10839
11081
|
defaultColors = series.chart.options.colors;
|
10840
|
-
|
10841
|
-
point.options = {};
|
10842
|
-
}
|
10843
|
-
point.color = point.options.color = point.color || defaultColors[counters.color++];
|
11082
|
+
point.color = point.color || defaultColors[counters.color++];
|
10844
11083
|
|
10845
11084
|
// loop back to zero
|
10846
11085
|
counters.wrapColor(defaultColors.length);
|
@@ -10878,6 +11117,11 @@ Point.prototype = {
|
|
10878
11117
|
if (options.dataLabels) {
|
10879
11118
|
series._hasPointLabels = true;
|
10880
11119
|
}
|
11120
|
+
|
11121
|
+
// Same approach as above for markers
|
11122
|
+
if (options.marker) {
|
11123
|
+
series._hasPointMarkers = true;
|
11124
|
+
}
|
10881
11125
|
} else if (typeof options[0] === 'string') { // categorized data with name in first position
|
10882
11126
|
point.name = options[0];
|
10883
11127
|
point.y = options[1];
|
@@ -10892,8 +11136,6 @@ Point.prototype = {
|
|
10892
11136
|
point.x = x === UNDEFINED ? series.autoIncrement() : x;
|
10893
11137
|
}
|
10894
11138
|
|
10895
|
-
|
10896
|
-
|
10897
11139
|
},
|
10898
11140
|
|
10899
11141
|
/**
|
@@ -11026,11 +11268,15 @@ Point.prototype = {
|
|
11026
11268
|
},
|
11027
11269
|
|
11028
11270
|
onMouseOut: function () {
|
11029
|
-
var
|
11030
|
-
|
11031
|
-
|
11032
|
-
|
11033
|
-
|
11271
|
+
var chart = this.series.chart,
|
11272
|
+
hoverPoints = chart.hoverPoints;
|
11273
|
+
|
11274
|
+
if (!hoverPoints || inArray(this, hoverPoints) === -1) { // #887
|
11275
|
+
this.firePointEvent('mouseOut');
|
11276
|
+
|
11277
|
+
this.setState();
|
11278
|
+
chart.hoverPoint = null;
|
11279
|
+
}
|
11034
11280
|
},
|
11035
11281
|
|
11036
11282
|
/**
|
@@ -11294,27 +11540,28 @@ Point.prototype = {
|
|
11294
11540
|
// if a graphic is not applied to each point in the normal state, create a shared
|
11295
11541
|
// graphic for the hover state
|
11296
11542
|
if (state && markerStateOptions) {
|
11297
|
-
|
11298
|
-
|
11543
|
+
radius = markerStateOptions.radius;
|
11544
|
+
if (!stateMarkerGraphic) { // add
|
11299
11545
|
series.stateMarkerGraphic = stateMarkerGraphic = chart.renderer.symbol(
|
11300
11546
|
series.symbol,
|
11301
|
-
-radius,
|
11302
|
-
-radius,
|
11547
|
+
plotX - radius,
|
11548
|
+
plotY - radius,
|
11303
11549
|
2 * radius,
|
11304
11550
|
2 * radius
|
11305
11551
|
)
|
11306
11552
|
.attr(pointAttr[state])
|
11307
|
-
.add(series.
|
11553
|
+
.add(series.markerGroup);
|
11554
|
+
|
11555
|
+
} else { // update
|
11556
|
+
stateMarkerGraphic.attr({ // #1054
|
11557
|
+
x: plotX - radius,
|
11558
|
+
y: plotY - radius
|
11559
|
+
});
|
11308
11560
|
}
|
11309
|
-
|
11310
|
-
stateMarkerGraphic.translate(
|
11311
|
-
plotX,
|
11312
|
-
plotY
|
11313
|
-
);
|
11314
11561
|
}
|
11315
11562
|
|
11316
11563
|
if (stateMarkerGraphic) {
|
11317
|
-
stateMarkerGraphic[state ? 'show' : 'hide']();
|
11564
|
+
stateMarkerGraphic[state && chart.isInsidePlot(plotX, plotY) ? 'show' : 'hide']();
|
11318
11565
|
}
|
11319
11566
|
}
|
11320
11567
|
|
@@ -11358,9 +11605,7 @@ Series.prototype = {
|
|
11358
11605
|
init: function (chart, options) {
|
11359
11606
|
var series = this,
|
11360
11607
|
eventType,
|
11361
|
-
events
|
11362
|
-
//pointEvent,
|
11363
|
-
index = chart.series.length;
|
11608
|
+
events;
|
11364
11609
|
|
11365
11610
|
series.chart = chart;
|
11366
11611
|
series.options = options = series.setOptions(options); // merge with plotOptions
|
@@ -11370,8 +11615,7 @@ Series.prototype = {
|
|
11370
11615
|
|
11371
11616
|
// set some variables
|
11372
11617
|
extend(series, {
|
11373
|
-
|
11374
|
-
name: options.name || 'Series ' + (index + 1),
|
11618
|
+
name: options.name,
|
11375
11619
|
state: NORMAL_STATE,
|
11376
11620
|
pointAttr: {},
|
11377
11621
|
visible: options.visible !== false, // true by default
|
@@ -11409,6 +11653,15 @@ Series.prototype = {
|
|
11409
11653
|
|
11410
11654
|
// Register it in the chart
|
11411
11655
|
chart.series.push(series);
|
11656
|
+
|
11657
|
+
// Sort series according to index option (#248, #1123)
|
11658
|
+
stableSort(chart.series, function (a, b) {
|
11659
|
+
return (a.options.index || 0) - (b.options.index || 0);
|
11660
|
+
});
|
11661
|
+
each(chart.series, function (series, i) {
|
11662
|
+
series.index = i;
|
11663
|
+
series.name = series.name || 'Series ' + (i + 1);
|
11664
|
+
});
|
11412
11665
|
},
|
11413
11666
|
|
11414
11667
|
/**
|
@@ -11515,17 +11768,17 @@ Series.prototype = {
|
|
11515
11768
|
* @param {Object} itemOptions
|
11516
11769
|
*/
|
11517
11770
|
setOptions: function (itemOptions) {
|
11518
|
-
var
|
11519
|
-
chart = series.chart,
|
11771
|
+
var chart = this.chart,
|
11520
11772
|
chartOptions = chart.options,
|
11521
11773
|
plotOptions = chartOptions.plotOptions,
|
11774
|
+
typeOptions = plotOptions[this.type],
|
11522
11775
|
data = itemOptions.data,
|
11523
11776
|
options;
|
11524
11777
|
|
11525
11778
|
itemOptions.data = null; // remove from merge to prevent looping over the data set
|
11526
11779
|
|
11527
11780
|
options = merge(
|
11528
|
-
|
11781
|
+
typeOptions,
|
11529
11782
|
plotOptions.series,
|
11530
11783
|
itemOptions
|
11531
11784
|
);
|
@@ -11534,7 +11787,12 @@ Series.prototype = {
|
|
11534
11787
|
options.data = itemOptions.data = data;
|
11535
11788
|
|
11536
11789
|
// the tooltip options are merged between global and series specific options
|
11537
|
-
|
11790
|
+
this.tooltipOptions = merge(chartOptions.tooltip, options.tooltip);
|
11791
|
+
|
11792
|
+
// Delte marker object if not allowed (#1125)
|
11793
|
+
if (typeOptions.marker === null) {
|
11794
|
+
delete options.marker;
|
11795
|
+
}
|
11538
11796
|
|
11539
11797
|
return options;
|
11540
11798
|
|
@@ -11641,8 +11899,8 @@ Series.prototype = {
|
|
11641
11899
|
yData = series.yData,
|
11642
11900
|
currentShift = (graph && graph.shift) || 0,
|
11643
11901
|
dataOptions = series.options.data,
|
11644
|
-
point
|
11645
|
-
|
11902
|
+
point,
|
11903
|
+
proto = series.pointClass.prototype;
|
11646
11904
|
|
11647
11905
|
setAnimation(animation, chart);
|
11648
11906
|
|
@@ -11663,9 +11921,9 @@ Series.prototype = {
|
|
11663
11921
|
// Get options and push the point to xData, yData and series.options. In series.generatePoints
|
11664
11922
|
// the Point instance will be created on demand and pushed to the series.data array.
|
11665
11923
|
point = { series: series };
|
11666
|
-
|
11924
|
+
proto.applyOptions.apply(point, [options]);
|
11667
11925
|
xData.push(point.x);
|
11668
|
-
yData.push(
|
11926
|
+
yData.push(proto.toYData ? proto.toYData.call(point) : point.y);
|
11669
11927
|
dataOptions.push(options);
|
11670
11928
|
|
11671
11929
|
|
@@ -11709,7 +11967,7 @@ Series.prototype = {
|
|
11709
11967
|
|
11710
11968
|
// reset properties
|
11711
11969
|
series.xIncrement = null;
|
11712
|
-
series.pointRange =
|
11970
|
+
series.pointRange = xAxis && xAxis.categories ? 1 : options.pointRange;
|
11713
11971
|
|
11714
11972
|
if (defined(initialColor)) { // reset colors for pie
|
11715
11973
|
chart.counters.color = initialColor;
|
@@ -11721,7 +11979,8 @@ Series.prototype = {
|
|
11721
11979
|
dataLength = data ? data.length : [],
|
11722
11980
|
turboThreshold = options.turboThreshold || 1000,
|
11723
11981
|
pt,
|
11724
|
-
|
11982
|
+
pointArrayMap = series.pointArrayMap,
|
11983
|
+
valueCount = pointArrayMap && pointArrayMap.length;
|
11725
11984
|
|
11726
11985
|
// In turbo mode, only one- or twodimensional arrays of numbers are allowed. The
|
11727
11986
|
// first value is tested, and we assume that all the rest are defined the same
|
@@ -11769,10 +12028,15 @@ Series.prototype = {
|
|
11769
12028
|
pt = { series: series };
|
11770
12029
|
pointProto.applyOptions.apply(pt, [data[i]]);
|
11771
12030
|
xData[i] = pt.x;
|
11772
|
-
yData[i] = pointProto.toYData ? pointProto.toYData.
|
12031
|
+
yData[i] = pointProto.toYData ? pointProto.toYData.call(pt) : pt.y;
|
11773
12032
|
}
|
11774
12033
|
}
|
11775
12034
|
|
12035
|
+
// Forgetting to cast strings to numbers is a common caveat when handling CSV or JSON
|
12036
|
+
if (isString(yData[0])) {
|
12037
|
+
error(14, true);
|
12038
|
+
}
|
12039
|
+
|
11776
12040
|
series.data = [];
|
11777
12041
|
series.options.data = data;
|
11778
12042
|
series.xData = xData;
|
@@ -11996,15 +12260,17 @@ Series.prototype = {
|
|
11996
12260
|
points = series.points,
|
11997
12261
|
dataLength = points.length,
|
11998
12262
|
hasModifyValue = !!series.modifyValue,
|
11999
|
-
|
12263
|
+
isBottomSeries,
|
12000
12264
|
allStackSeries = yAxis.series,
|
12001
|
-
i = allStackSeries.length
|
12265
|
+
i = allStackSeries.length,
|
12266
|
+
placeBetween = options.pointPlacement === 'between';
|
12267
|
+
//nextSeriesDown;
|
12002
12268
|
|
12003
12269
|
// Is it the last visible series?
|
12004
12270
|
while (i--) {
|
12005
12271
|
if (allStackSeries[i].visible) {
|
12006
|
-
if (i === series
|
12007
|
-
|
12272
|
+
if (allStackSeries[i] === series) { // #809
|
12273
|
+
isBottomSeries = true;
|
12008
12274
|
}
|
12009
12275
|
break;
|
12010
12276
|
}
|
@@ -12022,7 +12288,7 @@ Series.prototype = {
|
|
12022
12288
|
|
12023
12289
|
// get the plotX translation
|
12024
12290
|
//point.plotX = mathRound(xAxis.translate(xValue, 0, 0, 0, 1) * 10) / 10; // Math.round fixes #591
|
12025
|
-
point.plotX = xAxis.translate(xValue, 0, 0, 0, 1); // Math.round fixes #591
|
12291
|
+
point.plotX = xAxis.translate(xValue, 0, 0, 0, 1, placeBetween); // Math.round fixes #591
|
12026
12292
|
|
12027
12293
|
// calculate the bottom y value for stacked series
|
12028
12294
|
if (stacking && series.visible && stack && stack[xValue]) {
|
@@ -12031,8 +12297,8 @@ Series.prototype = {
|
|
12031
12297
|
pointStack.cum = yBottom = pointStack.cum - yValue; // start from top
|
12032
12298
|
yValue = yBottom + yValue;
|
12033
12299
|
|
12034
|
-
if (
|
12035
|
-
yBottom = options.threshold;
|
12300
|
+
if (isBottomSeries) {
|
12301
|
+
yBottom = pick(options.threshold, yAxis.isLog ? null : yAxis.min); // #1200
|
12036
12302
|
}
|
12037
12303
|
|
12038
12304
|
if (stacking === 'percent') {
|
@@ -12041,7 +12307,7 @@ Series.prototype = {
|
|
12041
12307
|
}
|
12042
12308
|
|
12043
12309
|
point.percentage = pointStackTotal ? point.y * 100 / pointStackTotal : 0;
|
12044
|
-
point.stackTotal = pointStackTotal;
|
12310
|
+
point.total = point.stackTotal = pointStackTotal;
|
12045
12311
|
point.stackY = yValue;
|
12046
12312
|
}
|
12047
12313
|
|
@@ -12059,7 +12325,7 @@ Series.prototype = {
|
|
12059
12325
|
point.plotY = (typeof yValue === 'number') ?
|
12060
12326
|
mathRound(yAxis.translate(yValue, 0, 1, 0, 1) * 10) / 10 : // Math.round fixes #591
|
12061
12327
|
UNDEFINED;
|
12062
|
-
|
12328
|
+
|
12063
12329
|
// set client related positions for mouse tracking
|
12064
12330
|
point.clientX = chart.inverted ?
|
12065
12331
|
chart.plotHeight - point.plotX :
|
@@ -12080,13 +12346,13 @@ Series.prototype = {
|
|
12080
12346
|
*/
|
12081
12347
|
setTooltipPoints: function (renew) {
|
12082
12348
|
var series = this,
|
12083
|
-
chart = series.chart,
|
12084
12349
|
points = [],
|
12085
12350
|
pointsLength,
|
12086
|
-
plotSize = chart.plotSizeX,
|
12087
12351
|
low,
|
12088
12352
|
high,
|
12089
12353
|
xAxis = series.xAxis,
|
12354
|
+
axisLength = xAxis ? (xAxis.tooltipLen || xAxis.len) : series.chart.plotSizeX, // tooltipLen and tooltipPosName used in polar
|
12355
|
+
plotX = (xAxis && xAxis.tooltipPosName) || 'plotX',
|
12090
12356
|
point,
|
12091
12357
|
i,
|
12092
12358
|
tooltipPoints = []; // a lookup array for each pixel in the x dimension
|
@@ -12106,8 +12372,7 @@ Series.prototype = {
|
|
12106
12372
|
points = points.concat(segment);
|
12107
12373
|
});
|
12108
12374
|
|
12109
|
-
//
|
12110
|
-
// pixel positions
|
12375
|
+
// Reverse the points in case the X axis is reversed
|
12111
12376
|
if (xAxis && xAxis.reversed) {
|
12112
12377
|
points = points.reverse();
|
12113
12378
|
}
|
@@ -12116,10 +12381,12 @@ Series.prototype = {
|
|
12116
12381
|
pointsLength = points.length;
|
12117
12382
|
for (i = 0; i < pointsLength; i++) {
|
12118
12383
|
point = points[i];
|
12119
|
-
|
12120
|
-
|
12121
|
-
|
12122
|
-
|
12384
|
+
// Set this range's low to the last range's high plus one
|
12385
|
+
low = points[i - 1] ? high + 1 : 0;
|
12386
|
+
// Now find the new high
|
12387
|
+
high = points[i + 1] ?
|
12388
|
+
mathMax(0, mathFloor((point[plotX] + (points[i + 1] ? points[i + 1][plotX] : axisLength)) / 2)) :
|
12389
|
+
axisLength;
|
12123
12390
|
|
12124
12391
|
while (low >= 0 && low <= high) {
|
12125
12392
|
tooltipPoints[low++] = point;
|
@@ -12163,9 +12430,9 @@ Series.prototype = {
|
|
12163
12430
|
chart = series.chart,
|
12164
12431
|
hoverSeries = chart.hoverSeries;
|
12165
12432
|
|
12166
|
-
if (!hasTouch && chart.mouseIsDown) {
|
12433
|
+
/*if (!hasTouch && chart.mouseIsDown) {
|
12167
12434
|
return;
|
12168
|
-
}
|
12435
|
+
}*/
|
12169
12436
|
|
12170
12437
|
// set normal state to previous series
|
12171
12438
|
if (hoverSeries && hoverSeries !== series) {
|
@@ -12221,29 +12488,86 @@ Series.prototype = {
|
|
12221
12488
|
animate: function (init) {
|
12222
12489
|
var series = this,
|
12223
12490
|
chart = series.chart,
|
12224
|
-
|
12225
|
-
|
12491
|
+
renderer = chart.renderer,
|
12492
|
+
clipRect,
|
12493
|
+
markerClipRect,
|
12494
|
+
animation = series.options.animation,
|
12495
|
+
clipBox = chart.clipBox,
|
12496
|
+
inverted = chart.inverted,
|
12497
|
+
sharedClipKey;
|
12226
12498
|
|
12499
|
+
// Animation option is set to true
|
12227
12500
|
if (animation && !isObject(animation)) {
|
12228
|
-
animation =
|
12501
|
+
animation = defaultPlotOptions[series.type].animation;
|
12229
12502
|
}
|
12503
|
+
sharedClipKey = '_sharedClip' + animation.duration + animation.easing;
|
12230
12504
|
|
12231
|
-
|
12232
|
-
|
12233
|
-
|
12234
|
-
|
12505
|
+
// Initialize the animation. Set up the clipping rectangle.
|
12506
|
+
if (init) {
|
12507
|
+
|
12508
|
+
// If a clipping rectangle with the same properties is currently present in the chart, use that.
|
12509
|
+
clipRect = chart[sharedClipKey];
|
12510
|
+
markerClipRect = chart[sharedClipKey + 'm'];
|
12511
|
+
if (!clipRect) {
|
12512
|
+
chart[sharedClipKey] = clipRect = renderer.clipRect(
|
12513
|
+
extend(clipBox, { width: 0 })
|
12514
|
+
);
|
12515
|
+
|
12516
|
+
chart[sharedClipKey + 'm'] = markerClipRect = renderer.clipRect(
|
12517
|
+
-99, // include the width of the first marker
|
12518
|
+
inverted ? -chart.plotLeft : -chart.plotTop,
|
12519
|
+
99,
|
12520
|
+
inverted ? chart.chartWidth : chart.chartHeight
|
12521
|
+
);
|
12235
12522
|
}
|
12523
|
+
series.group.clip(clipRect);
|
12524
|
+
series.markerGroup.clip(markerClipRect);
|
12525
|
+
series.sharedClipKey = sharedClipKey;
|
12236
12526
|
|
12237
|
-
|
12238
|
-
|
12239
|
-
|
12240
|
-
|
12527
|
+
// Run the animation
|
12528
|
+
} else {
|
12529
|
+
clipRect = chart[sharedClipKey];
|
12530
|
+
if (clipRect) {
|
12531
|
+
clipRect.animate({
|
12532
|
+
width: chart.plotSizeX
|
12533
|
+
}, animation);
|
12534
|
+
chart[sharedClipKey + 'm'].animate({
|
12535
|
+
width: chart.plotSizeX + 99
|
12536
|
+
}, animation);
|
12537
|
+
}
|
12241
12538
|
|
12242
|
-
//
|
12243
|
-
|
12539
|
+
// Delete this function to allow it only once
|
12540
|
+
series.animate = null;
|
12541
|
+
|
12542
|
+
// Call the afterAnimate function on animation complete (but don't overwrite the animation.complete option
|
12543
|
+
// which should be available to the user).
|
12544
|
+
series.animationTimeout = setTimeout(function () {
|
12545
|
+
series.afterAnimate();
|
12546
|
+
}, animation.duration);
|
12244
12547
|
}
|
12245
12548
|
},
|
12246
|
-
|
12549
|
+
|
12550
|
+
/**
|
12551
|
+
* This runs after animation to land on the final plot clipping
|
12552
|
+
*/
|
12553
|
+
afterAnimate: function () {
|
12554
|
+
var chart = this.chart,
|
12555
|
+
sharedClipKey = this.sharedClipKey,
|
12556
|
+
group = this.group;
|
12557
|
+
|
12558
|
+
if (group && this.options.clip !== false) {
|
12559
|
+
group.clip(chart.clipRect);
|
12560
|
+
this.markerGroup.clip(); // no clip
|
12561
|
+
}
|
12562
|
+
|
12563
|
+
// Remove the shared clipping rectancgle when all series are shown
|
12564
|
+
setTimeout(function () {
|
12565
|
+
if (sharedClipKey && chart[sharedClipKey]) {
|
12566
|
+
chart[sharedClipKey] = chart[sharedClipKey].destroy();
|
12567
|
+
chart[sharedClipKey + 'm'] = chart[sharedClipKey + 'm'].destroy();
|
12568
|
+
}
|
12569
|
+
}, 100);
|
12570
|
+
},
|
12247
12571
|
|
12248
12572
|
/**
|
12249
12573
|
* Draw the markers
|
@@ -12260,35 +12584,49 @@ Series.prototype = {
|
|
12260
12584
|
radius,
|
12261
12585
|
symbol,
|
12262
12586
|
isImage,
|
12263
|
-
graphic
|
12587
|
+
graphic,
|
12588
|
+
options = series.options,
|
12589
|
+
seriesMarkerOptions = options.marker,
|
12590
|
+
pointMarkerOptions,
|
12591
|
+
enabled,
|
12592
|
+
isInside,
|
12593
|
+
markerGroup = series.markerGroup;
|
12264
12594
|
|
12265
|
-
if (series.
|
12595
|
+
if (seriesMarkerOptions.enabled || series._hasPointMarkers) {
|
12596
|
+
|
12266
12597
|
i = points.length;
|
12267
12598
|
while (i--) {
|
12268
12599
|
point = points[i];
|
12269
12600
|
plotX = point.plotX;
|
12270
12601
|
plotY = point.plotY;
|
12271
12602
|
graphic = point.graphic;
|
12272
|
-
|
12603
|
+
pointMarkerOptions = point.marker || {};
|
12604
|
+
enabled = (seriesMarkerOptions.enabled && pointMarkerOptions.enabled === UNDEFINED) || pointMarkerOptions.enabled;
|
12605
|
+
isInside = chart.isInsidePlot(plotX, plotY, chart.inverted);
|
12606
|
+
|
12273
12607
|
// only draw the point if y is defined
|
12274
|
-
if (plotY !== UNDEFINED && !isNaN(plotY)) {
|
12608
|
+
if (enabled && plotY !== UNDEFINED && !isNaN(plotY)) {
|
12275
12609
|
|
12276
12610
|
// shortcuts
|
12277
12611
|
pointAttr = point.pointAttr[point.selected ? SELECT_STATE : NORMAL_STATE];
|
12278
12612
|
radius = pointAttr.r;
|
12279
|
-
symbol = pick(
|
12613
|
+
symbol = pick(pointMarkerOptions.symbol, series.symbol);
|
12280
12614
|
isImage = symbol.indexOf('url') === 0;
|
12281
12615
|
|
12282
12616
|
if (graphic) { // update
|
12283
|
-
graphic
|
12284
|
-
|
12285
|
-
|
12286
|
-
|
12287
|
-
|
12288
|
-
|
12289
|
-
|
12290
|
-
|
12291
|
-
|
12617
|
+
graphic
|
12618
|
+
.attr({ // Since the marker group isn't clipped, each individual marker must be toggled
|
12619
|
+
visibility: isInside ? (hasSVG ? 'inherit' : VISIBLE) : HIDDEN
|
12620
|
+
})
|
12621
|
+
.animate(extend({
|
12622
|
+
x: plotX - radius,
|
12623
|
+
y: plotY - radius
|
12624
|
+
}, graphic.symbolName ? { // don't apply to image symbols #507
|
12625
|
+
width: 2 * radius,
|
12626
|
+
height: 2 * radius
|
12627
|
+
} : {}));
|
12628
|
+
} else if (isInside && (radius > 0 || isImage)) {
|
12629
|
+
point.graphic = graphic = chart.renderer.symbol(
|
12292
12630
|
symbol,
|
12293
12631
|
plotX - radius,
|
12294
12632
|
plotY - radius,
|
@@ -12296,7 +12634,7 @@ Series.prototype = {
|
|
12296
12634
|
2 * radius
|
12297
12635
|
)
|
12298
12636
|
.attr(pointAttr)
|
12299
|
-
.add(
|
12637
|
+
.add(markerGroup);
|
12300
12638
|
}
|
12301
12639
|
}
|
12302
12640
|
}
|
@@ -12394,8 +12732,8 @@ Series.prototype = {
|
|
12394
12732
|
if (normalOptions && normalOptions.enabled === false) {
|
12395
12733
|
normalOptions.radius = 0;
|
12396
12734
|
}
|
12397
|
-
hasPointSpecificOptions =
|
12398
|
-
|
12735
|
+
hasPointSpecificOptions = series.options.colorByPoint; // #868
|
12736
|
+
|
12399
12737
|
// check if the point has specific visual options
|
12400
12738
|
if (point.options) {
|
12401
12739
|
for (key in pointAttrToOptions) {
|
@@ -12410,22 +12748,25 @@ Series.prototype = {
|
|
12410
12748
|
// a specific marker config object is defined for the individual point:
|
12411
12749
|
// create it's own attribute collection
|
12412
12750
|
if (hasPointSpecificOptions) {
|
12413
|
-
|
12751
|
+
normalOptions = normalOptions || {};
|
12414
12752
|
pointAttr = [];
|
12415
12753
|
stateOptions = normalOptions.states || {}; // reassign for individual point
|
12416
12754
|
pointStateOptionsHover = stateOptions[HOVER_STATE] = stateOptions[HOVER_STATE] || {};
|
12417
12755
|
|
12418
|
-
//
|
12756
|
+
// Handle colors for column and pies
|
12419
12757
|
if (!series.options.marker) { // column, bar, point
|
12758
|
+
// if no hover color is given, brighten the normal color
|
12420
12759
|
pointStateOptionsHover.color =
|
12421
|
-
Color(pointStateOptionsHover.color || point.
|
12760
|
+
Color(pointStateOptionsHover.color || point.color)
|
12422
12761
|
.brighten(pointStateOptionsHover.brightness ||
|
12423
12762
|
stateOptionsHover.brightness).get();
|
12424
12763
|
|
12425
12764
|
}
|
12426
12765
|
|
12427
12766
|
// normal point state inherits series wide normal state
|
12428
|
-
pointAttr[NORMAL_STATE] = series.convertAttribs(
|
12767
|
+
pointAttr[NORMAL_STATE] = series.convertAttribs(extend({
|
12768
|
+
color: point.color // #868
|
12769
|
+
}, normalOptions), seriesPointAttr[NORMAL_STATE]);
|
12429
12770
|
|
12430
12771
|
// inherit from point normal and series hover
|
12431
12772
|
pointAttr[HOVER_STATE] = series.convertAttribs(
|
@@ -12461,7 +12802,6 @@ Series.prototype = {
|
|
12461
12802
|
destroy: function () {
|
12462
12803
|
var series = this,
|
12463
12804
|
chart = series.chart,
|
12464
|
-
seriesClipRect = series.clipRect,
|
12465
12805
|
issue134 = /AppleWebKit\/533/.test(userAgent),
|
12466
12806
|
destroy,
|
12467
12807
|
i,
|
@@ -12500,14 +12840,11 @@ Series.prototype = {
|
|
12500
12840
|
}
|
12501
12841
|
series.points = null;
|
12502
12842
|
|
12503
|
-
//
|
12504
|
-
|
12505
|
-
if (seriesClipRect && seriesClipRect !== chart.clipRect) {
|
12506
|
-
series.clipRect = seriesClipRect.destroy();
|
12507
|
-
}
|
12843
|
+
// Clear the animation timeout if we are destroying the series during initial animation
|
12844
|
+
clearTimeout(series.animationTimeout);
|
12508
12845
|
|
12509
12846
|
// destroy all SVGElements associated to the series
|
12510
|
-
each(['area', 'graph', 'dataLabelsGroup', 'group', 'tracker', 'trackerGroup'], function (prop) {
|
12847
|
+
each(['area', 'graph', 'dataLabelsGroup', 'group', 'markerGroup', 'tracker', 'trackerGroup'], function (prop) {
|
12511
12848
|
if (series[prop]) {
|
12512
12849
|
|
12513
12850
|
// issue 134 workaround
|
@@ -12547,12 +12884,8 @@ Series.prototype = {
|
|
12547
12884
|
pointOptions,
|
12548
12885
|
generalOptions,
|
12549
12886
|
str,
|
12550
|
-
dataLabelsGroup
|
12887
|
+
dataLabelsGroup,
|
12551
12888
|
chart = series.chart,
|
12552
|
-
xAxis = series.xAxis,
|
12553
|
-
groupLeft = xAxis ? xAxis.left : chart.plotLeft,
|
12554
|
-
yAxis = series.yAxis,
|
12555
|
-
groupTop = yAxis ? yAxis.top : chart.plotTop,
|
12556
12889
|
renderer = chart.renderer,
|
12557
12890
|
inverted = chart.inverted,
|
12558
12891
|
seriesType = series.type,
|
@@ -12562,9 +12895,7 @@ Series.prototype = {
|
|
12562
12895
|
yIsNull = options.y === null,
|
12563
12896
|
fontMetrics = renderer.fontMetrics(options.style.fontSize), // height and baseline
|
12564
12897
|
fontLineHeight = fontMetrics.h,
|
12565
|
-
fontBaseline = fontMetrics.b
|
12566
|
-
dataLabel,
|
12567
|
-
enabled;
|
12898
|
+
fontBaseline = fontMetrics.b;
|
12568
12899
|
|
12569
12900
|
if (isBarLike) {
|
12570
12901
|
var defaultYs = {
|
@@ -12597,24 +12928,22 @@ Series.prototype = {
|
|
12597
12928
|
|
12598
12929
|
|
12599
12930
|
// create a separate group for the data labels to avoid rotation
|
12600
|
-
|
12601
|
-
dataLabelsGroup
|
12602
|
-
|
12603
|
-
|
12604
|
-
|
12605
|
-
|
12606
|
-
})
|
12607
|
-
.translate(groupLeft, groupTop)
|
12608
|
-
.add();
|
12609
|
-
} else {
|
12610
|
-
dataLabelsGroup.translate(groupLeft, groupTop);
|
12611
|
-
}
|
12931
|
+
dataLabelsGroup = series.plotGroup(
|
12932
|
+
'dataLabelsGroup',
|
12933
|
+
'data-labels',
|
12934
|
+
series.visible ? VISIBLE : HIDDEN,
|
12935
|
+
6
|
12936
|
+
);
|
12612
12937
|
|
12613
12938
|
// make the labels for each point
|
12614
12939
|
generalOptions = options;
|
12615
12940
|
each(points, function (point) {
|
12616
12941
|
|
12617
|
-
|
12942
|
+
var plotX,
|
12943
|
+
plotY,
|
12944
|
+
individualYDelta,
|
12945
|
+
enabled,
|
12946
|
+
dataLabel = point.dataLabel;
|
12618
12947
|
|
12619
12948
|
// Merge in individual options from point
|
12620
12949
|
options = generalOptions; // reset changes from previous points
|
@@ -12626,24 +12955,30 @@ Series.prototype = {
|
|
12626
12955
|
|
12627
12956
|
// Get the positions
|
12628
12957
|
if (enabled) {
|
12629
|
-
|
12630
|
-
|
12958
|
+
plotX = (point.barX && point.barX + point.barW / 2) || pick(point.plotX, -999);
|
12959
|
+
plotY = pick(point.plotY, -999);
|
12631
12960
|
|
12632
|
-
|
12633
|
-
|
12634
|
-
|
12635
|
-
|
12636
|
-
|
12637
|
-
|
12638
|
-
|
12961
|
+
// if options.y is null, which happens by default on column charts, set the position
|
12962
|
+
// above or below the column depending on the threshold
|
12963
|
+
individualYDelta = options.y === null ?
|
12964
|
+
(point.y >= seriesOptions.threshold ?
|
12965
|
+
-fontLineHeight + fontBaseline : // below the threshold
|
12966
|
+
fontBaseline) : // above the threshold
|
12967
|
+
options.y;
|
12639
12968
|
|
12640
12969
|
x = (inverted ? chart.plotWidth - plotY : plotX) + options.x;
|
12641
12970
|
y = mathRound((inverted ? chart.plotHeight - plotX : plotY) + individualYDelta);
|
12642
12971
|
|
12643
12972
|
}
|
12644
12973
|
|
12974
|
+
// Check if the individual label must be disabled due to either falling
|
12975
|
+
// ouside the plot area, or the enabled option being switched off
|
12976
|
+
if (series.isCartesian && !chart.isInsidePlot(x - options.x, y)) {
|
12977
|
+
enabled = false;
|
12978
|
+
}
|
12979
|
+
|
12645
12980
|
// If the point is outside the plot area, destroy it. #678, #820
|
12646
|
-
if (dataLabel &&
|
12981
|
+
if (dataLabel && !enabled) {
|
12647
12982
|
point.dataLabel = dataLabel.destroy();
|
12648
12983
|
|
12649
12984
|
// Individual labels are disabled if the are explicitly disabled
|
@@ -12776,24 +13111,15 @@ Series.prototype = {
|
|
12776
13111
|
},
|
12777
13112
|
|
12778
13113
|
/**
|
12779
|
-
*
|
13114
|
+
* Get the graph path
|
12780
13115
|
*/
|
12781
|
-
|
13116
|
+
getGraphPath: function () {
|
12782
13117
|
var series = this,
|
12783
|
-
options = series.options,
|
12784
|
-
chart = series.chart,
|
12785
|
-
graph = series.graph,
|
12786
13118
|
graphPath = [],
|
12787
|
-
group = series.group,
|
12788
|
-
color = options.lineColor || series.color,
|
12789
|
-
lineWidth = options.lineWidth,
|
12790
|
-
dashStyle = options.dashStyle,
|
12791
13119
|
segmentPath,
|
12792
|
-
|
12793
|
-
singlePoints = [], // used in drawTracker
|
12794
|
-
attribs;
|
13120
|
+
singlePoints = []; // used in drawTracker
|
12795
13121
|
|
12796
|
-
//
|
13122
|
+
// Divide into segments and build graph and area paths
|
12797
13123
|
each(series.segments, function (segment) {
|
12798
13124
|
|
12799
13125
|
segmentPath = series.getSegmentPath(segment);
|
@@ -12806,9 +13132,27 @@ Series.prototype = {
|
|
12806
13132
|
}
|
12807
13133
|
});
|
12808
13134
|
|
12809
|
-
//
|
12810
|
-
series.graphPath = graphPath;
|
13135
|
+
// Record it for use in drawGraph and drawTracker, and return graphPath
|
12811
13136
|
series.singlePoints = singlePoints;
|
13137
|
+
series.graphPath = graphPath;
|
13138
|
+
|
13139
|
+
return graphPath;
|
13140
|
+
|
13141
|
+
},
|
13142
|
+
|
13143
|
+
/**
|
13144
|
+
* Draw the actual graph
|
13145
|
+
*/
|
13146
|
+
drawGraph: function () {
|
13147
|
+
var options = this.options,
|
13148
|
+
graph = this.graph,
|
13149
|
+
group = this.group,
|
13150
|
+
color = options.lineColor || this.color,
|
13151
|
+
lineWidth = options.lineWidth,
|
13152
|
+
dashStyle = options.dashStyle,
|
13153
|
+
attribs,
|
13154
|
+
graphPath = this.getGraphPath();
|
13155
|
+
|
12812
13156
|
|
12813
13157
|
// draw the graph
|
12814
13158
|
if (graph) {
|
@@ -12819,13 +13163,14 @@ Series.prototype = {
|
|
12819
13163
|
if (lineWidth) {
|
12820
13164
|
attribs = {
|
12821
13165
|
stroke: color,
|
12822
|
-
'stroke-width': lineWidth
|
13166
|
+
'stroke-width': lineWidth,
|
13167
|
+
zIndex: 1 // #1069
|
12823
13168
|
};
|
12824
13169
|
if (dashStyle) {
|
12825
13170
|
attribs.dashstyle = dashStyle;
|
12826
13171
|
}
|
12827
13172
|
|
12828
|
-
|
13173
|
+
this.graph = this.chart.renderer.path(graphPath)
|
12829
13174
|
.attr(attribs).add(group).shadow(options.shadow);
|
12830
13175
|
}
|
12831
13176
|
}
|
@@ -12836,8 +13181,6 @@ Series.prototype = {
|
|
12836
13181
|
*/
|
12837
13182
|
invertGroups: function () {
|
12838
13183
|
var series = this,
|
12839
|
-
group = series.group,
|
12840
|
-
trackerGroup = series.trackerGroup,
|
12841
13184
|
chart = series.chart;
|
12842
13185
|
|
12843
13186
|
// A fixed size is needed for inversion to work
|
@@ -12847,13 +13190,11 @@ Series.prototype = {
|
|
12847
13190
|
height: series.xAxis.len
|
12848
13191
|
};
|
12849
13192
|
|
12850
|
-
|
12851
|
-
|
12852
|
-
|
12853
|
-
|
12854
|
-
|
12855
|
-
trackerGroup.attr(size).invert();
|
12856
|
-
}
|
13193
|
+
each(['group', 'trackerGroup', 'markerGroup'], function (groupName) {
|
13194
|
+
if (series[groupName]) {
|
13195
|
+
series[groupName].attr(size).invert();
|
13196
|
+
}
|
13197
|
+
});
|
12857
13198
|
}
|
12858
13199
|
|
12859
13200
|
addEvent(chart, 'resize', setInvert); // do it on resize
|
@@ -12869,24 +13210,34 @@ Series.prototype = {
|
|
12869
13210
|
},
|
12870
13211
|
|
12871
13212
|
/**
|
12872
|
-
*
|
13213
|
+
* General abstraction for creating plot groups like series.group, series.trackerGroup, series.dataLabelsGroup and
|
13214
|
+
* series.markerGroup. On subsequent calls, the group will only be adjusted to the updated plot size.
|
12873
13215
|
*/
|
12874
|
-
|
13216
|
+
plotGroup: function (prop, name, visibility, zIndex, parent) {
|
13217
|
+
var group = this[prop],
|
13218
|
+
chart = this.chart,
|
13219
|
+
xAxis = this.xAxis,
|
13220
|
+
yAxis = this.yAxis;
|
12875
13221
|
|
12876
|
-
|
12877
|
-
|
12878
|
-
|
12879
|
-
|
12880
|
-
|
12881
|
-
|
12882
|
-
|
12883
|
-
|
12884
|
-
|
13222
|
+
// Generate it on first call
|
13223
|
+
if (!group) {
|
13224
|
+
this[prop] = group = chart.renderer.g(name)
|
13225
|
+
.attr({
|
13226
|
+
visibility: visibility,
|
13227
|
+
zIndex: zIndex || 0.1 // IE8 needs this
|
13228
|
+
})
|
13229
|
+
.add(parent);
|
13230
|
+
}
|
13231
|
+
// Place it on first and subsequent (redraw) calls
|
13232
|
+
group.translate(
|
13233
|
+
xAxis ? xAxis.left : chart.plotLeft,
|
13234
|
+
yAxis ? yAxis.top : chart.plotTop
|
13235
|
+
);
|
13236
|
+
|
13237
|
+
return group;
|
12885
13238
|
|
12886
|
-
// Only run this once
|
12887
|
-
this.createGroup = noop;
|
12888
13239
|
},
|
12889
|
-
|
13240
|
+
|
12890
13241
|
/**
|
12891
13242
|
* Render the graph and markers
|
12892
13243
|
*/
|
@@ -12895,34 +13246,29 @@ Series.prototype = {
|
|
12895
13246
|
chart = series.chart,
|
12896
13247
|
group,
|
12897
13248
|
options = series.options,
|
12898
|
-
doClip = options.clip !== false,
|
12899
13249
|
animation = options.animation,
|
12900
|
-
doAnimation = animation && series.animate,
|
12901
|
-
|
12902
|
-
|
12903
|
-
|
12904
|
-
|
12905
|
-
|
12906
|
-
// Add plot area clipping rectangle. If this is before chart.hasRendered,
|
12907
|
-
// create one shared clipRect.
|
12908
|
-
|
12909
|
-
// Todo: since creating the clip property, the clipRect is created but
|
12910
|
-
// never used when clip is false. A better way would be that the animation
|
12911
|
-
// would run, then the clipRect destroyed.
|
12912
|
-
if (!clipRect) {
|
12913
|
-
clipRect = series.clipRect = !chart.hasRendered && chart.clipRect ?
|
12914
|
-
chart.clipRect :
|
12915
|
-
renderer.clipRect(0, 0, chart.plotSizeX, chart.plotSizeY + 1);
|
12916
|
-
if (!chart.clipRect) {
|
12917
|
-
chart.clipRect = clipRect;
|
12918
|
-
}
|
12919
|
-
}
|
13250
|
+
doAnimation = animation && !!series.animate,
|
13251
|
+
visibility = series.visible ? VISIBLE : HIDDEN,
|
13252
|
+
zIndex = options.zIndex,
|
13253
|
+
hasRendered = series.hasRendered,
|
13254
|
+
chartSeriesGroup = chart.seriesGroup;
|
12920
13255
|
|
12921
|
-
|
12922
13256
|
// the group
|
12923
|
-
series.
|
12924
|
-
|
13257
|
+
group = series.plotGroup(
|
13258
|
+
'group',
|
13259
|
+
'series',
|
13260
|
+
visibility,
|
13261
|
+
zIndex,
|
13262
|
+
chartSeriesGroup
|
13263
|
+
);
|
12925
13264
|
|
13265
|
+
series.markerGroup = series.plotGroup(
|
13266
|
+
'markerGroup',
|
13267
|
+
'markers',
|
13268
|
+
visibility,
|
13269
|
+
zIndex,
|
13270
|
+
chartSeriesGroup
|
13271
|
+
);
|
12926
13272
|
|
12927
13273
|
series.drawDataLabels();
|
12928
13274
|
|
@@ -12934,6 +13280,9 @@ Series.prototype = {
|
|
12934
13280
|
// cache attributes for shapes
|
12935
13281
|
series.getAttribs();
|
12936
13282
|
|
13283
|
+
// SVGRenderer needs to know this before drawing elements (#1089)
|
13284
|
+
group.inverted = chart.inverted;
|
13285
|
+
|
12937
13286
|
// draw the graph if any
|
12938
13287
|
if (series.drawGraph) {
|
12939
13288
|
series.drawGraph();
|
@@ -12952,37 +13301,26 @@ Series.prototype = {
|
|
12952
13301
|
series.invertGroups();
|
12953
13302
|
}
|
12954
13303
|
|
12955
|
-
//
|
12956
|
-
if (
|
12957
|
-
group.clip(clipRect);
|
12958
|
-
if (
|
12959
|
-
|
13304
|
+
// Initial clipping, must be defined after inverting groups for VML
|
13305
|
+
if (options.clip !== false && !series.sharedClipKey && !hasRendered) {
|
13306
|
+
group.clip(chart.clipRect);
|
13307
|
+
if (this.trackerGroup) {
|
13308
|
+
this.trackerGroup.clip(chart.clipRect);
|
12960
13309
|
}
|
12961
13310
|
}
|
12962
|
-
|
12963
13311
|
|
12964
|
-
//
|
13312
|
+
// Run the animation
|
12965
13313
|
if (doAnimation) {
|
12966
13314
|
series.animate();
|
13315
|
+
} else if (!hasRendered) {
|
13316
|
+
series.afterAnimate();
|
12967
13317
|
}
|
12968
13318
|
|
12969
|
-
// finish the individual clipRect
|
12970
|
-
setTimeout(function () {
|
12971
|
-
clipRect.isAnimating = false;
|
12972
|
-
group = series.group; // can be destroyed during the timeout
|
12973
|
-
if (group && clipRect !== chart.clipRect && clipRect.renderer) {
|
12974
|
-
if (doClip) {
|
12975
|
-
group.clip((series.clipRect = chart.clipRect));
|
12976
|
-
}
|
12977
|
-
clipRect.destroy();
|
12978
|
-
}
|
12979
|
-
}, duration);
|
12980
|
-
|
12981
13319
|
series.isDirty = series.isDirtyData = false; // means data is in accordance with what you see
|
12982
13320
|
// (See #322) series.isDirty = series.isDirtyData = false; // means data is in accordance with what you see
|
12983
13321
|
series.hasRendered = true;
|
12984
13322
|
},
|
12985
|
-
|
13323
|
+
|
12986
13324
|
/**
|
12987
13325
|
* Redraw the series after an update in the axes.
|
12988
13326
|
*/
|
@@ -13060,6 +13398,7 @@ Series.prototype = {
|
|
13060
13398
|
seriesGroup = series.group,
|
13061
13399
|
seriesTracker = series.tracker,
|
13062
13400
|
dataLabelsGroup = series.dataLabelsGroup,
|
13401
|
+
markerGroup = series.markerGroup,
|
13063
13402
|
showOrHide,
|
13064
13403
|
i,
|
13065
13404
|
points = series.points,
|
@@ -13075,6 +13414,9 @@ Series.prototype = {
|
|
13075
13414
|
if (seriesGroup) { // pies don't have one
|
13076
13415
|
seriesGroup[showOrHide]();
|
13077
13416
|
}
|
13417
|
+
if (markerGroup) {
|
13418
|
+
markerGroup[showOrHide]();
|
13419
|
+
}
|
13078
13420
|
|
13079
13421
|
// show or hide trackers
|
13080
13422
|
if (seriesTracker) {
|
@@ -13153,33 +13495,6 @@ Series.prototype = {
|
|
13153
13495
|
fireEvent(series, selected ? 'select' : 'unselect');
|
13154
13496
|
},
|
13155
13497
|
|
13156
|
-
/**
|
13157
|
-
* Create a group that holds the tracking object or objects. This allows for
|
13158
|
-
* individual clipping and placement of each series tracker.
|
13159
|
-
*/
|
13160
|
-
drawTrackerGroup: function () {
|
13161
|
-
var trackerGroup = this.trackerGroup,
|
13162
|
-
chart = this.chart;
|
13163
|
-
|
13164
|
-
if (this.isCartesian) {
|
13165
|
-
|
13166
|
-
// Generate it on first call
|
13167
|
-
if (!trackerGroup) {
|
13168
|
-
this.trackerGroup = trackerGroup = chart.renderer.g()
|
13169
|
-
.attr({
|
13170
|
-
zIndex: this.options.zIndex || 1
|
13171
|
-
})
|
13172
|
-
.add(chart.trackerGroup);
|
13173
|
-
|
13174
|
-
}
|
13175
|
-
// Place it on first and subsequent (redraw) calls
|
13176
|
-
trackerGroup.translate(this.xAxis.left, this.yAxis.top);
|
13177
|
-
|
13178
|
-
}
|
13179
|
-
|
13180
|
-
return trackerGroup;
|
13181
|
-
},
|
13182
|
-
|
13183
13498
|
/**
|
13184
13499
|
* Draw the tracker object that sits above all data labels and markers to
|
13185
13500
|
* track mouse events on the graph or points. For the line type charts
|
@@ -13199,7 +13514,7 @@ Series.prototype = {
|
|
13199
13514
|
cursor = options.cursor,
|
13200
13515
|
css = cursor && { cursor: cursor },
|
13201
13516
|
singlePoints = series.singlePoints,
|
13202
|
-
trackerGroup =
|
13517
|
+
trackerGroup = this.isCartesian && this.plotGroup('trackerGroup', null, VISIBLE, options.zIndex || 1, chart.trackerGroup),
|
13203
13518
|
singlePoint,
|
13204
13519
|
i;
|
13205
13520
|
|
@@ -13293,13 +13608,12 @@ var AreaSeries = extendClass(Series, {
|
|
13293
13608
|
areaSegmentPath = [].concat(segmentPath), // work on a copy for the area path
|
13294
13609
|
i,
|
13295
13610
|
options = this.options,
|
13296
|
-
segLength = segmentPath.length
|
13297
|
-
translatedThreshold = this.yAxis.getThreshold(options.threshold);
|
13611
|
+
segLength = segmentPath.length;
|
13298
13612
|
|
13299
13613
|
if (segLength === 3) { // for animation from 1 to two points
|
13300
13614
|
areaSegmentPath.push(L, segmentPath[1], segmentPath[2]);
|
13301
13615
|
}
|
13302
|
-
if (options.stacking && this.
|
13616
|
+
if (options.stacking && !this.closedStacks) {
|
13303
13617
|
|
13304
13618
|
// Follow stack back. Todo: implement areaspline. A general solution could be to
|
13305
13619
|
// reverse the entire graphPath of the previous series, though may be hard with
|
@@ -13315,20 +13629,29 @@ var AreaSeries = extendClass(Series, {
|
|
13315
13629
|
}
|
13316
13630
|
|
13317
13631
|
} else { // follow zero line back
|
13318
|
-
|
13319
|
-
L,
|
13320
|
-
segment[segment.length - 1].plotX,
|
13321
|
-
translatedThreshold,
|
13322
|
-
L,
|
13323
|
-
segment[0].plotX,
|
13324
|
-
translatedThreshold
|
13325
|
-
);
|
13632
|
+
this.closeSegment(areaSegmentPath, segment);
|
13326
13633
|
}
|
13327
13634
|
this.areaPath = this.areaPath.concat(areaSegmentPath);
|
13328
13635
|
|
13329
13636
|
return segmentPath;
|
13330
13637
|
},
|
13331
13638
|
|
13639
|
+
/**
|
13640
|
+
* Extendable method to close the segment path of an area. This is overridden in polar
|
13641
|
+
* charts.
|
13642
|
+
*/
|
13643
|
+
closeSegment: function (path, segment) {
|
13644
|
+
var translatedThreshold = this.yAxis.getThreshold(this.options.threshold);
|
13645
|
+
path.push(
|
13646
|
+
L,
|
13647
|
+
segment[segment.length - 1].plotX,
|
13648
|
+
translatedThreshold,
|
13649
|
+
L,
|
13650
|
+
segment[0].plotX,
|
13651
|
+
translatedThreshold
|
13652
|
+
);
|
13653
|
+
},
|
13654
|
+
|
13332
13655
|
/**
|
13333
13656
|
* Draw the graph and the underlying area. This method calls the Series base
|
13334
13657
|
* function and adds the area. The areaPath is calculated in the getSegmentPath
|
@@ -13357,7 +13680,8 @@ var AreaSeries = extendClass(Series, {
|
|
13357
13680
|
fill: pick(
|
13358
13681
|
options.fillColor,
|
13359
13682
|
Color(this.color).setOpacity(options.fillOpacity || 0.75).get()
|
13360
|
-
)
|
13683
|
+
),
|
13684
|
+
zIndex: 0 // #1069
|
13361
13685
|
}).add(this.group);
|
13362
13686
|
}
|
13363
13687
|
},
|
@@ -13395,7 +13719,7 @@ var SplineSeries = extendClass(Series, {
|
|
13395
13719
|
type: 'spline',
|
13396
13720
|
|
13397
13721
|
/**
|
13398
|
-
*
|
13722
|
+
* Get the spline segment from a given point's previous neighbour to the given point
|
13399
13723
|
*/
|
13400
13724
|
getPointSpline: function (segment, point, i) {
|
13401
13725
|
var smoothing = 1.5, // 1 means control points midway between points, 2 means 1/3 from the point, 3 is 1/4 etc
|
@@ -13411,7 +13735,8 @@ var SplineSeries = extendClass(Series, {
|
|
13411
13735
|
ret;
|
13412
13736
|
|
13413
13737
|
// find control points
|
13414
|
-
if (
|
13738
|
+
if (lastPoint && nextPoint) {
|
13739
|
+
|
13415
13740
|
var lastX = lastPoint.plotX,
|
13416
13741
|
lastY = lastPoint.plotY,
|
13417
13742
|
nextX = nextPoint.plotX,
|
@@ -13452,6 +13777,40 @@ var SplineSeries = extendClass(Series, {
|
|
13452
13777
|
point.rightContY = rightContY;
|
13453
13778
|
|
13454
13779
|
}
|
13780
|
+
|
13781
|
+
// Visualize control points for debugging
|
13782
|
+
/*
|
13783
|
+
if (leftContX) {
|
13784
|
+
this.chart.renderer.circle(leftContX + this.chart.plotLeft, leftContY + this.chart.plotTop, 2)
|
13785
|
+
.attr({
|
13786
|
+
stroke: 'red',
|
13787
|
+
'stroke-width': 1,
|
13788
|
+
fill: 'none'
|
13789
|
+
})
|
13790
|
+
.add();
|
13791
|
+
this.chart.renderer.path(['M', leftContX + this.chart.plotLeft, leftContY + this.chart.plotTop,
|
13792
|
+
'L', plotX + this.chart.plotLeft, plotY + this.chart.plotTop])
|
13793
|
+
.attr({
|
13794
|
+
stroke: 'red',
|
13795
|
+
'stroke-width': 1
|
13796
|
+
})
|
13797
|
+
.add();
|
13798
|
+
this.chart.renderer.circle(rightContX + this.chart.plotLeft, rightContY + this.chart.plotTop, 2)
|
13799
|
+
.attr({
|
13800
|
+
stroke: 'green',
|
13801
|
+
'stroke-width': 1,
|
13802
|
+
fill: 'none'
|
13803
|
+
})
|
13804
|
+
.add();
|
13805
|
+
this.chart.renderer.path(['M', rightContX + this.chart.plotLeft, rightContY + this.chart.plotTop,
|
13806
|
+
'L', plotX + this.chart.plotLeft, plotY + this.chart.plotTop])
|
13807
|
+
.attr({
|
13808
|
+
stroke: 'green',
|
13809
|
+
'stroke-width': 1
|
13810
|
+
})
|
13811
|
+
.add();
|
13812
|
+
}
|
13813
|
+
// */
|
13455
13814
|
|
13456
13815
|
// moveTo or lineTo
|
13457
13816
|
if (!i) {
|
@@ -13484,9 +13843,11 @@ defaultPlotOptions.areaspline = merge(defaultPlotOptions.area);
|
|
13484
13843
|
var areaProto = AreaSeries.prototype,
|
13485
13844
|
AreaSplineSeries = extendClass(SplineSeries, {
|
13486
13845
|
type: 'areaspline',
|
13846
|
+
closedStacks: true, // instead of following the previous graph back, follow the threshold back
|
13487
13847
|
|
13488
13848
|
// Mix in methods from the area series
|
13489
13849
|
getSegmentPath: areaProto.getSegmentPath,
|
13850
|
+
closeSegment: areaProto.closeSegment,
|
13490
13851
|
drawGraph: areaProto.drawGraph
|
13491
13852
|
});
|
13492
13853
|
seriesTypes.areaspline = AreaSplineSeries;
|
@@ -13500,6 +13861,7 @@ defaultPlotOptions.column = merge(defaultSeriesOptions, {
|
|
13500
13861
|
borderRadius: 0,
|
13501
13862
|
//colorByPoint: undefined,
|
13502
13863
|
groupPadding: 0.2,
|
13864
|
+
//grouping: true,
|
13503
13865
|
marker: null, // point options are specified in the base options
|
13504
13866
|
pointPadding: 0.1,
|
13505
13867
|
//pointWidth: null,
|
@@ -13536,6 +13898,10 @@ var ColumnSeries = extendClass(Series, {
|
|
13536
13898
|
fill: 'color',
|
13537
13899
|
r: 'borderRadius'
|
13538
13900
|
},
|
13901
|
+
|
13902
|
+
/**
|
13903
|
+
* Initialize the series
|
13904
|
+
*/
|
13539
13905
|
init: function () {
|
13540
13906
|
Series.prototype.init.apply(this, arguments);
|
13541
13907
|
|
@@ -13574,21 +13940,27 @@ var ColumnSeries = extendClass(Series, {
|
|
13574
13940
|
// Get the total number of column type series.
|
13575
13941
|
// This is called on every series. Consider moving this logic to a
|
13576
13942
|
// chart.orderStacks() function and call it on init, addSeries and removeSeries
|
13577
|
-
|
13578
|
-
|
13579
|
-
|
13580
|
-
|
13581
|
-
|
13582
|
-
|
13583
|
-
|
13943
|
+
if (options.grouping === false) {
|
13944
|
+
columnCount = 1;
|
13945
|
+
|
13946
|
+
} else {
|
13947
|
+
each(chart.series, function (otherSeries) {
|
13948
|
+
var otherOptions = otherSeries.options;
|
13949
|
+
if (otherSeries.type === series.type && otherSeries.visible &&
|
13950
|
+
series.options.group === otherOptions.group) { // used in Stock charts navigator series
|
13951
|
+
if (otherOptions.stacking) {
|
13952
|
+
stackKey = otherSeries.stackKey;
|
13953
|
+
if (stackGroups[stackKey] === UNDEFINED) {
|
13954
|
+
stackGroups[stackKey] = columnCount++;
|
13955
|
+
}
|
13956
|
+
columnIndex = stackGroups[stackKey];
|
13957
|
+
} else if (otherOptions.grouping !== false) { // #1162
|
13958
|
+
columnIndex = columnCount++;
|
13584
13959
|
}
|
13585
|
-
columnIndex =
|
13586
|
-
} else {
|
13587
|
-
columnIndex = columnCount++;
|
13960
|
+
otherSeries.columnIndex = columnIndex;
|
13588
13961
|
}
|
13589
|
-
|
13590
|
-
|
13591
|
-
});
|
13962
|
+
});
|
13963
|
+
}
|
13592
13964
|
|
13593
13965
|
// calculate the width and position of each column based on
|
13594
13966
|
// the number of column series in the plot, the groupPadding
|
@@ -13664,8 +14036,7 @@ var ColumnSeries = extendClass(Series, {
|
|
13664
14036
|
|
13665
14037
|
},
|
13666
14038
|
|
13667
|
-
getSymbol:
|
13668
|
-
},
|
14039
|
+
getSymbol: noop,
|
13669
14040
|
|
13670
14041
|
/**
|
13671
14042
|
* Use a solid rectangle like the area series types
|
@@ -13676,7 +14047,7 @@ var ColumnSeries = extendClass(Series, {
|
|
13676
14047
|
/**
|
13677
14048
|
* Columns have no graph
|
13678
14049
|
*/
|
13679
|
-
drawGraph:
|
14050
|
+
drawGraph: noop,
|
13680
14051
|
|
13681
14052
|
/**
|
13682
14053
|
* Draw the columns. For bars, the series.group is rotated, so the same coordinates
|
@@ -13725,7 +14096,7 @@ var ColumnSeries = extendClass(Series, {
|
|
13725
14096
|
options = series.options,
|
13726
14097
|
cursor = options.cursor,
|
13727
14098
|
css = cursor && { cursor: cursor },
|
13728
|
-
trackerGroup = series.
|
14099
|
+
trackerGroup = series.isCartesian && series.plotGroup('trackerGroup', null, VISIBLE, options.zIndex || 1, chart.trackerGroup),
|
13729
14100
|
rel,
|
13730
14101
|
plotY,
|
13731
14102
|
validPlotY;
|
@@ -13923,7 +14294,7 @@ var ScatterSeries = extendClass(Series, {
|
|
13923
14294
|
|
13924
14295
|
// Add the event listeners, we need to do this only once
|
13925
14296
|
if (!series._hasTracking) {
|
13926
|
-
series.
|
14297
|
+
series.markerGroup
|
13927
14298
|
.attr({
|
13928
14299
|
isTracker: true
|
13929
14300
|
})
|
@@ -13942,7 +14313,6 @@ var ScatterSeries = extendClass(Series, {
|
|
13942
14313
|
} else {
|
13943
14314
|
series._hasTracking = true;
|
13944
14315
|
}
|
13945
|
-
|
13946
14316
|
}
|
13947
14317
|
});
|
13948
14318
|
seriesTypes.scatter = ScatterSeries;
|
@@ -14019,7 +14389,8 @@ var PiePoint = extendClass(Point, {
|
|
14019
14389
|
*/
|
14020
14390
|
setVisible: function (vis) {
|
14021
14391
|
var point = this,
|
14022
|
-
|
14392
|
+
series = point.series,
|
14393
|
+
chart = series.chart,
|
14023
14394
|
tracker = point.tracker,
|
14024
14395
|
dataLabel = point.dataLabel,
|
14025
14396
|
connector = point.connector,
|
@@ -14047,6 +14418,12 @@ var PiePoint = extendClass(Point, {
|
|
14047
14418
|
if (point.legendItem) {
|
14048
14419
|
chart.legend.colorizeItem(point, vis);
|
14049
14420
|
}
|
14421
|
+
|
14422
|
+
// Handle ignore hidden slices
|
14423
|
+
if (!series.isDirty && series.options.ignoreHiddenPoint) {
|
14424
|
+
series.isDirty = true;
|
14425
|
+
chart.redraw();
|
14426
|
+
}
|
14050
14427
|
},
|
14051
14428
|
|
14052
14429
|
/**
|
@@ -14200,7 +14577,8 @@ var PieSeries = {
|
|
14200
14577
|
fraction,
|
14201
14578
|
radiusX, // the x component of the radius vector for a given point
|
14202
14579
|
radiusY,
|
14203
|
-
labelDistance = options.dataLabels.distance
|
14580
|
+
labelDistance = options.dataLabels.distance,
|
14581
|
+
ignoreHiddenPoint = options.ignoreHiddenPoint;
|
14204
14582
|
|
14205
14583
|
// get positions - either an integer or a percentage string must be given
|
14206
14584
|
series.center = positions = series.getCenter();
|
@@ -14217,14 +14595,16 @@ var PieSeries = {
|
|
14217
14595
|
|
14218
14596
|
// get the total sum
|
14219
14597
|
each(points, function (point) {
|
14220
|
-
total += point.y;
|
14598
|
+
total += (ignoreHiddenPoint && !point.visible) ? 0 : point.y;
|
14221
14599
|
});
|
14222
14600
|
|
14223
14601
|
each(points, function (point) {
|
14224
14602
|
// set start and end angle
|
14225
14603
|
fraction = total ? point.y / total : 0;
|
14226
14604
|
start = mathRound(cumulative * circ * precision) / precision;
|
14227
|
-
|
14605
|
+
if (!ignoreHiddenPoint || point.visible) {
|
14606
|
+
cumulative += fraction;
|
14607
|
+
}
|
14228
14608
|
end = mathRound(cumulative * circ * precision) / precision;
|
14229
14609
|
|
14230
14610
|
// set the shape
|
@@ -14405,7 +14785,7 @@ var PieSeries = {
|
|
14405
14785
|
j;
|
14406
14786
|
|
14407
14787
|
// get out if not enabled
|
14408
|
-
if (!options.enabled) {
|
14788
|
+
if (!options.enabled && !series._hasPointLabels) {
|
14409
14789
|
return;
|
14410
14790
|
}
|
14411
14791
|
|
@@ -14646,6 +15026,7 @@ extend(Highcharts, {
|
|
14646
15026
|
Chart: Chart,
|
14647
15027
|
Color: Color,
|
14648
15028
|
Legend: Legend,
|
15029
|
+
MouseTracker: MouseTracker,
|
14649
15030
|
Point: Point,
|
14650
15031
|
Tick: Tick,
|
14651
15032
|
Tooltip: Tooltip,
|
@@ -14675,7 +15056,11 @@ extend(Highcharts, {
|
|
14675
15056
|
splat: splat,
|
14676
15057
|
extendClass: extendClass,
|
14677
15058
|
pInt: pInt,
|
15059
|
+
wrap: wrap,
|
15060
|
+
svg: hasSVG,
|
15061
|
+
canvas: useCanVG,
|
15062
|
+
vml: !hasSVG && !useCanVG,
|
14678
15063
|
product: 'Highcharts',
|
14679
|
-
version: '2.2
|
15064
|
+
version: '2.3.2'
|
14680
15065
|
});
|
14681
15066
|
}());
|