Chart.elements.Rectangle.prototype.draw影响同页其他图表(Angular)
Chart.elements.Rectangle.prototype.draw inpacting on other charts in the same page(Angular)
我在不同的组件中创建了 2 个图表,这 2 个图表在同一页面(同一组件)中使用。图表有不同的逻辑和风格,调试图表我意识到绘图功能正在影响另一个图表,反之亦然。
这两个图表都有绘图功能,并且正在从 'chart-js' 导入图表,有人知道我如何在绘图功能中区分这些图表吗?
我已经尝试查询选择器图表并执行 if 检查绘制函数检查 id 但它不起作用
绘制方法如下
private customizeChartJs() {
const el = this.hostElement.nativeElement.querySelector('#customerRetention');
if (el) {
try {
Chart.elements.Rectangle.prototype.draw = function () {
console.log(this._chart);
const ctx = this._chart.ctx;
console.log();
const vm = this._view;
let left;
let right;
let top;
let bottom;
let signX;
let signY;
let borderSkipped;
let borderWidth = vm.borderWidth;
let nextCornerId;
let nextCorner;
let width;
let height;
let x;
let y;
const roundedCorner = this._chart.options.roundedCorner;
// Set Radius Here
const cornerRadius = 10;
// If radius is large enough to cause drawing errors a max radius is imposed
if (!vm.horizontal) {
// bar
left = vm.x - vm.width;
right = vm.x + vm.width / 2;
top = vm.y;
bottom = vm.base;
signX = 5;
signY = bottom > top ? 1 : -1;
borderSkipped = vm.borderSkipped || 'bottom';
} else {
// horizontal bar
left = vm.base;
right = vm.x;
top = vm.y - vm.height / 2;
bottom = vm.y + vm.height / 2;
signX = right > left ? 1 : -1;
signY = 1;
borderSkipped = vm.borderSkipped || 'left';
}
// 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 (borderWidth) {
// borderWidth shold be less than bar width and bar height.
const barSize = Math.min(Math.abs(left - right), Math.abs(top - bottom));
borderWidth = borderWidth > barSize ? barSize : borderWidth;
const halfStroke = borderWidth / 2;
// Adjust borderWidth when bar top position is near vm.base(zero).
const borderLeft = left + (borderSkipped !== 'left' ? halfStroke * signX : 0);
const borderRight = right + (borderSkipped !== 'right' ? -halfStroke * signX : 0);
const borderTop = top + (borderSkipped !== 'top' ? halfStroke * signY : 0);
const borderBottom = bottom + (borderSkipped !== 'bottom' ? -halfStroke * signY : 0);
// not become a vertical line?
if (borderLeft !== borderRight) {
top = borderTop;
bottom = borderBottom;
}
// not become a horizontal line?
if (borderTop !== borderBottom) {
left = borderLeft;
right = borderRight;
}
}
ctx.beginPath();
ctx.strokeStyle = vm.borderColor;
ctx.lineWidth = borderWidth;
ctx.fillStyle = vm.backgroundColor;
// Corner points, from bottom-left to bottom-right clockwise
// | 1 2 |
// | 0 3 |
const corners = [
[left, bottom],
[left, top],
[right, top],
[right, bottom],
];
// Find first (starting) corner with fallback to 'bottom'
const borders = ['bottom', 'left', 'top', 'right'];
let startCorner = borders.indexOf(borderSkipped, 0);
if (startCorner === -1) {
startCorner = 0;
}
function cornerAt(index) {
return corners[(startCorner + index) % 4];
}
// Draw rectangle from 'startCorner'
let corner = cornerAt(0);
ctx.moveTo(corner[0], corner[1]);
for (let i = 1; i < 4; i++) {
corner = cornerAt(i);
nextCornerId = i + 1;
if (nextCornerId === 4) {
nextCornerId = 0;
}
nextCorner = cornerAt(nextCornerId);
width = corners[2][0] - corners[1][0];
height = corners[0][1] - corners[1][1];
x = corners[1][0];
y = corners[1][1];
let radius = cornerRadius;
// Fix radius being too large
if (radius > height / 2) {
radius = height / 2;
}
if (radius > width / 2) {
radius = width / 2;
}
if (!vm.horizontal) {
ctx.beginPath();
ctx.moveTo(x + radius, y);
ctx.lineTo(x + width - radius, y);
ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
ctx.lineTo(x + width, y + height);
ctx.lineTo(x, y + height);
ctx.lineTo(x, y);
ctx.quadraticCurveTo(x, y, x, y);
ctx.closePath();
} else if (vm.horizontal && !roundedCorner) {
ctx.moveTo(x + radius, y);
ctx.lineTo(x + width - radius, y);
ctx.lineTo(x + width, y, x + width, y + radius);
ctx.lineTo(x + width, y + height - radius);
ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
ctx.lineTo(x + radius, y + height);
ctx.lineTo(x, y + height, x, y + height - radius);
ctx.lineTo(x, y + radius);
ctx.lineTo(x, y, x + radius, y);
} else {
ctx.moveTo(x + radius, y);
ctx.lineTo(x + width - radius, y);
ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
ctx.lineTo(x + width, y + height - radius);
ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
ctx.lineTo(x + radius, y + height);
ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
ctx.lineTo(x, y + radius);
ctx.quadraticCurveTo(x, y, x + radius, y);
}
}
ctx.fill();
if (borderWidth) {
ctx.stroke();
}
};
Chart.defaults.CustomerRetention = Chart.defaults.bar;
Chart.Tooltip.positioners.custom = (elements, position) => {
if (!elements.length) {
return false;
}
const { forceFirstTooltipsToLeft } = elements[0]._chart.options.custom;
let x = -299;
let y = 0;
// primeiros 3 itens da esquerda precisam abrir tooltip pra direita
if (forceFirstTooltipsToLeft && elements[0]._index < 3) {
x = 10;
} else {
const maxIndex = elements[0]._xScale.maxIndex;
if (maxIndex > 9 && elements[0]._index < 3) {
x = 10;
}
}
if (elements.length > 1) {
let indexElementTaller: number;
x += elements[0]._model.x;
indexElementTaller = elements[0]._model.y <= elements[1]._model.y ? 0 : 1;
const tallerElementHeight = 280 - 27 - elements[indexElementTaller]._model.y;
if (tallerElementHeight < 30) {
y += -20;
}
y += elements[indexElementTaller]._model.y;
} else {
x += elements[0]._model.x;
y += elements[0]._model.y;
}
y += -20;
return { x, y };
};
Chart.controllers.CustomerRetention = Chart.controllers.bar.extend({
draw(ease) {
Chart.controllers.bar.prototype.draw.call(this, ease);
const customOptions: any = this.chart.options.custom;
const tooltipTitleData: any[] = this.chart.tooltip._options.titles;
const ctx = this.chart.chart.ctx;
ctx.clearRect(0, this.chart.height - 37, 1000, 22);
},
});
} catch (e) {
console.error(e);
}
}
}
我想你可以尝试使用 RectangleElement 的方法 extend
,还有 BarController,添加 属性 dataElementType
,像这样:
const rectangleElement = Chart.elements.Rectangle;
const otherRectangleElement = rectangleElement.extend({
draw() {
const ctx = this._chart.ctx;
// ...
}
}
Chart.defaults.CustomerRetention = Chart.defaults.bar;
Chart.controllers.CustomerRetention = Chart.controllers.bar.extend({
dataElementType: otherRectangleElement,
draw(ease) {
Chart.controllers.bar.prototype.draw.call(this, ease);
// ...
}
}
我在不同的组件中创建了 2 个图表,这 2 个图表在同一页面(同一组件)中使用。图表有不同的逻辑和风格,调试图表我意识到绘图功能正在影响另一个图表,反之亦然。 这两个图表都有绘图功能,并且正在从 'chart-js' 导入图表,有人知道我如何在绘图功能中区分这些图表吗? 我已经尝试查询选择器图表并执行 if 检查绘制函数检查 id 但它不起作用
绘制方法如下
private customizeChartJs() {
const el = this.hostElement.nativeElement.querySelector('#customerRetention');
if (el) {
try {
Chart.elements.Rectangle.prototype.draw = function () {
console.log(this._chart);
const ctx = this._chart.ctx;
console.log();
const vm = this._view;
let left;
let right;
let top;
let bottom;
let signX;
let signY;
let borderSkipped;
let borderWidth = vm.borderWidth;
let nextCornerId;
let nextCorner;
let width;
let height;
let x;
let y;
const roundedCorner = this._chart.options.roundedCorner;
// Set Radius Here
const cornerRadius = 10;
// If radius is large enough to cause drawing errors a max radius is imposed
if (!vm.horizontal) {
// bar
left = vm.x - vm.width;
right = vm.x + vm.width / 2;
top = vm.y;
bottom = vm.base;
signX = 5;
signY = bottom > top ? 1 : -1;
borderSkipped = vm.borderSkipped || 'bottom';
} else {
// horizontal bar
left = vm.base;
right = vm.x;
top = vm.y - vm.height / 2;
bottom = vm.y + vm.height / 2;
signX = right > left ? 1 : -1;
signY = 1;
borderSkipped = vm.borderSkipped || 'left';
}
// 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 (borderWidth) {
// borderWidth shold be less than bar width and bar height.
const barSize = Math.min(Math.abs(left - right), Math.abs(top - bottom));
borderWidth = borderWidth > barSize ? barSize : borderWidth;
const halfStroke = borderWidth / 2;
// Adjust borderWidth when bar top position is near vm.base(zero).
const borderLeft = left + (borderSkipped !== 'left' ? halfStroke * signX : 0);
const borderRight = right + (borderSkipped !== 'right' ? -halfStroke * signX : 0);
const borderTop = top + (borderSkipped !== 'top' ? halfStroke * signY : 0);
const borderBottom = bottom + (borderSkipped !== 'bottom' ? -halfStroke * signY : 0);
// not become a vertical line?
if (borderLeft !== borderRight) {
top = borderTop;
bottom = borderBottom;
}
// not become a horizontal line?
if (borderTop !== borderBottom) {
left = borderLeft;
right = borderRight;
}
}
ctx.beginPath();
ctx.strokeStyle = vm.borderColor;
ctx.lineWidth = borderWidth;
ctx.fillStyle = vm.backgroundColor;
// Corner points, from bottom-left to bottom-right clockwise
// | 1 2 |
// | 0 3 |
const corners = [
[left, bottom],
[left, top],
[right, top],
[right, bottom],
];
// Find first (starting) corner with fallback to 'bottom'
const borders = ['bottom', 'left', 'top', 'right'];
let startCorner = borders.indexOf(borderSkipped, 0);
if (startCorner === -1) {
startCorner = 0;
}
function cornerAt(index) {
return corners[(startCorner + index) % 4];
}
// Draw rectangle from 'startCorner'
let corner = cornerAt(0);
ctx.moveTo(corner[0], corner[1]);
for (let i = 1; i < 4; i++) {
corner = cornerAt(i);
nextCornerId = i + 1;
if (nextCornerId === 4) {
nextCornerId = 0;
}
nextCorner = cornerAt(nextCornerId);
width = corners[2][0] - corners[1][0];
height = corners[0][1] - corners[1][1];
x = corners[1][0];
y = corners[1][1];
let radius = cornerRadius;
// Fix radius being too large
if (radius > height / 2) {
radius = height / 2;
}
if (radius > width / 2) {
radius = width / 2;
}
if (!vm.horizontal) {
ctx.beginPath();
ctx.moveTo(x + radius, y);
ctx.lineTo(x + width - radius, y);
ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
ctx.lineTo(x + width, y + height);
ctx.lineTo(x, y + height);
ctx.lineTo(x, y);
ctx.quadraticCurveTo(x, y, x, y);
ctx.closePath();
} else if (vm.horizontal && !roundedCorner) {
ctx.moveTo(x + radius, y);
ctx.lineTo(x + width - radius, y);
ctx.lineTo(x + width, y, x + width, y + radius);
ctx.lineTo(x + width, y + height - radius);
ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
ctx.lineTo(x + radius, y + height);
ctx.lineTo(x, y + height, x, y + height - radius);
ctx.lineTo(x, y + radius);
ctx.lineTo(x, y, x + radius, y);
} else {
ctx.moveTo(x + radius, y);
ctx.lineTo(x + width - radius, y);
ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
ctx.lineTo(x + width, y + height - radius);
ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
ctx.lineTo(x + radius, y + height);
ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
ctx.lineTo(x, y + radius);
ctx.quadraticCurveTo(x, y, x + radius, y);
}
}
ctx.fill();
if (borderWidth) {
ctx.stroke();
}
};
Chart.defaults.CustomerRetention = Chart.defaults.bar;
Chart.Tooltip.positioners.custom = (elements, position) => {
if (!elements.length) {
return false;
}
const { forceFirstTooltipsToLeft } = elements[0]._chart.options.custom;
let x = -299;
let y = 0;
// primeiros 3 itens da esquerda precisam abrir tooltip pra direita
if (forceFirstTooltipsToLeft && elements[0]._index < 3) {
x = 10;
} else {
const maxIndex = elements[0]._xScale.maxIndex;
if (maxIndex > 9 && elements[0]._index < 3) {
x = 10;
}
}
if (elements.length > 1) {
let indexElementTaller: number;
x += elements[0]._model.x;
indexElementTaller = elements[0]._model.y <= elements[1]._model.y ? 0 : 1;
const tallerElementHeight = 280 - 27 - elements[indexElementTaller]._model.y;
if (tallerElementHeight < 30) {
y += -20;
}
y += elements[indexElementTaller]._model.y;
} else {
x += elements[0]._model.x;
y += elements[0]._model.y;
}
y += -20;
return { x, y };
};
Chart.controllers.CustomerRetention = Chart.controllers.bar.extend({
draw(ease) {
Chart.controllers.bar.prototype.draw.call(this, ease);
const customOptions: any = this.chart.options.custom;
const tooltipTitleData: any[] = this.chart.tooltip._options.titles;
const ctx = this.chart.chart.ctx;
ctx.clearRect(0, this.chart.height - 37, 1000, 22);
},
});
} catch (e) {
console.error(e);
}
}
}
我想你可以尝试使用 RectangleElement 的方法 extend
,还有 BarController,添加 属性 dataElementType
,像这样:
const rectangleElement = Chart.elements.Rectangle;
const otherRectangleElement = rectangleElement.extend({
draw() {
const ctx = this._chart.ctx;
// ...
}
}
Chart.defaults.CustomerRetention = Chart.defaults.bar;
Chart.controllers.CustomerRetention = Chart.controllers.bar.extend({
dataElementType: otherRectangleElement,
draw(ease) {
Chart.controllers.bar.prototype.draw.call(this, ease);
// ...
}
}