222 lines
5.6 KiB
JavaScript
222 lines
5.6 KiB
JavaScript
'use strict';
|
|
|
|
module.exports = function(Chart) {
|
|
|
|
var globalOpts = Chart.defaults.global;
|
|
|
|
globalOpts.elements.rectangle = {
|
|
backgroundColor: globalOpts.defaultColor,
|
|
borderWidth: 0,
|
|
borderColor: globalOpts.defaultColor,
|
|
borderSkipped: 'bottom'
|
|
};
|
|
|
|
function isVertical(bar) {
|
|
return bar._view.width !== undefined;
|
|
}
|
|
|
|
/**
|
|
* Helper function to get the bounds of the bar regardless of the orientation
|
|
* @private
|
|
* @param bar {Chart.Element.Rectangle} the bar
|
|
* @return {Bounds} bounds of the bar
|
|
*/
|
|
function getBarBounds(bar) {
|
|
var vm = bar._view;
|
|
var x1, x2, y1, y2;
|
|
|
|
if (isVertical(bar)) {
|
|
// vertical
|
|
var halfWidth = vm.width / 2;
|
|
x1 = vm.x - halfWidth;
|
|
x2 = vm.x + halfWidth;
|
|
y1 = Math.min(vm.y, vm.base);
|
|
y2 = Math.max(vm.y, vm.base);
|
|
} else {
|
|
// horizontal bar
|
|
var halfHeight = vm.height / 2;
|
|
x1 = Math.min(vm.x, vm.base);
|
|
x2 = Math.max(vm.x, vm.base);
|
|
y1 = vm.y - halfHeight;
|
|
y2 = vm.y + halfHeight;
|
|
}
|
|
|
|
return {
|
|
left: x1,
|
|
top: y1,
|
|
right: x2,
|
|
bottom: y2
|
|
};
|
|
}
|
|
|
|
Chart.elements.Whisker = Chart.Element.extend({
|
|
draw: function() {
|
|
var ctx = this._chart.ctx;
|
|
var vm = this._view;
|
|
|
|
var halfWidth = vm.width / 2,
|
|
leftX = vm.x - halfWidth,
|
|
rightX = vm.x + halfWidth,
|
|
top = vm.base - (vm.base - vm.y),
|
|
halfStroke = vm.borderWidth / 2;
|
|
|
|
// Canvas doesn't allow us to stroke inside the width so we can
|
|
// adjust the sizes to fit if we're setting a stroke on the line
|
|
if (vm.borderWidth) {
|
|
leftX += halfStroke;
|
|
rightX -= halfStroke;
|
|
top += halfStroke;
|
|
}
|
|
|
|
ctx.beginPath();
|
|
ctx.fillStyle = vm.backgroundColor;
|
|
ctx.strokeStyle = vm.borderColor;
|
|
ctx.lineWidth = vm.borderWidth;
|
|
|
|
// Corner points, from bottom-left to bottom-right clockwise
|
|
// | 1 2 |
|
|
// | 0 3 |
|
|
var corners = [
|
|
[leftX, vm.base],
|
|
[leftX, top],
|
|
[rightX, top],
|
|
[rightX, vm.base]
|
|
];
|
|
|
|
// Find first (starting) corner with fallback to 'bottom'
|
|
var borders = ['bottom', 'left', 'top', 'right'];
|
|
var startCorner = borders.indexOf(vm.borderSkipped, 0);
|
|
if (startCorner === -1) {
|
|
startCorner = 0;
|
|
}
|
|
|
|
function cornerAt(index) {
|
|
return corners[(startCorner + index) % 4];
|
|
}
|
|
|
|
// Draw rectangle from 'startCorner'
|
|
var corner = cornerAt(0);
|
|
ctx.moveTo(corner[0], corner[1]);
|
|
|
|
for (var i = 1; i < 4; i++) {
|
|
corner = cornerAt(i);
|
|
ctx.lineTo(corner[0], corner[1]);
|
|
}
|
|
|
|
ctx.fill();
|
|
if (vm.borderWidth) {
|
|
ctx.stroke();
|
|
}
|
|
ctx.closePath();
|
|
|
|
// Median line
|
|
ctx.beginPath();
|
|
|
|
ctx.moveTo(leftX, vm.median);
|
|
ctx.lineTo(rightX, vm.median);
|
|
ctx.lineWidth = 2;
|
|
|
|
// set line color
|
|
ctx.strokeStyle = 'rgb(54, 74, 205)';
|
|
ctx.stroke();
|
|
ctx.closePath();
|
|
|
|
// Top Whisker
|
|
// if (smaller than 5px then do not draw)
|
|
if (vm.median - vm.maxV > 10) {
|
|
ctx.beginPath();
|
|
ctx.moveTo((rightX - leftX) / 2 + leftX, vm.median - 1);
|
|
ctx.lineTo((rightX - leftX) / 2 + leftX, vm.maxV);
|
|
ctx.lineWidth = 2;
|
|
ctx.strokeStyle = 'rgb(245, 93, 93)';
|
|
ctx.stroke();
|
|
ctx.closePath();
|
|
ctx.beginPath();
|
|
ctx.arc((rightX - leftX) / 2 + leftX, vm.maxV, 3, 0, 2 * Math.PI);
|
|
ctx.fillStyle = 'rgb(245, 93, 93)';
|
|
ctx.fill();
|
|
}
|
|
|
|
// Bottom Whisker
|
|
// if (smaller than 5px then do not draw)
|
|
if (vm.minV - vm.median > 10) {
|
|
ctx.beginPath();
|
|
ctx.moveTo((rightX - leftX) / 2 + leftX, vm.median + 1);
|
|
ctx.lineTo((rightX - leftX) / 2 + leftX, vm.minV);
|
|
ctx.lineWidth = 2;
|
|
ctx.strokeStyle = 'rgb(245, 93, 93)';
|
|
ctx.stroke();
|
|
ctx.closePath();
|
|
ctx.beginPath();
|
|
ctx.arc((rightX - leftX) / 2 + leftX, vm.minV, 3, 0, 2 * Math.PI);
|
|
ctx.fillStyle = 'rgb(245, 93, 93)';
|
|
ctx.fill();
|
|
}
|
|
},
|
|
height: function() {
|
|
var vm = this._view;
|
|
return vm.base - vm.y;
|
|
},
|
|
inRange: function(mouseX, mouseY) {
|
|
var inRange = false;
|
|
|
|
if (this._view) {
|
|
var bounds = getBarBounds(this);
|
|
inRange = mouseX >= bounds.left && mouseX <= bounds.right && mouseY >= bounds.top && mouseY <= bounds.bottom;
|
|
}
|
|
|
|
return inRange;
|
|
},
|
|
inLabelRange: function(mouseX, mouseY) {
|
|
var me = this;
|
|
if (!me._view) {
|
|
return false;
|
|
}
|
|
|
|
var inRange = false;
|
|
var bounds = getBarBounds(me);
|
|
|
|
if (isVertical(me)) {
|
|
inRange = mouseX >= bounds.left && mouseX <= bounds.right;
|
|
} else {
|
|
inRange = mouseY >= bounds.top && mouseY <= bounds.bottom;
|
|
}
|
|
|
|
return inRange;
|
|
},
|
|
inXRange: function(mouseX) {
|
|
var bounds = getBarBounds(this);
|
|
return mouseX >= bounds.left && mouseX <= bounds.right;
|
|
},
|
|
inYRange: function(mouseY) {
|
|
var bounds = getBarBounds(this);
|
|
return mouseY >= bounds.top && mouseY <= bounds.bottom;
|
|
},
|
|
getCenterPoint: function() {
|
|
var vm = this._view;
|
|
var x, y;
|
|
if (isVertical(this)) {
|
|
x = vm.x;
|
|
y = (vm.y + vm.base) / 2;
|
|
} else {
|
|
x = (vm.x + vm.base) / 2;
|
|
y = vm.y;
|
|
}
|
|
|
|
return {x: x, y: y};
|
|
},
|
|
getArea: function() {
|
|
var vm = this._view;
|
|
return vm.width * Math.abs(vm.y - vm.base);
|
|
},
|
|
tooltipPosition: function() {
|
|
var vm = this._view;
|
|
return {
|
|
x: vm.x,
|
|
y: vm.y
|
|
};
|
|
}
|
|
});
|
|
|
|
};
|