highcharts-rails 3.0.3 → 3.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,284 +1,12 @@
1
- /**
2
- * @license
3
- * Highcharts funnel module, Beta
4
- *
5
- * (c) 2010-2012 Torstein Hønsi
6
- *
7
- * License: www.highcharts.com/license
8
- */
9
-
10
- /*global Highcharts */
11
- (function (Highcharts) {
12
-
13
- 'use strict';
14
-
15
- // create shortcuts
16
- var defaultOptions = Highcharts.getOptions(),
17
- defaultPlotOptions = defaultOptions.plotOptions,
18
- seriesTypes = Highcharts.seriesTypes,
19
- merge = Highcharts.merge,
20
- noop = function () {},
21
- each = Highcharts.each;
22
-
23
- // set default options
24
- defaultPlotOptions.funnel = merge(defaultPlotOptions.pie, {
25
- center: ['50%', '50%'],
26
- width: '90%',
27
- neckWidth: '30%',
28
- height: '100%',
29
- neckHeight: '25%',
30
-
31
- dataLabels: {
32
- //position: 'right',
33
- connectorWidth: 1,
34
- connectorColor: '#606060'
35
- },
36
- size: true, // to avoid adapting to data label size in Pie.drawDataLabels
37
- states: {
38
- select: {
39
- color: '#C0C0C0',
40
- borderColor: '#000000',
41
- shadow: false
42
- }
43
- }
44
- });
45
-
46
-
47
- seriesTypes.funnel = Highcharts.extendClass(seriesTypes.pie, {
48
-
49
- type: 'funnel',
50
- animate: noop,
51
-
52
- /**
53
- * Overrides the pie translate method
54
- */
55
- translate: function () {
56
-
57
- var
58
- // Get positions - either an integer or a percentage string must be given
59
- getLength = function (length, relativeTo) {
60
- return (/%$/).test(length) ?
61
- relativeTo * parseInt(length, 10) / 100 :
62
- parseInt(length, 10);
63
- },
64
-
65
- sum = 0,
66
- series = this,
67
- chart = series.chart,
68
- plotWidth = chart.plotWidth,
69
- plotHeight = chart.plotHeight,
70
- cumulative = 0, // start at top
71
- options = series.options,
72
- center = options.center,
73
- centerX = getLength(center[0], plotWidth),
74
- centerY = getLength(center[0], plotHeight),
75
- width = getLength(options.width, plotWidth),
76
- tempWidth,
77
- getWidthAt,
78
- height = getLength(options.height, plotHeight),
79
- neckWidth = getLength(options.neckWidth, plotWidth),
80
- neckHeight = getLength(options.neckHeight, plotHeight),
81
- neckY = height - neckHeight,
82
- data = series.data,
83
- path,
84
- fraction,
85
- half = options.dataLabels.position === 'left' ? 1 : 0,
86
-
87
- x1,
88
- y1,
89
- x2,
90
- x3,
91
- y3,
92
- x4,
93
- y5;
94
-
95
- // Return the width at a specific y coordinate
96
- series.getWidthAt = getWidthAt = function (y) {
97
- return y > height - neckHeight || height === neckHeight ?
98
- neckWidth :
99
- neckWidth + (width - neckWidth) * ((height - neckHeight - y) / (height - neckHeight));
100
- };
101
- series.getX = function (y, half) {
102
- return centerX + (half ? -1 : 1) * ((getWidthAt(y) / 2) + options.dataLabels.distance);
103
- };
104
-
105
- // Expose
106
- series.center = [centerX, centerY, height];
107
- series.centerX = centerX;
108
-
109
- /*
110
- * Individual point coordinate naming:
111
- *
112
- * x1,y1 _________________ x2,y1
113
- * \ /
114
- * \ /
115
- * \ /
116
- * \ /
117
- * \ /
118
- * x3,y3 _________ x4,y3
119
- *
120
- * Additional for the base of the neck:
121
- *
122
- * | |
123
- * | |
124
- * | |
125
- * x3,y5 _________ x4,y5
126
- */
127
-
128
-
129
-
130
-
131
- // get the total sum
132
- each(data, function (point) {
133
- sum += point.y;
134
- });
135
-
136
- each(data, function (point) {
137
- // set start and end positions
138
- y5 = null;
139
- fraction = sum ? point.y / sum : 0;
140
- y1 = centerY - height / 2 + cumulative * height;
141
- y3 = y1 + fraction * height;
142
- //tempWidth = neckWidth + (width - neckWidth) * ((height - neckHeight - y1) / (height - neckHeight));
143
- tempWidth = getWidthAt(y1);
144
- x1 = centerX - tempWidth / 2;
145
- x2 = x1 + tempWidth;
146
- tempWidth = getWidthAt(y3);
147
- x3 = centerX - tempWidth / 2;
148
- x4 = x3 + tempWidth;
149
-
150
- // the entire point is within the neck
151
- if (y1 > neckY) {
152
- x1 = x3 = centerX - neckWidth / 2;
153
- x2 = x4 = centerX + neckWidth / 2;
154
-
155
- // the base of the neck
156
- } else if (y3 > neckY) {
157
- y5 = y3;
158
-
159
- tempWidth = getWidthAt(neckY);
160
- x3 = centerX - tempWidth / 2;
161
- x4 = x3 + tempWidth;
162
-
163
- y3 = neckY;
164
- }
165
-
166
- // save the path
167
- path = [
168
- 'M',
169
- x1, y1,
170
- 'L',
171
- x2, y1,
172
- x4, y3
173
- ];
174
- if (y5) {
175
- path.push(x4, y5, x3, y5);
176
- }
177
- path.push(x3, y3, 'Z');
178
-
179
- // prepare for using shared dr
180
- point.shapeType = 'path';
181
- point.shapeArgs = { d: path };
182
-
183
-
184
- // for tooltips and data labels
185
- point.percentage = fraction * 100;
186
- point.plotX = centerX;
187
- point.plotY = (y1 + (y5 || y3)) / 2;
188
-
189
- // Placement of tooltips and data labels
190
- point.tooltipPos = [
191
- centerX,
192
- point.plotY
193
- ];
194
-
195
- // Slice is a noop on funnel points
196
- point.slice = noop;
197
-
198
- // Mimicking pie data label placement logic
199
- point.half = half;
200
-
201
- cumulative += fraction;
202
- });
203
-
204
-
205
- series.setTooltipPoints();
206
- },
207
- /**
208
- * Draw a single point (wedge)
209
- * @param {Object} point The point object
210
- * @param {Object} color The color of the point
211
- * @param {Number} brightness The brightness relative to the color
212
- */
213
- drawPoints: function () {
214
- var series = this,
215
- options = series.options,
216
- chart = series.chart,
217
- renderer = chart.renderer;
218
-
219
- each(series.data, function (point) {
220
-
221
- var graphic = point.graphic,
222
- shapeArgs = point.shapeArgs;
223
-
224
- if (!graphic) { // Create the shapes
225
- point.graphic = renderer.path(shapeArgs).
226
- attr({
227
- fill: point.color,
228
- stroke: options.borderColor,
229
- 'stroke-width': options.borderWidth
230
- }).
231
- add(series.group);
232
-
233
- } else { // Update the shapes
234
- graphic.animate(shapeArgs);
235
- }
236
- });
237
- },
238
-
239
- /**
240
- * Extend the pie data label method
241
- */
242
- drawDataLabels: function () {
243
- var data = this.data,
244
- labelDistance = this.options.dataLabels.distance,
245
- leftSide,
246
- sign,
247
- point,
248
- i = data.length,
249
- x,
250
- y;
251
-
252
- // In the original pie label anticollision logic, the slots are distributed
253
- // from one labelDistance above to one labelDistance below the pie. In funnels
254
- // we don't want this.
255
- this.center[2] -= 2 * labelDistance;
256
-
257
- // Set the label position array for each point.
258
- while (i--) {
259
- point = data[i];
260
- leftSide = point.half;
261
- sign = leftSide ? 1 : -1;
262
- y = point.plotY;
263
- x = this.getX(y, leftSide);
264
-
265
- // set the anchor point for data labels
266
- point.labelPos = [
267
- 0, // first break of connector
268
- y, // a/a
269
- x + (labelDistance - 5) * sign, // second break, right outside point shape
270
- y, // a/a
271
- x + labelDistance * sign, // landing point for connector
272
- y, // a/a
273
- leftSide ? 'right' : 'left', // alignment
274
- 0 // center angle
275
- ];
276
- }
277
-
278
- seriesTypes.pie.prototype.drawDataLabels.call(this);
279
- }
280
-
281
- });
282
-
283
-
284
- }(Highcharts));
1
+ /*
2
+
3
+ Highcharts funnel module, Beta
4
+
5
+ (c) 2010-2012 Torstein Hønsi
6
+
7
+ License: www.highcharts.com/license
8
+ */
9
+ (function(d){var u=d.getOptions().plotOptions,p=d.seriesTypes,D=d.merge,B=function(){},z=d.each;u.funnel=D(u.pie,{center:["50%","50%"],width:"90%",neckWidth:"30%",height:"100%",neckHeight:"25%",dataLabels:{connectorWidth:1,connectorColor:"#606060"},size:!0,states:{select:{color:"#C0C0C0",borderColor:"#000000",shadow:!1}}});p.funnel=d.extendClass(p.pie,{type:"funnel",animate:B,translate:function(){var a=function(k,a){return/%$/.test(k)?a*parseInt(k,10)/100:parseInt(k,10)},g=0,e=this.chart,f=e.plotWidth,
10
+ e=e.plotHeight,h=0,c=this.options,C=c.center,b=a(C[0],f),d=a(C[0],e),p=a(c.width,f),i,q,j=a(c.height,e),r=a(c.neckWidth,f),s=a(c.neckHeight,e),v=j-s,a=this.data,w,x,u=c.dataLabels.position==="left"?1:0,y,m,A,n,l,t,o;this.getWidthAt=q=function(k){return k>j-s||j===s?r:r+(p-r)*((j-s-k)/(j-s))};this.getX=function(k,a){return b+(a?-1:1)*(q(k)/2+c.dataLabels.distance)};this.center=[b,d,j];this.centerX=b;z(a,function(a){g+=a.y});z(a,function(a){o=null;x=g?a.y/g:0;m=d-j/2+h*j;l=m+x*j;i=q(m);y=b-i/2;A=y+
11
+ i;i=q(l);n=b-i/2;t=n+i;m>v?(y=n=b-r/2,A=t=b+r/2):l>v&&(o=l,i=q(v),n=b-i/2,t=n+i,l=v);w=["M",y,m,"L",A,m,t,l];o&&w.push(t,o,n,o);w.push(n,l,"Z");a.shapeType="path";a.shapeArgs={d:w};a.percentage=x*100;a.plotX=b;a.plotY=(m+(o||l))/2;a.tooltipPos=[b,a.plotY];a.slice=B;a.half=u;h+=x});this.setTooltipPoints()},drawPoints:function(){var a=this,g=a.options,e=a.chart.renderer;z(a.data,function(f){var h=f.graphic,c=f.shapeArgs;h?h.animate(c):f.graphic=e.path(c).attr({fill:f.color,stroke:g.borderColor,"stroke-width":g.borderWidth}).add(a.group)})},
12
+ drawDataLabels:function(){var a=this.data,g=this.options.dataLabels.distance,e,f,h,c=a.length,d,b;for(this.center[2]-=2*g;c--;)h=a[c],f=(e=h.half)?1:-1,b=h.plotY,d=this.getX(b,e),h.labelPos=[0,b,d+(g-5)*f,b,d+g*f,b,e?"right":"left",0];p.pie.prototype.drawDataLabels.call(this)}})})(Highcharts);
@@ -1,57 +1 @@
1
- (function (Highcharts) {
2
- var seriesTypes = Highcharts.seriesTypes,
3
- each = Highcharts.each;
4
-
5
- seriesTypes.heatmap = Highcharts.extendClass(seriesTypes.map, {
6
- colorKey: 'z',
7
- pointArrayMap: ['y', 'z'],
8
- translate: function () {
9
- var series = this,
10
- options = series.options,
11
- dataMin = Number.MAX_VALUE,
12
- dataMax = Number.MIN_VALUE,
13
- opacity,
14
- minOpacity = options.minOpacity,
15
- path,
16
- color;
17
-
18
-
19
- series.generatePoints();
20
-
21
- each(series.data, function (point) {
22
- var x = point.x,
23
- y = point.y,
24
- value = point.z,
25
- xPad = (series.options.colsize || 1) / 2,
26
- yPad = (series.options.rowsize || 1) / 2;
27
-
28
- point.path = [
29
- 'M', x - xPad, y - yPad,
30
- 'L', x + xPad, y - yPad,
31
- 'L', x + xPad, y + yPad,
32
- 'L', x - xPad, y + yPad,
33
- 'Z'
34
- ];
35
-
36
- point.shapeType = 'path';
37
- point.shapeArgs = {
38
- d: series.translatePath(point.path)
39
- };
40
-
41
- if (typeof value === 'number') {
42
- if (value > dataMax) {
43
- dataMax = value;
44
- } else if (value < dataMin) {
45
- dataMin = value;
46
- }
47
- }
48
- });
49
-
50
- series.translateColors(dataMin, dataMax);
51
- },
52
-
53
- getBox: function () {}
54
-
55
- });
56
-
57
- }(Highcharts));
1
+ (function(b){var k=b.seriesTypes,l=b.each;k.heatmap=b.extendClass(k.map,{colorKey:"z",pointArrayMap:["y","z"],translate:function(){var c=this,b=c.options,i=Number.MAX_VALUE,j=Number.MIN_VALUE;c.generatePoints();l(c.data,function(a){var e=a.x,f=a.y,d=a.z,g=(b.colsize||1)/2,h=(b.rowsize||1)/2;a.path=["M",e-g,f-h,"L",e+g,f-h,"L",e+g,f+h,"L",e-g,f+h,"Z"];a.shapeType="path";a.shapeArgs={d:c.translatePath(a.path)};typeof d==="number"&&(d>j?j=d:d<i&&(i=d))});c.translateColors(i,j)},getBox:function(){}})})(Highcharts);
@@ -1,576 +1,21 @@
1
- /**
2
- * @license Map plugin v0.1 for Highcharts
3
- *
4
- * (c) 2011-2013 Torstein Hønsi
5
- *
6
- * License: www.highcharts.com/license
7
- */
8
-
9
- /*
10
- * See www.highcharts.com/studies/world-map.htm for use case.
11
- *
12
- * To do:
13
- * - Optimize long variable names and alias adapter methods and Highcharts namespace variables
14
- * - Zoom and pan GUI
15
- */
16
- (function (Highcharts) {
17
- var UNDEFINED,
18
- Axis = Highcharts.Axis,
19
- each = Highcharts.each,
20
- extend = Highcharts.extend,
21
- merge = Highcharts.merge,
22
- pick = Highcharts.pick,
23
- numberFormat = Highcharts.numberFormat,
24
- plotOptions = Highcharts.getOptions().plotOptions,
25
- Color = Highcharts.Color,
26
- noop = function () {};
27
-
28
- /**
29
- * Utility for reading SVG paths directly.
30
- *
31
- * @todo This is moved to the Data plugin. Make sure it is deleted here.
32
- */
33
- Highcharts.pathToArray = function (path) {
34
- var i;
35
-
36
- // Move letters apart
37
- path = path.replace(/([A-Za-z])/g, ' $1 ');
38
- // Trim
39
- path = path.replace(/^\s*/, "").replace(/\s*$/, "");
40
-
41
- // Split on spaces and commas
42
- path = path.split(/[ ,]+/);
43
-
44
- for (i = 0; i < path.length; i++) {
45
- if (!/[a-zA-Z]/.test(path[i])) {
46
- path[i] = parseFloat(path[i]);
47
- }
48
- }
49
- return path;
50
- };
51
-
52
- /**
53
- * Extend the Axis object with methods specific to maps
54
- */
55
- Highcharts.wrap(Axis.prototype, 'init', function (proceed, chart, userOptions) {
56
-
57
- if (chart.options.chart.type === 'map') {
58
- extend(this, {
59
-
60
- /**
61
- * Override to use the extreme coordinates from the SVG shape, not the
62
- * data values
63
- */
64
- getSeriesExtremes: function () {
65
- var isXAxis = this.isXAxis,
66
- dataMin = Number.MAX_VALUE,
67
- dataMax = Number.MIN_VALUE;
68
- each(this.series, function (series) {
69
- dataMin = Math.min(dataMin, series[isXAxis ? 'minX' : 'minY']);
70
- dataMax = Math.max(dataMax, series[isXAxis ? 'maxX' : 'maxY']);
71
- });
72
- this.dataMin = dataMin;
73
- this.dataMax = dataMax;
74
- },
75
-
76
- /**
77
- * Override axis translation to make sure the aspect ratio is always kept
78
- */
79
- setAxisTranslation: function () {
80
- var chart = this.chart,
81
- mapRatio,
82
- plotRatio = chart.plotWidth / chart.plotHeight,
83
- isXAxis = this.isXAxis,
84
- adjustedAxisLength,
85
- xAxis = chart.xAxis[0],
86
- padAxis;
87
-
88
- // Run the parent method
89
- Axis.prototype.setAxisTranslation.call(this);
90
-
91
- // On Y axis, handle both
92
- if (!isXAxis && xAxis.transA !== UNDEFINED) {
93
-
94
- // Use the same translation for both axes
95
- this.transA = xAxis.transA = Math.min(this.transA, xAxis.transA);
96
-
97
- mapRatio = (xAxis.max - xAxis.min) / (this.max - this.min);
98
-
99
- // What axis to pad to put the map in the middle
100
- padAxis = mapRatio > plotRatio ? this : xAxis;
101
-
102
- // Pad it
103
- adjustedAxisLength = (padAxis.max - padAxis.min) * padAxis.transA;
104
- padAxis.minPixelPadding = (padAxis.len - adjustedAxisLength) / 2;
105
- }
106
-
107
- }
108
- });
109
- }
110
-
111
- return proceed.call(this, chart, userOptions);
112
- });
113
-
114
- /**
115
- * Extend the default options with map options
116
- */
117
- plotOptions.map = merge(
118
- plotOptions.scatter,
119
- {
120
- animation: false, // makes the complex shapes slow
121
- minOpacity: 0.2,
122
- nullColor: '#F8F8F8',
123
- borderColor: 'silver',
124
- borderWidth: 1,
125
- marker: null,
126
- stickyTracking: false,
127
- tooltip: {
128
- followPointer: true,
129
- headerFormat: '<span style="font-size:10px">{point.key}</span><br/>',
130
- pointFormat: '{series.name}: {point.y}<br/>'
131
- }
132
- }
133
- );
134
-
135
- /**
136
- * Add the series type
137
- */
138
- Highcharts.seriesTypes.map = Highcharts.extendClass(Highcharts.seriesTypes.scatter, {
139
- type: 'map',
140
- pointAttrToOptions: { // mapping between SVG attributes and the corresponding options
141
- stroke: 'borderColor',
142
- 'stroke-width': 'borderWidth',
143
- fill: 'color'
144
- },
145
- colorKey: 'y',
146
- trackerGroups: ['group', 'markerGroup'],
147
- getSymbol: noop,
148
- getExtremesFromAll: true,
149
- init: function (chart) {
150
- var series = this,
151
- valueDecimals = chart.options.legend.valueDecimals,
152
- legendItems = [],
153
- name,
154
- from,
155
- to,
156
- fromLabel,
157
- toLabel,
158
- colorRange,
159
- gradientColor,
160
- grad,
161
- tmpLabel,
162
- horizontal = chart.options.legend.layout === 'horizontal';
163
-
164
-
165
- Highcharts.Series.prototype.init.apply(this, arguments);
166
- colorRange = series.options.colorRange;
167
-
168
- if (series.options.valueRanges) {
169
- each(series.options.valueRanges, function (range) {
170
- from = range.from;
171
- to = range.to;
172
-
173
- // Assemble the default name. This can be overridden by legend.options.labelFormatter
174
- name = '';
175
- if (from === UNDEFINED) {
176
- name = '< ';
177
- } else if (to === UNDEFINED) {
178
- name = '> ';
179
- }
180
- if (from !== UNDEFINED) {
181
- name += numberFormat(from, valueDecimals);
182
- }
183
- if (from !== UNDEFINED && to !== UNDEFINED) {
184
- name += ' - ';
185
- }
186
- if (to !== UNDEFINED) {
187
- name += numberFormat(to, valueDecimals);
188
- }
189
-
190
- // Add a mock object to the legend items
191
- legendItems.push(Highcharts.extend({
192
- chart: series.chart,
193
- name: name,
194
- options: {},
195
- drawLegendSymbol: Highcharts.seriesTypes.area.prototype.drawLegendSymbol,
196
- visible: true,
197
- setState: function () {},
198
- setVisible: function () {}
199
- }, range));
200
- });
201
- series.legendItems = legendItems;
202
-
203
- } else if (colorRange) {
204
-
205
- from = colorRange.from;
206
- to = colorRange.to;
207
- fromLabel = colorRange.fromLabel;
208
- toLabel = colorRange.toLabel;
209
-
210
- // Flips linearGradient variables and label text.
211
- grad = horizontal ? [0, 0, 1, 0] : [0, 1, 0, 0];
212
- if (!horizontal) {
213
- tmpLabel = fromLabel;
214
- fromLabel = toLabel;
215
- toLabel = tmpLabel;
216
- }
217
-
218
- // Creates color gradient.
219
- gradientColor = {
220
- linearGradient: { x1: grad[0], y1: grad[1], x2: grad[2], y2: grad[3] },
221
- stops:
222
- [
223
- [0, from],
224
- [1, to]
225
- ]
226
- };
227
-
228
- // Add a mock object to the legend items.
229
- legendItems = [{
230
- chart: series.chart,
231
- options: {},
232
- fromLabel: fromLabel,
233
- toLabel: toLabel,
234
- color: gradientColor,
235
- drawLegendSymbol: this.drawLegendSymbol,
236
- visible: true,
237
- setState: function () {},
238
- setVisible: function () {}
239
- }];
240
-
241
- series.legendItems = legendItems;
242
- }
243
- },
244
-
245
- /**
246
- * Gets the series' symbol in the legend and extended legend with more information.
247
- *
248
- * @param {Object} legend The legend object
249
- * @param {Object} item The series (this) or point
250
- */
251
- drawLegendSymbol: function (legend, item) {
252
-
253
- var spacing = legend.options.symbolPadding,
254
- padding = pick(legend.options.padding, 8),
255
- positionY,
256
- positionX,
257
- gradientSize = this.chart.renderer.fontMetrics(legend.options.itemStyle.fontSize).h,
258
- horizontal = legend.options.layout === 'horizontal',
259
- box1,
260
- box2,
261
- box3,
262
- rectangleLength = pick(legend.options.rectangleLength, 200);
263
-
264
- // Set local variables based on option.
265
- if (horizontal) {
266
- positionY = -(spacing / 2);
267
- positionX = 0;
268
- } else {
269
- positionY = -rectangleLength + legend.baseline - (spacing / 2);
270
- positionX = padding + gradientSize;
271
- }
272
-
273
- // Creates the from text.
274
- item.fromText = this.chart.renderer.text(
275
- item.fromLabel, // Text.
276
- positionX, // Lower left x.
277
- positionY // Lower left y.
278
- ).attr({
279
- zIndex: 2
280
- }).add(item.legendGroup);
281
- box1 = item.fromText.getBBox();
282
-
283
- // Creates legend symbol.
284
- // Ternary changes variables based on option.
285
- item.legendSymbol = this.chart.renderer.rect(
286
- horizontal ? box1.x + box1.width + spacing : box1.x - gradientSize - spacing, // Upper left x.
287
- box1.y, // Upper left y.
288
- horizontal ? rectangleLength : gradientSize, // Width.
289
- horizontal ? gradientSize : rectangleLength, // Height.
290
- 2 // Corner radius.
291
- ).attr({
292
- zIndex: 1
293
- }).add(item.legendGroup);
294
- box2 = item.legendSymbol.getBBox();
295
-
296
- // Creates the to text.
297
- // Vertical coordinate changed based on option.
298
- item.toText = this.chart.renderer.text(
299
- item.toLabel,
300
- box2.x + box2.width + spacing,
301
- horizontal ? positionY : box2.y + box2.height - spacing
302
- ).attr({
303
- zIndex: 2
304
- }).add(item.legendGroup);
305
- box3 = item.toText.getBBox();
306
-
307
- // Changes legend box settings based on option.
308
- if (horizontal) {
309
- legend.offsetWidth = box1.width + box2.width + box3.width + (spacing * 2) + padding;
310
- legend.itemY = gradientSize + padding;
311
- } else {
312
- legend.offsetWidth = Math.max(box1.width, box3.width) + (spacing) + box2.width + padding;
313
- legend.itemY = box2.height + padding;
314
- legend.itemX = spacing;
315
- }
316
- },
317
-
318
- /**
319
- * Get the bounding box of all paths in the map combined.
320
- */
321
- getBox: function () {
322
- var chart = this.chart,
323
- maxX = -Math.pow(2, 31),
324
- minX = Math.pow(2, 31) - 1,
325
- maxY = -Math.pow(2, 31),
326
- minY = Math.pow(2, 31) - 1,
327
- xyRatio,
328
- ratioCorrection,
329
- plotWidth = chart.plotWidth,
330
- plotHeight = chart.plotHeight,
331
- pad;
332
-
333
-
334
- // Find the bounding box
335
- each(this.options.data, function (point) {
336
- var path = point.path,
337
- i = path.length,
338
- even = false; // while loop reads from the end
339
-
340
- while (i--) {
341
- if (typeof path[i] === 'number') {
342
- if (even) { // even = x
343
- maxX = Math.max(maxX, path[i]);
344
- minX = Math.min(minX, path[i]);
345
- } else { // odd = Y
346
- maxY = Math.max(maxY, path[i]);
347
- minY = Math.min(minY, path[i]);
348
- }
349
- even = !even;
350
- }
351
- }
352
- });
353
- this.minY = minY;
354
- this.maxY = maxY;
355
- this.minX = minX;
356
- this.maxX = maxX;
357
-
358
- },
359
-
360
-
361
-
362
- /**
363
- * Translate the path so that it automatically fits into the plot area box
364
- * @param {Object} path
365
- */
366
- translatePath: function (path) {
367
-
368
- var series = this,
369
- chart = series.chart,
370
- even = false, // while loop reads from the end
371
- xAxis = series.xAxis,
372
- yAxis = series.yAxis;
373
-
374
- // Preserve the original
375
- path = [].concat(path);
376
-
377
- // Do the translation
378
- i = path.length;
379
- while (i--) {
380
- if (typeof path[i] === 'number') {
381
- if (even) { // even = x
382
- path[i] = Math.round(xAxis.translate(path[i]));
383
- } else { // odd = Y
384
- path[i] = Math.round(yAxis.len - yAxis.translate(path[i]));
385
- }
386
- even = !even;
387
- }
388
- }
389
- return path;
390
- },
391
-
392
- setData: function () {
393
- Highcharts.Series.prototype.setData.apply(this, arguments);
394
- this.getBox();
395
- },
396
-
397
- /**
398
- * Add the path option for data points. Find the max value for color calculation.
399
- */
400
- translate: function () {
401
- var series = this,
402
- options = series.options,
403
- dataMin = Number.MAX_VALUE,
404
- dataMax = Number.MIN_VALUE,
405
- opacity,
406
- minOpacity = options.minOpacity,
407
- path,
408
- color;
409
-
410
- series.generatePoints();
411
-
412
- each(series.data, function (point) {
413
-
414
- point.shapeType = 'path';
415
- point.shapeArgs = {
416
- d: series.translatePath(point.path)
417
- };
418
-
419
- // TODO: do point colors in drawPoints instead of point.init
420
- if (typeof point.y === 'number') {
421
- if (point.y > dataMax) {
422
- dataMax = point.y;
423
- } else if (point.y < dataMin) {
424
- dataMin = point.y;
425
- }
426
- }
427
- });
428
-
429
- series.translateColors(dataMin, dataMax);
430
- },
431
-
432
- /**
433
- * In choropleth maps, the color is a result of the value, so this needs translation tood
434
- */
435
- translateColors: function (dataMin, dataMax) {
436
-
437
- var seriesOptions = this.options,
438
- valueRanges = seriesOptions.valueRanges,
439
- colorRange = seriesOptions.colorRange,
440
- colorKey = this.colorKey;
441
-
442
- each(this.data, function (point) {
443
- var value = point[colorKey],
444
- rgba = [],
445
- range,
446
- from,
447
- to,
448
- i,
449
- pos;
450
-
451
- if (valueRanges) {
452
- i = valueRanges.length;
453
- while (i--) {
454
- range = valueRanges[i];
455
- from = range.from;
456
- to = range.to;
457
- if ((from === UNDEFINED || value >= from) && (to === UNDEFINED || value <= to)) {
458
- point.options.color = range.color;
459
- break;
460
- }
461
-
462
- }
463
- } else if (colorRange && value !== undefined) {
464
- from = Color(colorRange.from);
465
- to = Color(colorRange.to);
466
- pos = (dataMax - value) / (dataMax - dataMin);
467
- i = 4;
468
- while (i--) {
469
- rgba[i] = Math.round(
470
- to.rgba[i] + (from.rgba[i] - to.rgba[i]) * pos
471
- );
472
- }
473
- point.options.color = 'rgba(' + rgba.join(',') + ')';
474
- }
475
- });
476
- },
477
-
478
- drawGraph: noop,
479
-
480
- /**
481
- * We need the points' bounding boxes in order to draw the data labels, so
482
- * we skip it now and call if from drawPoints instead.
483
- */
484
- drawDataLabels: noop,
485
-
486
- /**
487
- * Use the drawPoints method of column, that is able to handle simple shapeArgs.
488
- * Extend it by assigning the tooltip position.
489
- */
490
- drawPoints: function () {
491
- var series = this,
492
- chart = series.chart,
493
- saturation,
494
- bBox,
495
- colorKey = series.colorKey;
496
-
497
- // Make points pass test in drawing
498
- each(series.data, function (point) {
499
- point.plotY = 1; // pass null test in column.drawPoints
500
- if (point[colorKey] === null) {
501
- point[colorKey] = 0;
502
- point.isNull = true;
503
- }
504
- });
505
-
506
- // Draw them
507
- Highcharts.seriesTypes.column.prototype.drawPoints.apply(series);
508
-
509
- each(series.data, function (point) {
510
-
511
- bBox = point.graphic.getBBox();
512
- // for tooltip
513
- point.tooltipPos = [
514
- bBox.x + bBox.width / 2,
515
- bBox.y + bBox.height / 2
516
- ];
517
- // for data labels
518
- point.plotX = point.tooltipPos[0];
519
- point.plotY = point.tooltipPos[1];
520
-
521
- // Reset escaped null points
522
- if (point.isNull) {
523
- point[colorKey] = null;
524
- }
525
- });
526
-
527
- // Now draw the data labels
528
- Highcharts.Series.prototype.drawDataLabels.call(series);
529
-
530
- }
531
- });
532
-
533
- /**
534
- * A wrapper for Chart with all the default values for a Map
535
- */
536
- Highcharts.Map = function (options, callback) {
537
-
538
- var hiddenAxis = {
539
- endOnTick: false,
540
- gridLineWidth: 0,
541
- labels: {
542
- enabled: false
543
- },
544
- lineWidth: 0,
545
- minPadding: 0,
546
- maxPadding: 0,
547
- startOnTick: false,
548
- tickWidth: 0,
549
- title: null
550
- };
551
-
552
- // Don't merge the data
553
- seriesOptions = options.series;
554
- options.series = null;
555
-
556
- options = merge({
557
- chart: {
558
- type: 'map'
559
- },
560
- xAxis: hiddenAxis,
561
- yAxis: merge(hiddenAxis, { reversed: true })
562
- },
563
- options, // user's options
564
-
565
- { // forced options
566
- chart: {
567
- inverted: false
568
- }
569
- });
570
-
571
- options.series = seriesOptions;
572
-
573
-
574
- return new Highcharts.Chart(options, callback);
575
- };
576
- }(Highcharts));
1
+ /*
2
+ Map plugin v0.1 for Highcharts
3
+
4
+ (c) 2011-2013 Torstein Hønsi
5
+
6
+ License: www.highcharts.com/license
7
+ */
8
+ (function(f){var s=f.Axis,t=f.Chart,k=f.each,q=f.extend,p=f.merge,n=f.pick,u=f.numberFormat,v=f.getOptions(),w=v.plotOptions,x=f.Color,r=function(){};v.mapNavigation={enabled:!1,buttonOptions:{align:"right",verticalAlign:"bottom",x:0,width:18,height:18,style:{fontSize:"15px",fontWeight:"bold",textAlign:"center"}},buttons:{zoomIn:{onclick:function(){this.mapZoom(0.5)},text:"+",y:-32},zoomOut:{onclick:function(){this.mapZoom(2)},text:"-",y:0}}};f.splitPath=function(a){var b,a=a.replace(/([A-Za-z])/g,
9
+ " $1 "),a=a.replace(/^\s*/,"").replace(/\s*$/,""),a=a.split(/[ ,]+/);for(b=0;b<a.length;b++)/[a-zA-Z]/.test(a[b])||(a[b]=parseFloat(a[b]));return a};f.maps={};f.wrap(s.prototype,"init",function(a,b,c){b.options.chart.type==="map"&&q(this,{getSeriesExtremes:function(){var d=this.isXAxis,a=Number.MAX_VALUE,b=Number.MIN_VALUE;k(this.series,function(c){a=Math.min(a,c[d?"minX":"minY"]);b=Math.max(b,c[d?"maxX":"maxY"])});this.dataMin=a;this.dataMax=b},setAxisTranslation:function(){var a=this.chart,b,c=
10
+ a.plotWidth/a.plotHeight;b=this.isXAxis;a=a.xAxis[0];s.prototype.setAxisTranslation.call(this);if(!b&&a.transA!==void 0)this.transA=a.transA=Math.min(this.transA,a.transA),b=(a.max-a.min)/(this.max-this.min),b=b>c?this:a,c=(b.max-b.min)*b.transA,b.minPixelPadding=(b.len-c)/2}});return a.call(this,b,c)});f.wrap(t.prototype,"render",function(a){a.call(this);this.renderMapNavigation()});q(t.prototype,{renderMapNavigation:function(){var a=this,b=this.options.mapNavigation,c=b.buttons,d,e,h,i=function(){this.handler.call(a)};
11
+ if(n(b.enabled,!0))for(d in c)if(c.hasOwnProperty(d))h=p(b.buttonOptions,c[d]),e=a.renderer.button(h.text,0,0,i).attr({width:h.width,height:h.height}).css(h.style).add(),e.handler=h.onclick,e.align(q(h,{width:e.width,height:e.height}),null,"spacingBox")},fitToBox:function(a,b){k([["x","width"],["y","height"]],function(c){var d=c[0],c=c[1];a[d]+a[c]>b[d]+b[c]&&(a[c]>b[c]?(a[c]=b[c],a[d]=b[d]):a[d]=b[d]+b[c]-a[c]);a[d]<b[d]&&(a[d]=b[d])});return a},mapZoom:function(a){var b=this.xAxis[0],c=b.max-b.min,
12
+ d=c*a,e=this.yAxis[0],h=e.max-e.min;a*=h;c=this.fitToBox({x:b.min+c/2-d/2,y:e.min+h/2-a/2,width:d,height:a},{x:b.dataMin,y:e.dataMin,width:b.dataMax-b.dataMin,height:e.dataMax-e.dataMin});b.setExtremes(c.x,c.x+c.width,!1);e.setExtremes(c.y,c.y+c.height,!1);this.redraw()}});w.map=p(w.scatter,{animation:!1,minOpacity:0.2,nullColor:"#F8F8F8",borderColor:"silver",borderWidth:1,marker:null,stickyTracking:!1,dataLabels:{verticalAlign:"middle"},tooltip:{followPointer:!0,headerFormat:'<span style="font-size:10px">{point.key}</span><br/>',
13
+ pointFormat:"{series.name}: {point.y}<br/>"}});f.seriesTypes.map=f.extendClass(f.seriesTypes.scatter,{type:"map",pointAttrToOptions:{stroke:"borderColor","stroke-width":"borderWidth",fill:"color"},colorKey:"y",trackerGroups:["group","markerGroup","dataLabelsGroup"],getSymbol:r,getExtremesFromAll:!0,init:function(a){var b=this,c=a.options.legend.valueDecimals,d=[],e,h,i,j,g,o,l;l=a.options.legend.layout==="horizontal";f.Series.prototype.init.apply(this,arguments);g=b.options.colorRange;if(b.options.valueRanges)k(b.options.valueRanges,
14
+ function(a){h=a.from;i=a.to;e="";h===void 0?e="< ":i===void 0&&(e="> ");h!==void 0&&(e+=u(h,c));h!==void 0&&i!==void 0&&(e+=" - ");i!==void 0&&(e+=u(i,c));d.push(f.extend({chart:b.chart,name:e,options:{},drawLegendSymbol:f.seriesTypes.area.prototype.drawLegendSymbol,visible:!0,setState:function(){},setVisible:function(){}},a))}),b.legendItems=d;else if(g)h=g.from,i=g.to,j=g.fromLabel,g=g.toLabel,o=l?[0,0,1,0]:[0,1,0,0],l||(l=j,j=g,g=l),o={linearGradient:{x1:o[0],y1:o[1],x2:o[2],y2:o[3]},stops:[[0,
15
+ h],[1,i]]},d=[{chart:b.chart,options:{},fromLabel:j,toLabel:g,color:o,drawLegendSymbol:this.drawLegendSymbol,visible:!0,setState:function(){},setVisible:function(){}}],b.legendItems=d},drawLegendSymbol:function(a,b){var c=a.options.symbolPadding,d=n(a.options.padding,8),e,h,i=this.chart.renderer.fontMetrics(a.options.itemStyle.fontSize).h,j=a.options.layout==="horizontal",g;g=n(a.options.rectangleLength,200);j?(e=-(c/2),h=0):(e=-g+a.baseline-c/2,h=d+i);b.fromText=this.chart.renderer.text(b.fromLabel,
16
+ h,e).attr({zIndex:2}).add(b.legendGroup);h=b.fromText.getBBox();b.legendSymbol=this.chart.renderer.rect(j?h.x+h.width+c:h.x-i-c,h.y,j?g:i,j?i:g,2).attr({zIndex:1}).add(b.legendGroup);g=b.legendSymbol.getBBox();b.toText=this.chart.renderer.text(b.toLabel,g.x+g.width+c,j?e:g.y+g.height-c).attr({zIndex:2}).add(b.legendGroup);e=b.toText.getBBox();j?(a.offsetWidth=h.width+g.width+e.width+c*2+d,a.itemY=i+d):(a.offsetWidth=Math.max(h.width,e.width)+c+g.width+d,a.itemY=g.height+d,a.itemX=c)},getBox:function(a){var b=
17
+ Number.MIN_VALUE,c=Number.MAX_VALUE,d=Number.MIN_VALUE,e=Number.MAX_VALUE;k(a||this.options.data,function(a){for(var i=a.path,j=i.length,g=!1,f=Number.MIN_VALUE,l=Number.MAX_VALUE,m=Number.MIN_VALUE,k=Number.MAX_VALUE;j--;)typeof i[j]==="number"&&(g?(f=Math.max(f,i[j]),l=Math.min(l,i[j])):(m=Math.max(m,i[j]),k=Math.min(k,i[j])),g=!g);a._maxX=f;a._minX=l;a._maxY=m;a._minY=k;b=Math.max(b,f);c=Math.min(c,l);d=Math.max(d,m);e=Math.min(e,k)});this.minY=e;this.maxY=d;this.minX=c;this.maxX=b},translatePath:function(a){var b=
18
+ !1,c=this.xAxis,d=this.yAxis,e,a=[].concat(a);for(e=a.length;e--;)typeof a[e]==="number"&&(a[e]=b?Math.round(c.translate(a[e])):Math.round(d.len-d.translate(a[e])),b=!b);return a},setData:function(){f.Series.prototype.setData.apply(this,arguments);this.getBox()},translate:function(){var a=this,b=Number.MAX_VALUE,c=Number.MIN_VALUE;a.generatePoints();k(a.data,function(d){d.shapeType="path";d.shapeArgs={d:a.translatePath(d.path)};if(typeof d.y==="number")if(d.y>c)c=d.y;else if(d.y<b)b=d.y});a.translateColors(b,
19
+ c)},translateColors:function(a,b){var c=this.options,d=c.valueRanges,e=c.colorRange,h=this.colorKey,i,f;e&&(i=x(e.from),f=x(e.to));k(this.data,function(g){var k=g[h],l=[],m,n;if(d)for(m=d.length;m--;){if(l=d[m],i=l.from,f=l.to,(i===void 0||k>=i)&&(f===void 0||k<=f)){g.options.color=l.color;break}}else if(e&&k!==void 0){n=(b-k)/(b-a);for(m=4;m--;)l[m]=Math.round(f.rgba[m]+(i.rgba[m]-f.rgba[m])*n);g.options.color=k===null?c.nullColor:"rgba("+l.join(",")+")"}})},drawGraph:r,drawDataLabels:r,drawPoints:function(){var a=
20
+ this.xAxis,b=this.yAxis,c=this.colorKey;k(this.data,function(a){a.plotY=1;if(a[c]===null)a[c]=0,a.isNull=!0});f.seriesTypes.column.prototype.drawPoints.apply(this);k(this.data,function(d){var e=d.dataLabels,f=a.toPixels(d._minX,!0),i=a.toPixels(d._maxX,!0),j=b.toPixels(d._minY,!0),g=b.toPixels(d._maxY,!0);d.plotX=Math.round(f+(i-f)*n(e&&e.anchorX,0.5));d.plotY=Math.round(j+(g-j)*n(e&&e.anchorY,0.5));d.isNull&&(d[c]=null)});f.Series.prototype.drawDataLabels.call(this)}});f.Map=function(a,b){var c=
21
+ {endOnTick:!1,gridLineWidth:0,labels:{enabled:!1},lineWidth:0,minPadding:0,maxPadding:0,startOnTick:!1,tickWidth:0,title:null},d;d=a.series;a.series=null;a=p({chart:{type:"map",panning:"xy"},xAxis:c,yAxis:p(c,{reversed:!0})},a,{chart:{inverted:!1}});a.series=d;return new f.Chart(a,b)}})(Highcharts);