corrade-nucleus-nucleons – Blame information for rev 20

Subversion Repositories:
Rev:
Rev Author Line No. Line
20 office 1 /**
2 * @license Highcharts JS v5.0.12 (2017-05-24)
3 * GridAxis
4 *
5 * (c) 2016 Lars A. V. Cabrera
6 *
7 * --- WORK IN PROGRESS ---
8 *
9 * License: www.highcharts.com/license
10 */
11 'use strict';
12 (function(factory) {
13 if (typeof module === 'object' && module.exports) {
14 module.exports = factory;
15 } else {
16 factory(Highcharts);
17 }
18 }(function(Highcharts) {
19 (function(H) {
20 /**
21 * (c) 2016 Highsoft AS
22 * Authors: Lars A. V. Cabrera
23 *
24 * License: www.highcharts.com/license
25 */
26  
27 var dateFormat = H.dateFormat,
28 each = H.each,
29 isObject = H.isObject,
30 pick = H.pick,
31 wrap = H.wrap,
32 Axis = H.Axis,
33 Chart = H.Chart,
34 Tick = H.Tick;
35  
36  
37 // Enum for which side the axis is on.
38 // Maps to axis.side
39 var axisSide = {
40 top: 0,
41 right: 1,
42 bottom: 2,
43 left: 3,
44 0: 'top',
45 1: 'right',
46 2: 'bottom',
47 3: 'left'
48 };
49  
50 /**
51 * Checks if an axis is the outer axis in its dimension. Since
52 * axes are placed outwards in order, the axis with the highest
53 * index is the outermost axis.
54 *
55 * Example: If there are multiple x-axes at the top of the chart,
56 * this function returns true if the axis supplied is the last
57 * of the x-axes.
58 *
59 * @return true if the axis is the outermost axis in its dimension;
60 * false if not
61 */
62 Axis.prototype.isOuterAxis = function() {
63 var axis = this,
64 thisIndex = -1,
65 isOuter = true;
66  
67 each(this.chart.axes, function(otherAxis, index) {
68 if (otherAxis.side === axis.side) {
69 if (otherAxis === axis) {
70 // Get the index of the axis in question
71 thisIndex = index;
72  
73 // Check thisIndex >= 0 in case thisIndex has
74 // not been found yet
75 } else if (thisIndex >= 0 && index > thisIndex) {
76 // There was an axis on the same side with a
77 // higher index. Exit the loop.
78 isOuter = false;
79 return;
80 }
81 }
82 });
83 // There were either no other axes on the same side,
84 // or the other axes were not farther from the chart
85 return isOuter;
86 };
87  
88 /**
89 * Shortcut function to Tick.label.getBBox().width.
90 *
91 * @return {number} width - the width of the tick label
92 */
93 Tick.prototype.getLabelWidth = function() {
94 return this.label.getBBox().width;
95 };
96  
97 /**
98 * Get the maximum label length.
99 * This function can be used in states where the axis.maxLabelLength has not
100 * been set.
101 *
102 * @param {boolean} force - Optional parameter to force a new calculation, even
103 * if a value has already been set
104 * @return {number} maxLabelLength - the maximum label length of the axis
105 */
106 Axis.prototype.getMaxLabelLength = function(force) {
107 var tickPositions = this.tickPositions,
108 ticks = this.ticks,
109 maxLabelLength = 0;
110  
111 if (!this.maxLabelLength || force) {
112 each(tickPositions, function(tick) {
113 tick = ticks[tick];
114 if (tick && tick.labelLength > maxLabelLength) {
115 maxLabelLength = tick.labelLength;
116 }
117 });
118 this.maxLabelLength = maxLabelLength;
119 }
120 return this.maxLabelLength;
121 };
122  
123 /**
124 * Adds the axis defined in axis.options.title
125 */
126 Axis.prototype.addTitle = function() {
127 var axis = this,
128 renderer = axis.chart.renderer,
129 axisParent = axis.axisParent,
130 horiz = axis.horiz,
131 opposite = axis.opposite,
132 options = axis.options,
133 axisTitleOptions = options.title,
134 hasData,
135 showAxis,
136 textAlign;
137  
138 // For reuse in Axis.render
139 hasData = axis.hasData();
140 axis.showAxis = showAxis = hasData || pick(options.showEmpty, true);
141  
142 // Disregard title generation in original Axis.getOffset()
143 options.title = '';
144  
145 if (!axis.axisTitle) {
146 textAlign = axisTitleOptions.textAlign;
147 if (!textAlign) {
148 textAlign = (horiz ? {
149 low: 'left',
150 middle: 'center',
151 high: 'right'
152 } : {
153 low: opposite ? 'right' : 'left',
154 middle: 'center',
155 high: opposite ? 'left' : 'right'
156 })[axisTitleOptions.align];
157 }
158 axis.axisTitle = renderer.text(
159 axisTitleOptions.text,
160 0,
161 0,
162 axisTitleOptions.useHTML
163 )
164 .attr({
165 zIndex: 7,
166 rotation: axisTitleOptions.rotation || 0,
167 align: textAlign
168 })
169 .addClass('highcharts-axis-title')
170  
171 // Add to axisParent instead of axisGroup, to ignore the space
172 // it takes
173 .add(axisParent);
174 axis.axisTitle.isNew = true;
175 }
176  
177  
178 // hide or show the title depending on whether showEmpty is set
179 axis.axisTitle[showAxis ? 'show' : 'hide'](true);
180 };
181  
182 /**
183 * Add custom date formats
184 */
185 H.dateFormats = {
186 // Week number
187 W: function(timestamp) {
188 var date = new Date(timestamp),
189 day = date.getUTCDay() === 0 ? 7 : date.getUTCDay(),
190 time = date.getTime(),
191 startOfYear = new Date(date.getUTCFullYear(), 0, 1, -6),
192 dayNumber;
193 date.setDate(date.getUTCDate() + 4 - day);
194 dayNumber = Math.floor((time - startOfYear) / 86400000);
195 return 1 + Math.floor(dayNumber / 7);
196 },
197 // First letter of the day of the week, e.g. 'M' for 'Monday'.
198 E: function(timestamp) {
199 return dateFormat('%a', timestamp, true).charAt(0);
200 }
201 };
202  
203 /**
204 * Prevents adding the last tick label if the axis is not a category axis.
205 *
206 * Since numeric labels are normally placed at starts and ends of a range of
207 * value, and this module makes the label point at the value, an "extra" label
208 * would appear.
209 *
210 * @param {function} proceed - the original function
211 */
212 wrap(Tick.prototype, 'addLabel', function(proceed) {
213 var axis = this.axis,
214 isCategoryAxis = axis.options.categories !== undefined,
215 tickPositions = axis.tickPositions,
216 lastTick = tickPositions[tickPositions.length - 1],
217 isLastTick = this.pos !== lastTick;
218  
219 if (!axis.options.grid || isCategoryAxis || isLastTick) {
220 proceed.apply(this);
221 }
222 });
223  
224 /**
225 * Center tick labels vertically and horizontally between ticks
226 *
227 * @param {function} proceed - the original function
228 *
229 * @return {object} object - an object containing x and y positions
230 * for the tick
231 */
232 wrap(Tick.prototype, 'getLabelPosition', function(proceed, x, y, label) {
233 var retVal = proceed.apply(this, Array.prototype.slice.call(arguments, 1)),
234 axis = this.axis,
235 options = axis.options,
236 tickInterval = options.tickInterval || 1,
237 newX,
238 newPos,
239 axisHeight,
240 fontSize,
241 labelMetrics,
242 lblB,
243 lblH,
244 labelCenter;
245  
246 // Only center tick labels if axis has option grid: true
247 if (options.grid) {
248 fontSize = options.labels.style.fontSize;
249 labelMetrics = axis.chart.renderer.fontMetrics(fontSize, label);
250 lblB = labelMetrics.b;
251 lblH = labelMetrics.h;
252  
253 if (axis.horiz && options.categories === undefined) {
254 // Center x position
255 axisHeight = axis.axisGroup.getBBox().height;
256 newPos = this.pos + tickInterval / 2;
257 retVal.x = axis.translate(newPos) + axis.left;
258 labelCenter = (axisHeight / 2) + (lblH / 2) - Math.abs(lblH - lblB);
259  
260 // Center y position
261 if (axis.side === axisSide.top) {
262 retVal.y = y - labelCenter;
263 } else {
264 retVal.y = y + labelCenter;
265 }
266 } else {
267 // Center y position
268 if (options.categories === undefined) {
269 newPos = this.pos + (tickInterval / 2);
270 retVal.y = axis.translate(newPos) + axis.top + (lblB / 2);
271 }
272  
273 // Center x position
274 newX = (this.getLabelWidth() / 2) - (axis.maxLabelLength / 2);
275 if (axis.side === axisSide.left) {
276 retVal.x += newX;
277 } else {
278 retVal.x -= newX;
279 }
280 }
281 }
282 return retVal;
283 });
284  
285  
286 /**
287 * Draw vertical ticks extra long to create cell floors and roofs.
288 * Overrides the tickLength for vertical axes.
289 *
290 * @param {function} proceed - the original function
291 * @returns {array} retVal -
292 */
293 wrap(Axis.prototype, 'tickSize', function(proceed) {
294 var axis = this,
295 retVal = proceed.apply(axis, Array.prototype.slice.call(arguments, 1)),
296 labelPadding,
297 distance;
298  
299 if (axis.options.grid && !axis.horiz) {
300 labelPadding = (Math.abs(axis.defaultLeftAxisOptions.labels.x) * 2);
301 if (!axis.maxLabelLength) {
302 axis.maxLabelLength = axis.getMaxLabelLength();
303 }
304 distance = axis.maxLabelLength + labelPadding;
305  
306 retVal[0] = distance;
307 }
308 return retVal;
309 });
310  
311 /**
312 * Disregards space required by axisTitle, by adding axisTitle to axisParent
313 * instead of axisGroup, and disregarding margins and offsets related to
314 * axisTitle.
315 *
316 * @param {function} proceed - the original function
317 */
318 wrap(Axis.prototype, 'getOffset', function(proceed) {
319 var axis = this,
320 axisOffset = axis.chart.axisOffset,
321 side = axis.side,
322 axisHeight,
323 tickSize,
324 options = axis.options,
325 axisTitleOptions = options.title,
326 addTitle = axisTitleOptions &&
327 axisTitleOptions.text &&
328 axisTitleOptions.enabled !== false;
329  
330 if (axis.options.grid && isObject(axis.options.title)) {
331  
332 tickSize = axis.tickSize('tick')[0];
333 if (axisOffset[side] && tickSize) {
334 axisHeight = axisOffset[side] + tickSize;
335 }
336  
337 if (addTitle) {
338 // Use the custom addTitle() to add it, while preventing making room
339 // for it
340 axis.addTitle();
341 }
342  
343 proceed.apply(axis, Array.prototype.slice.call(arguments, 1));
344  
345 axisOffset[side] = pick(axisHeight, axisOffset[side]);
346  
347  
348 // Put axis options back after original Axis.getOffset() has been called
349 options.title = axisTitleOptions;
350  
351 } else {
352 proceed.apply(axis, Array.prototype.slice.call(arguments, 1));
353 }
354 });
355  
356 /**
357 * Prevents rotation of labels when squished, as rotating them would not
358 * help.
359 *
360 * @param {function} proceed - the original function
361 */
362 wrap(Axis.prototype, 'renderUnsquish', function(proceed) {
363 if (this.options.grid) {
364 this.labelRotation = 0;
365 this.options.labels.rotation = 0;
366 }
367 proceed.apply(this);
368 });
369  
370 /**
371 * Places leftmost tick at the start of the axis, to create a left wall.
372 *
373 * @param {function} proceed - the original function
374 */
375 wrap(Axis.prototype, 'setOptions', function(proceed, userOptions) {
376 var axis = this;
377 if (userOptions.grid && axis.horiz) {
378 userOptions.startOnTick = true;
379 userOptions.minPadding = 0;
380 userOptions.endOnTick = true;
381 }
382 proceed.apply(this, Array.prototype.slice.call(arguments, 1));
383 });
384  
385 /**
386 * Draw an extra line on the far side of the the axisLine,
387 * creating cell roofs of a grid.
388 *
389 * @param {function} proceed - the original function
390 */
391 wrap(Axis.prototype, 'render', function(proceed) {
392 var axis = this,
393 options = axis.options,
394 labelPadding,
395 distance,
396 lineWidth,
397 linePath,
398 yStartIndex,
399 yEndIndex,
400 xStartIndex,
401 xEndIndex,
402 renderer = axis.chart.renderer,
403 axisGroupBox;
404  
405 if (options.grid) {
406 labelPadding = (Math.abs(axis.defaultLeftAxisOptions.labels.x) * 2);
407 distance = axis.maxLabelLength + labelPadding;
408 lineWidth = options.lineWidth;
409  
410 // Remove right wall before rendering
411 if (axis.rightWall) {
412 axis.rightWall.destroy();
413 }
414  
415 // Call original Axis.render() to obtain axis.axisLine and
416 // axis.axisGroup
417 proceed.apply(axis);
418  
419 axisGroupBox = axis.axisGroup.getBBox();
420  
421 // Add right wall on horizontal axes
422 if (axis.horiz) {
423 axis.rightWall = renderer.path([
424 'M',
425 axisGroupBox.x + axis.width + 1, // account for left wall
426 axisGroupBox.y,
427 'L',
428 axisGroupBox.x + axis.width + 1, // account for left wall
429 axisGroupBox.y + axisGroupBox.height
430 ])
431 .attr({
432 stroke: options.tickColor || '#ccd6eb',
433 'stroke-width': options.tickWidth || 1,
434 zIndex: 7,
435 class: 'grid-wall'
436 })
437 .add(axis.axisGroup);
438 }
439  
440 if (axis.isOuterAxis() && axis.axisLine) {
441 if (axis.horiz) {
442 // -1 to avoid adding distance each time the chart updates
443 distance = axisGroupBox.height - 1;
444 }
445  
446 if (lineWidth) {
447 linePath = axis.getLinePath(lineWidth);
448 xStartIndex = linePath.indexOf('M') + 1;
449 xEndIndex = linePath.indexOf('L') + 1;
450 yStartIndex = linePath.indexOf('M') + 2;
451 yEndIndex = linePath.indexOf('L') + 2;
452  
453 // Negate distance if top or left axis
454 if (axis.side === axisSide.top || axis.side === axisSide.left) {
455 distance = -distance;
456 }
457  
458 // If axis is horizontal, reposition line path vertically
459 if (axis.horiz) {
460 linePath[yStartIndex] = linePath[yStartIndex] + distance;
461 linePath[yEndIndex] = linePath[yEndIndex] + distance;
462 } else {
463 // If axis is vertical, reposition line path horizontally
464 linePath[xStartIndex] = linePath[xStartIndex] + distance;
465 linePath[xEndIndex] = linePath[xEndIndex] + distance;
466 }
467  
468 if (!axis.axisLineExtra) {
469 axis.axisLineExtra = renderer.path(linePath)
470 .attr({
471 stroke: options.lineColor,
472 'stroke-width': lineWidth,
473 zIndex: 7
474 })
475 .add(axis.axisGroup);
476 } else {
477 axis.axisLineExtra.animate({
478 d: linePath
479 });
480 }
481  
482 // show or hide the line depending on options.showEmpty
483 axis.axisLine[axis.showAxis ? 'show' : 'hide'](true);
484 }
485 }
486 } else {
487 proceed.apply(axis);
488 }
489 });
490  
491 /**
492 * Wraps chart rendering with the following customizations:
493 * 1. Prohibit timespans of multitudes of a time unit
494 * 2. Draw cell walls on vertical axes
495 *
496 * @param {function} proceed - the original function
497 */
498 wrap(Chart.prototype, 'render', function(proceed) {
499 // 25 is optimal height for default fontSize (11px)
500 // 25 / 11 ≈ 2.28
501 var fontSizeToCellHeightRatio = 25 / 11,
502 fontMetrics,
503 fontSize;
504  
505 each(this.axes, function(axis) {
506 var options = axis.options;
507 if (options.grid) {
508 fontSize = options.labels.style.fontSize;
509 fontMetrics = axis.chart.renderer.fontMetrics(fontSize);
510  
511 // Prohibit timespans of multitudes of a time unit,
512 // e.g. two days, three weeks, etc.
513 if (options.type === 'datetime') {
514 options.units = [
515 ['millisecond', [1]],
516 ['second', [1]],
517 ['minute', [1]],
518 ['hour', [1]],
519 ['day', [1]],
520 ['week', [1]],
521 ['month', [1]],
522 ['year', null]
523 ];
524 }
525  
526 // Make tick marks taller, creating cell walls of a grid.
527 // Use cellHeight axis option if set
528 if (axis.horiz) {
529 options.tickLength = options.cellHeight ||
530 fontMetrics.h * fontSizeToCellHeightRatio;
531 } else {
532 options.tickWidth = 1;
533 if (!options.lineWidth) {
534 options.lineWidth = 1;
535 }
536 }
537 }
538 });
539  
540 // Call original Chart.render()
541 proceed.apply(this);
542 });
543  
544 }(Highcharts));
545 }));