214 lines
4.1 KiB
JavaScript
214 lines
4.1 KiB
JavaScript
'use strict';
|
|
|
|
var defaults = require('../core/core.defaults');
|
|
var Element = require('../core/core.element');
|
|
var helpers = require('../helpers/index');
|
|
|
|
var defaultColor = defaults.global.defaultColor;
|
|
|
|
defaults._set('global', {
|
|
elements: {
|
|
rectangle: {
|
|
backgroundColor: defaultColor,
|
|
borderColor: defaultColor,
|
|
borderSkipped: 'bottom',
|
|
borderWidth: 0
|
|
}
|
|
}
|
|
});
|
|
|
|
function isVertical(vm) {
|
|
return vm && vm.width !== undefined;
|
|
}
|
|
|
|
/**
|
|
* Helper function to get the bounds of the bar regardless of the orientation
|
|
* @param bar {Chart.Element.Rectangle} the bar
|
|
* @return {Bounds} bounds of the bar
|
|
* @private
|
|
*/
|
|
function getBarBounds(vm) {
|
|
var x1, x2, y1, y2, half;
|
|
|
|
if (isVertical(vm)) {
|
|
half = vm.width / 2;
|
|
x1 = vm.x - half;
|
|
x2 = vm.x + half;
|
|
y1 = Math.min(vm.y, vm.base);
|
|
y2 = Math.max(vm.y, vm.base);
|
|
} else {
|
|
half = vm.height / 2;
|
|
x1 = Math.min(vm.x, vm.base);
|
|
x2 = Math.max(vm.x, vm.base);
|
|
y1 = vm.y - half;
|
|
y2 = vm.y + half;
|
|
}
|
|
|
|
return {
|
|
left: x1,
|
|
top: y1,
|
|
right: x2,
|
|
bottom: y2
|
|
};
|
|
}
|
|
|
|
function swap(orig, v1, v2) {
|
|
return orig === v1 ? v2 : orig === v2 ? v1 : orig;
|
|
}
|
|
|
|
function parseBorderSkipped(vm) {
|
|
var edge = vm.borderSkipped;
|
|
var res = {};
|
|
|
|
if (!edge) {
|
|
return res;
|
|
}
|
|
|
|
if (vm.horizontal) {
|
|
if (vm.base > vm.x) {
|
|
edge = swap(edge, 'left', 'right');
|
|
}
|
|
} else if (vm.base < vm.y) {
|
|
edge = swap(edge, 'bottom', 'top');
|
|
}
|
|
|
|
res[edge] = true;
|
|
return res;
|
|
}
|
|
|
|
function parseBorderWidth(vm, maxW, maxH) {
|
|
var value = vm.borderWidth;
|
|
var skip = parseBorderSkipped(vm);
|
|
var t, r, b, l;
|
|
|
|
if (helpers.isObject(value)) {
|
|
t = +value.top || 0;
|
|
r = +value.right || 0;
|
|
b = +value.bottom || 0;
|
|
l = +value.left || 0;
|
|
} else {
|
|
t = r = b = l = +value || 0;
|
|
}
|
|
|
|
return {
|
|
t: skip.top || (t < 0) ? 0 : t > maxH ? maxH : t,
|
|
r: skip.right || (r < 0) ? 0 : r > maxW ? maxW : r,
|
|
b: skip.bottom || (b < 0) ? 0 : b > maxH ? maxH : b,
|
|
l: skip.left || (l < 0) ? 0 : l > maxW ? maxW : l
|
|
};
|
|
}
|
|
|
|
function boundingRects(vm) {
|
|
var bounds = getBarBounds(vm);
|
|
var width = bounds.right - bounds.left;
|
|
var height = bounds.bottom - bounds.top;
|
|
var border = parseBorderWidth(vm, width / 2, height / 2);
|
|
|
|
return {
|
|
outer: {
|
|
x: bounds.left,
|
|
y: bounds.top,
|
|
w: width,
|
|
h: height
|
|
},
|
|
inner: {
|
|
x: bounds.left + border.l,
|
|
y: bounds.top + border.t,
|
|
w: width - border.l - border.r,
|
|
h: height - border.t - border.b
|
|
}
|
|
};
|
|
}
|
|
|
|
function inRange(vm, x, y) {
|
|
var skipX = x === null;
|
|
var skipY = y === null;
|
|
var bounds = !vm || (skipX && skipY) ? false : getBarBounds(vm);
|
|
|
|
return bounds
|
|
&& (skipX || x >= bounds.left && x <= bounds.right)
|
|
&& (skipY || y >= bounds.top && y <= bounds.bottom);
|
|
}
|
|
|
|
module.exports = Element.extend({
|
|
_type: 'rectangle',
|
|
|
|
draw: function() {
|
|
var ctx = this._chart.ctx;
|
|
var vm = this._view;
|
|
var rects = boundingRects(vm);
|
|
var outer = rects.outer;
|
|
var inner = rects.inner;
|
|
|
|
ctx.fillStyle = vm.backgroundColor;
|
|
ctx.fillRect(outer.x, outer.y, outer.w, outer.h);
|
|
|
|
if (outer.w === inner.w && outer.h === inner.h) {
|
|
return;
|
|
}
|
|
|
|
ctx.save();
|
|
ctx.beginPath();
|
|
ctx.rect(outer.x, outer.y, outer.w, outer.h);
|
|
ctx.clip();
|
|
ctx.fillStyle = vm.borderColor;
|
|
ctx.rect(inner.x, inner.y, inner.w, inner.h);
|
|
ctx.fill('evenodd');
|
|
ctx.restore();
|
|
},
|
|
|
|
height: function() {
|
|
var vm = this._view;
|
|
return vm.base - vm.y;
|
|
},
|
|
|
|
inRange: function(mouseX, mouseY) {
|
|
return inRange(this._view, mouseX, mouseY);
|
|
},
|
|
|
|
inLabelRange: function(mouseX, mouseY) {
|
|
var vm = this._view;
|
|
return isVertical(vm)
|
|
? inRange(vm, mouseX, null)
|
|
: inRange(vm, null, mouseY);
|
|
},
|
|
|
|
inXRange: function(mouseX) {
|
|
return inRange(this._view, mouseX, null);
|
|
},
|
|
|
|
inYRange: function(mouseY) {
|
|
return inRange(this._view, null, mouseY);
|
|
},
|
|
|
|
getCenterPoint: function() {
|
|
var vm = this._view;
|
|
var x, y;
|
|
if (isVertical(vm)) {
|
|
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 isVertical(vm)
|
|
? vm.width * Math.abs(vm.y - vm.base)
|
|
: vm.height * Math.abs(vm.x - vm.base);
|
|
},
|
|
|
|
tooltipPosition: function() {
|
|
var vm = this._view;
|
|
return {
|
|
x: vm.x,
|
|
y: vm.y
|
|
};
|
|
}
|
|
});
|