基本上我正在尝试实现与这个问题完全相同但在 V4 中: Chartjs饼图,径向位移(偏移量)_
此代码答案在 v2.6 中有效,任何人都可以指导我使用 v4 的格式吗。
Chart.defaults.cutOutPie = Chart.helpers.clone(Chart.defaults.pie);
Chart.controllers.cutOutPie = Chart.controllers.pie.extend({
updateElement: function(arc, index, reset) {
Chart.controllers.pie.prototype.updateElement.call(this, arc, index, reset);
var displacement = this.getDataset().displacements[index]||0;
var model = arc._model;
var angle = model.startAngle + model.circumference/2;
model.x += Math.cos(angle) * displacement;
model.y += Math.sin(angle) * displacement;
}
});
new Chart('chart', {
type: 'cutOutPie',
data: {
labels: ['a', 'b', 'c', 'd', 'e', 'f'],
datasets: [{
data: [1, 7, 2, 8, 3, 9],
backgroundColor: ['red', 'orange', 'green', 'gold', 'pink', 'blue'],
displacements: [0, 0, 40, 0, 0, 16],
}],
},
});
<script src="//cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js"></script>
<canvas id="chart" width="400" height="300"></canvas>
如果我在 React 或 Vue 中打包构建,我知道该怎么做,但不知道如何在浏览器中做同样的事情。
文档似乎只谈论导入和类。
javascript v4,使用 ecmascript 类,因此自定义控制器应该是现有控制器的子类,覆盖相关方法,如文档“新图表”部分中所述。
因此,旧代码的类比是:
const PieController = Chart.controllers.pie;
class CutOutPie extends PieController{
static id = 'cutOutPie';
updateElement(arc, index, properties, mode) {
const displacement = this.getDataset().displacements?.[index] || 0;
if(displacement && properties.circumference){
const angle = properties.startAngle + properties.circumference/2;
properties.x += displacement * Math.cos(angle);
properties.y += displacement * Math.sin(angle);
}
if(properties.outerRadius){
properties.outerRadius -= Math.max(...this.chart.data.datasets[0].displacements);
}
super.updateElement(arc, index, properties, mode);
}
}
Chart.register(CutOutPie);
new Chart('chart', {
type: 'cutOutPie',
data: {
labels: ['a', 'b', 'c', 'd', 'e', 'f'],
datasets: [{
data: [1, 7, 2, 8, 3, 9],
backgroundColor: ['red', 'orange', 'green', 'gold', 'pink', 'blue'],
displacements: [0, 0, 40, 0, 0, 26],
}]
},
options:{
responsive: true,
animation:{
duration: 500,
animateRotate: true,
animateScale: true
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.1.2/chart.umd.js"
integrity="sha512-t41WshQCxr9T3SWH3DBZoDnAT9gfVLtQS+NKO60fdAwScoB37rXtdxT/oKe986G0BFnP4mtGzXxuYpHrMoMJLA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<body>
<div style="height:500px; width: 500px">
<canvas id="chart" style="border: 1px solid #999"></canvas>
</div>
这里有一个稍微复杂的版本,它预先计算位移并考虑标准动画:
const PieController = Chart.registry.controllers.get('pie');
//this seems to be the most general way to get the controller class
// alternatives, depending on environment:
// PieController = Chart.PieController;
// PieController = Chart.controllers.pie;
// import {PieController} from 'chart.js';
class CutOutPie extends PieController{
static id = 'cutOutPie';
static defaults = {
displacements: []
}
initialize(){
super.initialize();
this._displacementOffset = 0;
this._offsetsValid = false;
this._arcProperties = [];
}
updateElements(arcs, start, count, mode){
this._offsetsValid = false;
this._arcProperties = [];
super.updateElements(arcs, start, count, mode);
if(!this._offsetsValid){
this._computeDisplacementOffsets(arcs);
for(let i = start; i < start + count; i++){
this.updateElement(arcs[i], i, {}, mode);
}
}
}
_computeDisplacementOffsets(arcs){
if(Number.isFinite(this._arcProperties?.[0]?.outerRadius)){
let startAngle = this._getRotation();
for(let i = 0; i < arcs.length; i++){
const displacement = this.getDataset().displacements?.[i] || 0;
const endAngle = startAngle + this._circumference(i);
this._arcProperties[i] = Object.assign(this._arcProperties[i] || {}, {dx: 0, dy: 0, shrink: 1});
if(displacement){
const angle = (startAngle + endAngle)/2;
this._arcProperties[i].dx = Math.cos(angle) * displacement;
this._arcProperties[i].dy = Math.sin(angle) * displacement;
this._displacementOffset = Math.max(this._displacementOffset, displacement);
}
startAngle = endAngle;
}
for(let i = 0; i < arcs.length; i++){
const outerRadius = this._arcProperties[i].outerRadius || this.outerRadius;
if(outerRadius){
this._arcProperties[i].shrink = (outerRadius - this._displacementOffset)/outerRadius ;
}
}
this._offsetsValid = true;
}
}
updateElement(arc, index, properties, mode) {
this._arcProperties[index] = this._arcProperties[index] || {};
Object.assign(this._arcProperties[index], properties || {});
const animation = this.options.animation.animateRotate || this.options.animation.animateScale;
if(this._offsetsValid){
if(mode !== 'reset' || !animation){
if(this._arcProperties[index].hasOwnProperty('dx')){
this._arcProperties[index].x += this._arcProperties[index].dx;
}
if(this._arcProperties[index].hasOwnProperty('dy')){
this._arcProperties[index].y += this._arcProperties[index].dy;
}
arc.x = this._arcProperties[index].x - this._arcProperties[index].dx;
arc.y = this._arcProperties[index].y - this._arcProperties[index].dy;
}
const shrink = this._arcProperties[index].shrink;
if(shrink){
this._arcProperties[index].outerRadius *= shrink;
this._arcProperties[index].innerRadius *= shrink;
}
super.updateElement(arc, index, this._arcProperties[index], mode);
}
}
}
Chart.register(CutOutPie);
new Chart('chart', {
type: 'cutOutPie',
data: {
labels: ['a', 'b', 'c', 'd', 'e', 'f'],
datasets: [{
data: [1, 7, 2, 8, 3, 9],
backgroundColor: ['red', 'orange', 'green', 'gold', 'pink', 'blue'],
displacements: [0, 0, 40, 0, 0, 26],
}]
},
options:{
responsive: true,
animation:{
duration: 500,
animateRotate: true,
animateScale: true
}
}
});
<div style="height:500px; width: 500px">
<canvas id="chart" style="border: 1px solid #999"></canvas>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.1.2/chart.umd.js"
integrity="sha512-t41WshQCxr9T3SWH3DBZoDnAT9gfVLtQS+NKO60fdAwScoB37rXtdxT/oKe986G0BFnP4mtGzXxuYpHrMoMJLA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>