corrade-nucleus-nucleons – Blame information for rev 31

Subversion Repositories:
Rev:
Rev Author Line No. Line
31 office 1 /**
2 * @license Highcharts JS v5.0.14 (2017-07-28)
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 .css(axisTitleOptions.style)
172  
173 // Add to axisParent instead of axisGroup, to ignore the space
174 // it takes
175 .add(axisParent);
176 axis.axisTitle.isNew = true;
177 }
178  
179  
180 // hide or show the title depending on whether showEmpty is set
181 axis.axisTitle[showAxis ? 'show' : 'hide'](true);
182 };
183  
184 /**
185 * Add custom date formats
186 */
187 H.dateFormats = {
188 // Week number
189 W: function(timestamp) {
190 var date = new Date(timestamp),
191 day = date.getUTCDay() === 0 ? 7 : date.getUTCDay(),
192 time = date.getTime(),
193 startOfYear = new Date(date.getUTCFullYear(), 0, 1, -6),
194 dayNumber;
195 date.setDate(date.getUTCDate() + 4 - day);
196 dayNumber = Math.floor((time - startOfYear) / 86400000);
197 return 1 + Math.floor(dayNumber / 7);
198 },
199 // First letter of the day of the week, e.g. 'M' for 'Monday'.
200 E: function(timestamp) {
201 return dateFormat('%a', timestamp, true).charAt(0);
202 }
203 };
204  
205 /**
206 * Prevents adding the last tick label if the axis is not a category axis.
207 *
208 * Since numeric labels are normally placed at starts and ends of a range of
209 * value, and this module makes the label point at the value, an "extra" label
210 * would appear.
211 *
212 * @param {function} proceed - the original function
213 */
214 wrap(Tick.prototype, 'addLabel', function(proceed) {
215 var axis = this.axis,
216 isCategoryAxis = axis.options.categories !== undefined,
217 tickPositions = axis.tickPositions,
218 lastTick = tickPositions[tickPositions.length - 1],
219 isLastTick = this.pos !== lastTick;
220  
221 if (!axis.options.grid || isCategoryAxis || isLastTick) {
222 proceed.apply(this);
223 }
224 });
225  
226 /**
227 * Center tick labels vertically and horizontally between ticks
228 *
229 * @param {function} proceed - the original function
230 *
231 * @return {object} object - an object containing x and y positions
232 * for the tick
233 */
234 wrap(Tick.prototype, 'getLabelPosition', function(proceed, x, y, label) {
235 var retVal = proceed.apply(this, Array.prototype.slice.call(arguments, 1)),
236 axis = this.axis,
237 options = axis.options,
238 tickInterval = options.tickInterval || 1,
239 newX,
240 newPos,
241 axisHeight,
242 fontSize,
243 labelMetrics,
244 lblB,
245 lblH,
246 labelCenter;
247  
248 // Only center tick labels if axis has option grid: true
249 if (options.grid) {
250 fontSize = options.labels.style.fontSize;
251 labelMetrics = axis.chart.renderer.fontMetrics(fontSize, label);
252 lblB = labelMetrics.b;
253 lblH = labelMetrics.h;
254  
255 if (axis.horiz && options.categories === undefined) {
256 // Center x position
257 axisHeight = axis.axisGroup.getBBox().height;
258 newPos = this.pos + tickInterval / 2;
259 retVal.x = axis.translate(newPos) + axis.left;
260 labelCenter = (axisHeight / 2) + (lblH / 2) - Math.abs(lblH - lblB);
261  
262 // Center y position
263 if (axis.side === axisSide.top) {
264 retVal.y = y - labelCenter;
265 } else {
266 retVal.y = y + labelCenter;
267 }
268 } else {
269 // Center y position
270 if (options.categories === undefined) {
271 newPos = this.pos + (tickInterval / 2);
272 retVal.y = axis.translate(newPos) + axis.top + (lblB / 2);
273 }
274  
275 // Center x position
276 newX = (this.getLabelWidth() / 2) - (axis.maxLabelLength / 2);
277 if (axis.side === axisSide.left) {
278 retVal.x += newX;
279 } else {
280 retVal.x -= newX;
281 }
282 }
283 }
284 return retVal;
285 });
286  
287  
288 /**
289 * Draw vertical ticks extra long to create cell floors and roofs.
290 * Overrides the tickLength for vertical axes.
291 *
292 * @param {function} proceed - the original function
293 * @returns {array} retVal -
294 */
295 wrap(Axis.prototype, 'tickSize', function(proceed) {
296 var axis = this,
297 retVal = proceed.apply(axis, Array.prototype.slice.call(arguments, 1)),
298 labelPadding,
299 distance;
300  
301 if (axis.options.grid && !axis.horiz) {
302 labelPadding = (Math.abs(axis.defaultLeftAxisOptions.labels.x) * 2);
303 if (!axis.maxLabelLength) {
304 axis.maxLabelLength = axis.getMaxLabelLength();
305 }
306 distance = axis.maxLabelLength + labelPadding;
307  
308 retVal[0] = distance;
309 }
310 return retVal;
311 });
312  
313 /**
314 * Disregards space required by axisTitle, by adding axisTitle to axisParent
315 * instead of axisGroup, and disregarding margins and offsets related to
316 * axisTitle.
317 *
318 * @param {function} proceed - the original function
319 */
320 wrap(Axis.prototype, 'getOffset', function(proceed) {
321 var axis = this,
322 axisOffset = axis.chart.axisOffset,
323 side = axis.side,
324 axisHeight,
325 tickSize,
326 options = axis.options,
327 axisTitleOptions = options.title,
328 addTitle = axisTitleOptions &&
329 axisTitleOptions.text &&
330 axisTitleOptions.enabled !== false;
331  
332 if (axis.options.grid && isObject(axis.options.title)) {
333  
334 tickSize = axis.tickSize('tick')[0];
335 if (axisOffset[side] && tickSize) {
336 axisHeight = axisOffset[side] + tickSize;
337 }
338  
339 if (addTitle) {
340 // Use the custom addTitle() to add it, while preventing making room
341 // for it
342 axis.addTitle();
343 }
344  
345 proceed.apply(axis, Array.prototype.slice.call(arguments, 1));
346  
347 axisOffset[side] = pick(axisHeight, axisOffset[side]);
348  
349  
350 // Put axis options back after original Axis.getOffset() has been called
351 options.title = axisTitleOptions;
352  
353 } else {
354 proceed.apply(axis, Array.prototype.slice.call(arguments, 1));
355 }
356 });
357  
358 /**
359 * Prevents rotation of labels when squished, as rotating them would not
360 * help.
361 *
362 * @param {function} proceed - the original function
363 */
364 wrap(Axis.prototype, 'renderUnsquish', function(proceed) {
365 if (this.options.grid) {
366 this.labelRotation = 0;
367 this.options.labels.rotation = 0;
368 }
369 proceed.apply(this);
370 });
371  
372 /**
373 * Places leftmost tick at the start of the axis, to create a left wall.
374 *
375 * @param {function} proceed - the original function
376 */
377 wrap(Axis.prototype, 'setOptions', function(proceed, userOptions) {
378 var axis = this;
379 if (userOptions.grid && axis.horiz) {
380 userOptions.startOnTick = true;
381 userOptions.minPadding = 0;
382 userOptions.endOnTick = true;
383 }
384 proceed.apply(this, Array.prototype.slice.call(arguments, 1));
385 });
386  
387 /**
388 * Draw an extra line on the far side of the the axisLine,
389 * creating cell roofs of a grid.
390 *
391 * @param {function} proceed - the original function
392 */
393 wrap(Axis.prototype, 'render', function(proceed) {
394 var axis = this,
395 options = axis.options,
396 labelPadding,
397 distance,
398 lineWidth,
399 linePath,
400 yStartIndex,
401 yEndIndex,
402 xStartIndex,
403 xEndIndex,
404 renderer = axis.chart.renderer,
405 axisGroupBox;
406  
407 if (options.grid) {
408 labelPadding = (Math.abs(axis.defaultLeftAxisOptions.labels.x) * 2);
409 distance = axis.maxLabelLength + labelPadding;
410 lineWidth = options.lineWidth;
411  
412 // Remove right wall before rendering
413 if (axis.rightWall) {
414 axis.rightWall.destroy();
415 }
416  
417 // Call original Axis.render() to obtain axis.axisLine and
418 // axis.axisGroup
419 proceed.apply(axis);
420  
421 axisGroupBox = axis.axisGroup.getBBox();
422  
423 // Add right wall on horizontal axes
424 if (axis.horiz) {
425 axis.rightWall = renderer.path([
426 'M',
427 axisGroupBox.x + axis.width + 1, // account for left wall
428 axisGroupBox.y,
429 'L',
430 axisGroupBox.x + axis.width + 1, // account for left wall
431 axisGroupBox.y + axisGroupBox.height
432 ])
433 .attr({
434 stroke: options.tickColor || '#ccd6eb',
435 'stroke-width': options.tickWidth || 1,
436 zIndex: 7,
437 class: 'grid-wall'
438 })
439 .add(axis.axisGroup);
440 }
441  
442 if (axis.isOuterAxis() && axis.axisLine) {
443 if (axis.horiz) {
444 // -1 to avoid adding distance each time the chart updates
445 distance = axisGroupBox.height - 1;
446 }
447  
448 if (lineWidth) {
449 linePath = axis.getLinePath(lineWidth);
450 xStartIndex = linePath.indexOf('M') + 1;
451 xEndIndex = linePath.indexOf('L') + 1;
452 yStartIndex = linePath.indexOf('M') + 2;
453 yEndIndex = linePath.indexOf('L') + 2;
454  
455 // Negate distance if top or left axis
456 if (axis.side === axisSide.top || axis.side === axisSide.left) {
457 distance = -distance;
458 }
459  
460 // If axis is horizontal, reposition line path vertically
461 if (axis.horiz) {
462 linePath[yStartIndex] = linePath[yStartIndex] + distance;
463 linePath[yEndIndex] = linePath[yEndIndex] + distance;
464 } else {
465 // If axis is vertical, reposition line path horizontally
466 linePath[xStartIndex] = linePath[xStartIndex] + distance;
467 linePath[xEndIndex] = linePath[xEndIndex] + distance;
468 }
469  
470 if (!axis.axisLineExtra) {
471 axis.axisLineExtra = renderer.path(linePath)
472 .attr({
473 stroke: options.lineColor,
474 'stroke-width': lineWidth,
475 zIndex: 7
476 })
477 .add(axis.axisGroup);
478 } else {
479 axis.axisLineExtra.animate({
480 d: linePath
481 });
482 }
483  
484 // show or hide the line depending on options.showEmpty
485 axis.axisLine[axis.showAxis ? 'show' : 'hide'](true);
486 }
487 }
488 } else {
489 proceed.apply(axis);
490 }
491 });
492  
493 /**
494 * Wraps chart rendering with the following customizations:
495 * 1. Prohibit timespans of multitudes of a time unit
496 * 2. Draw cell walls on vertical axes
497 *
498 * @param {function} proceed - the original function
499 */
500 wrap(Chart.prototype, 'render', function(proceed) {
501 // 25 is optimal height for default fontSize (11px)
502 // 25 / 11 ≈ 2.28
503 var fontSizeToCellHeightRatio = 25 / 11,
504 fontMetrics,
505 fontSize;
506  
507 each(this.axes, function(axis) {
508 var options = axis.options;
509 if (options.grid) {
510 fontSize = options.labels.style.fontSize;
511 fontMetrics = axis.chart.renderer.fontMetrics(fontSize);
512  
513 // Prohibit timespans of multitudes of a time unit,
514 // e.g. two days, three weeks, etc.
515 if (options.type === 'datetime') {
516 options.units = [
517 ['millisecond', [1]],
518 ['second', [1]],
519 ['minute', [1]],
520 ['hour', [1]],
521 ['day', [1]],
522 ['week', [1]],
523 ['month', [1]],
524 ['year', null]
525 ];
526 }
527  
528 // Make tick marks taller, creating cell walls of a grid.
529 // Use cellHeight axis option if set
530 if (axis.horiz) {
531 options.tickLength = options.cellHeight ||
532 fontMetrics.h * fontSizeToCellHeightRatio;
533 } else {
534 options.tickWidth = 1;
535 if (!options.lineWidth) {
536 options.lineWidth = 1;
537 }
538 }
539 }
540 });
541  
542 // Call original Chart.render()
543 proceed.apply(this);
544 });
545  
546 }(Highcharts));
547 }));