highcharts-js-rails 0.1.9 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
}());
|