图表js - 绘制气泡图的每个气泡的中心

时间:2017-05-29 15:16:52

标签: javascript meteor charts chart.js

我有一个带大气泡的气泡图。我想画一个十字架或每个泡泡中心的任何东西,但我找不到任何解决方案。下图显示了上下文:

bubble chart

我在流星上使用Chart.js 2.5.0。

2 个答案:

答案 0 :(得分:2)

我的问题对我来说似乎很有趣,因此,我构建了以下chartjs插件,这将有助于满足您的要求。

Chart.plugins.register({
   afterDraw: c => {
      let datasets = c.data.datasets;
      datasets.forEach((e, i) => {
         let isHidden = e._meta[0].hidden;
         if (!isHidden) {
            let data = c.getDatasetMeta(i).data;
            data.forEach(e => {
               let ctx = c.chart.ctx;
               let x = e._model.x;
               let y = e._model.y;
               let r = e._model.radius;

               // draw a cross
               // or you can draw anything using general canvas methods
               ctx.save();
               ctx.beginPath();
               ctx.moveTo(x - r / 4, y - r / 4);
               ctx.lineTo(x + r / 4, y + r / 4);
               ctx.moveTo(x + r / 4, y - r / 4);
               ctx.lineTo(x - r / 4, y + r / 4);
               ctx.strokeStyle = 'white';
               ctx.lineWidth = 2;
               ctx.stroke();
               ctx.restore();
            });
         }
      });
   }
});

<强>ᴅᴇᴍᴏ

Chart.plugins.register({
   afterDraw: c => {
      let datasets = c.data.datasets;
      datasets.forEach((e, i) => {
         let isHidden = e._meta[0].hidden;
         if (!isHidden) {
            let data = c.getDatasetMeta(i).data;
            data.forEach(e => {
               let ctx = c.chart.ctx;
               let x = e._model.x;
               let y = e._model.y;
               let r = e._model.radius;
               
               // draw a cross
               // or you can draw anything using general canvas methods
               ctx.save();
               ctx.beginPath();
               ctx.moveTo(x - r / 4, y - r / 4);
               ctx.lineTo(x + r / 4, y + r / 4);
               ctx.moveTo(x + r / 4, y - r / 4);
               ctx.lineTo(x - r / 4, y + r / 4);
               ctx.strokeStyle = 'white';
               ctx.lineWidth = 2;
               ctx.stroke();
               ctx.restore();
            });
         }
      });
   }
});

let ctx = document.querySelector('#c').getContext('2d');
let chart = new Chart(ctx, {
   type: 'bubble',
   data: {
      labels: ['Jan', 'Feb', 'Mar'],
      datasets: [{
         label: 'John',
         data: [
            { x: 5, y: 5, r: 10 },
            { x: 10, y: 10, r: 15 },
            { x: 16, y: 15, r: 18 }
         ],
         backgroundColor: '#76d1bf'
      }, {
         label: 'Smith',
         data: [
            { x: 3, y: 10, r: 10 },
            { x: 7, y: 11, r: 15 },
            { x: 12, y: 6, r: 18 }
         ],
         backgroundColor: '#827ada'
      }]
   },
   options: {
      responsive: false,
      scales: {
         xAxes: [{
            ticks: {
               min: 2,
               max: 18,
               stepSize: 4
            }
      	 }],
         yAxes: [{
            ticks: {
               min: 0,
               max: 20,
               stepSize: 4
            }
      	 }]
      }
   }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js"></script>
<canvas id="c" height="200"></canvas>

答案 1 :(得分:1)

Chart.js一直是一个非常直接和简单的库。其中一个优点是易于定制。这也是JavaScript的优点之一,源代码始终可用于您使用的库。

有一种回归定制方式。一旦您对库进行了更改,您将不得不使用该特定版本,因为自定义不是作者在进行更改时会考虑的。

因此,要使用下面的代码,您应该转到github page并下载项目并将该版本的chart.js用于您的站点。我没有更改原始版本,大部分时间每个自定义都针对特定情况而且代码是在客户端自定义的。

变化很简单。首先备份绘制点的函数

Chart.canvasHelpers.defaultDrawPoint = Chart.canvasHelpers.drawPoint;

这样做就可以将您不感兴趣的所有调用传递回标准处理程序。

接下来,通过替换刚刚备份的函数来编写拦截代码。

Chart.canvasHelpers.drawPoint = function(ctx, pointStyle, radius, x, y){

查看原始源代码,您可以弄清楚它是如何绘制圆圈的,只是将所有其他参数变体的行为传递给原始代码。

如果pointStyle未定义或===“circle”你处理你的自我

    // pointStyle undefined is default 
    // pointStyle === "circle" is the default named style
    if(pointStyle === undefined || pointStyle === "circle"){

        // next 4 lines copied from the source
        ctx.beginPath();
        ctx.arc(x, y, radius, 0, Math.PI * 2);
        ctx.closePath();
        ctx.fill();   

然后添加自定义代码以呈现您喜欢的内容。保存当前的2D上下文非常重要,因为您不必担心会破坏某些内容。

        // draw a cross

        ctx.save();  // save the state
        ctx.strokeStyle = "white";
        ctx.strokeWidth = 4;
        ctx.beginPath();
        ctx.moveTo(x - radius *0.3, y - radius *0.3);
        ctx.lineTo(x + radius *0.3, y + radius *0.3);
        ctx.moveTo(x + radius *0.3, y - radius *0.3);
        ctx.lineTo(x - radius *0.3, y + radius *0.3);
        ctx.stroke();

然后恢复2D上下文的状态

        ctx.restore(); // restore the state

else会处理您不感兴趣的标准电话

    }else{  // all other styles pass on to default handler
        Chart.canvasHelpers.defaultDrawPoint(ctx, pointStyle, radius, x, y);
    }

对于Chart.js,这特别有用,因为它提供了一种自定义和获取动画的方法。

Chart.canvasHelpers.defaultDrawPoint = Chart.canvasHelpers.drawPoint;
Chart.canvasHelpers.drawPoint = function(ctx, pointStyle, radius, x, y){
    // PointStyle undefined is default 
    // PointStyle === "circle" is the default named style
    if(pointStyle === undefined || pointStyle === "circle"){
    
        ctx.beginPath();
        ctx.arc(x, y, radius, 0, Math.PI * 2);
        ctx.closePath();
        ctx.fill();   
        
        // custom code here
        ctx.save();  // save the state
        ctx.strokeStyle = "white";
        ctx.strokeWidth = 4;
        ctx.beginPath();
        ctx.moveTo(x - radius *0.3, y - radius *0.3);
        ctx.lineTo(x + radius *0.3, y + radius *0.3);
        ctx.moveTo(x + radius *0.3, y - radius *0.3);
        ctx.lineTo(x - radius *0.3, y + radius *0.3);
        ctx.stroke();
        ctx.restore(); // restor the state
        
    }else{  // all other styles pass on to default handler
        Chart.canvasHelpers.defaultDrawPoint(ctx, pointStyle, radius, x, y);
    }
}

// some utils to add data
// returns a random int
const rand = (min, max = min + (min = 0))=> Math.floor( Math.random() * (max-min) + min);    
// returns a random data point {x,y,r}
const randData = ()=>({x : rand(0,50), y: rand(5,50), r: rand(4,20)});
// create a chart.
const ctx = canvas.getContext("2d");
const chart = new Chart(ctx, {
   type: "bubble",
   data: {
      datasets: [{
         label: "Random Data",
         backgroundColor: "#7AF",
         data: (()=>{
            var dat = [];
            for(var i = 0; i < 10; i++){ dat.push(randData()) }
            return dat;
         })(),
      }]
   },
   options: { responsive: false } // this is required to work or it throws
                                  // not sure why by it is not due to the
                                  // changes
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js"></script>
<canvas id=canvas height=200 width=400></canvas>

要回滚更改,只需将功能设置回原始状态。

Chart.canvasHelpers.drawPoint = Chart.canvasHelpers.defualtDrawPoint;

删除额外的参考

Chart.canvasHelpers.defualtDrawPoint = undefined;