gpt4 book ai didi

javascript - 使用chart.js在 donut chart 中心的事件处理程序

转载 作者:行者123 更新时间:2023-12-03 23:04:18 25 4
gpt4 key购买 nike

我在页面上创建了4个甜甜圈图,该页面的中心有一些文本,我知道可以通过在中心放置DIV来完成此操作,但是由于图表下载为PNG :

演示:https://jsfiddle.net/cmyker/ooxdL2vj/

为此,我需要跟踪我使用pageX,pageY来确定是否在中间部分进行单击的中心文本的点击。

坐标是在甜甜圈图的中心孔内的矩形部分的角,并且可能包含文本。

jQuery('#canvas').on('click',function(e){
var pageX = e.pageX;
var pageY = e.pageY;
if((pageY >= 379 && pageY <= 571) && (pageX >= 440 && pageX <= 629)){ //coordinates are of rectangular area which has text inside the center of doughnut chart.
//do something
}
});

但是如果屏幕的分辨率不同(因为坐标会变化),则此方法将无效。

有任何想法吗?

我尝试使用raphael.js使中心可点击,但是对此尝试不太确定。
我正在尝试使用 container方法在甜甜圈的中心孔中创建一个圆形,可以在其上附加单击处理程序。

使用 的代码信息Raphael JS
Chart.pluginService.register({
beforeDraw: function(chart) {
if(chart['data']['midNum']){
var width = chart.chart.width,
height = chart.chart.height,
ctx = chart.chart.ctx;

ctx.restore();
var fontSize = (height / 114).toFixed(2);
ctx.font = fontSize + "em sans-serif";
ctx.textBaseline = "middle";

var text = chart['data']['midNum'],
textX = Math.round((width - ctx.measureText(text).width) / 2),
textY = height / 2.5;
var chartID = chart['chart']['canvas']['id']; //the ID of element on which this donut was created

var paper = Raphael(chartID,textX,textY); //trying to use the container approach
var circle = paper.circle(textX, textY, 10);
circle.attr("fill", "#f00");
//ctx.clearRect(0,0,width,height);
//ctx.fillText(text, textX, textY);
//ctx.save();
}
}
})

最佳答案

这是对有关this code的原始问题的解答。自发布以来,该问题已多次更改-添加了另存为PNG的要求,图表的数量从原始代码中的1更改为4,并且使用的框架从HTML Canvas上的Chart.js渲染更改为SVG上的Raphaël渲染。我离开了我发布的解决方案,希望它对将来的某人有用。

我在这里没有什么主意:

寻找像素

一种较慢但肯定的方法:知道您对黑色像素感兴趣,可以遍历 Canvas 的所有像素并记住4个数字:找到的任何黑色像素的最小和最大x和y坐标。您可以为此添加一些边距,并且即使在将来的版本中库开始在其他位置写入文本时,也可以始终看到一个矩形。

重新绘制 Canvas 后,每次调整窗口大小时都必须重新计算它。

为此,您的文本必须使用 Canvas 上其他任何地方都没有的颜色(目前是这种情况)。

猜测坐标

您可以猜测坐标-或更精确地计算它们-知道如何绘制。似乎大圆圈在较小的维度上占据了整个空间(在这种情况下为整个高度),并且在另一个轴上居中(在这种情况下,它在水平方向上居中)。

使用该知识,您可以通过类似于以下方式来计算仅具有 Canvas 尺寸的内(白色)圆的大小和位置:

查找 Canvas 的宽度或高度较小,并将其用作基数。将其除以2将得到R-大圆的半径。划分R/2可以大致得到r-内部小的白色圆圈的半径。计算xy- Canvas 中心的坐标-x = width/2y = height /2

现在,您可以尝试使用文本所在的矩形。它可能类似于:左边和右边的x - 0.7*rx + 0.7*r,下面和上面的边缘的y - 0.4*ry + 0.4*r。这些仅是示例,您可以使这些数字满足您的要求。

这些数字不一定是完美的,因为无论如何您应该在文本周围留出几个像素的空白。

在这种情况下,当库将来开始完全不同地绘制它时,它可能无法工作,但对于像这样的简单图表来说可能就不行了。

好消息是,您不必寻找特定的颜色,并且计算将比检查每个像素更快。

同样,如果以其他大小重绘了图表,则必须重新计算这些尺寸。

更改您的pluginService

另一个想法是更改pluginServicebeforeDraw函数,以便保存已经拥有的数字。

特别是,您已经具有:

textX = Math.round((width - ctx.measureText(text).width) / 2),
textY = height / 2;

如果将其更改为:
var measured = ctx.measureText(text);
textX = Math.round((width - measured.width) / 2),
textY = height / 2;

(为避免以后重新计算文本尺寸),您可以在以下位置存储以下数字:

要么 textXtextY连同 measured.widthmeasured.height,要么是一个具有以下属性的对象:
var textPos = {
x1: textX,
y1: textY,
x2: textX + measured.width,
y2: textY + measured.height
}

如果需要,请确保使用舍入。例如,您可以将该对象存储在某些全局对象中,或作为某些HTML元素的 data-*属性存储(例如在 Canvas 本身上)。

最后一个解决方案很好,因为您不必担心颜色,也不必猜测文本的放置位置,因为您确切地知道该内容,也不必担心在调整大小时重新计算该值,因为该代码在每次绘制文本本身时运行。

缺点是您需要修改 pluginService

Canvas 上的div

另一种方法是将div放在 Canvas 上,然后将文本放在该div中而不是在 Canvas 中。这样,您便可以轻松添加事件侦听器等。

您可以执行以下操作:

将 Canvas 和空div(或更多div)放入更大的div中:
<div id="chart">
<canvas id="myChart"></canvas>
<div class="chart-text" id="text1"></div>
</div>

您可以添加更多的div(例如text1)来获得更多的圈子/图表,如下所示:
<div id="chart">
<canvas id="myChart"></canvas>
<div class="chart-text" id="text1"></div>
<div class="chart-text" id="text2"></div>
</div>

添加此CSS以使其正确堆叠:
#chart { position: relative; }
.chart-text { position: absolute; }

现在,您将文本添加到该内部div中,而不是在 Canvas 上绘制文本:
var text1 = document.getElementById('text1');
text1.addEventListener("click", function (e) {
alert("CLICKED!");
});

Chart.pluginService.register({
beforeDraw: function(chart) {
var width = chart.chart.width,
height = chart.chart.height;

var fontSize = (height / 114).toFixed(2);
text1.style.font = fontSize + "em sans-serif";

var text = "75%";
text1.innerText = text;
var r = text1.getBoundingClientRect();
text1.style.left = ((width-r.width)/2)+"px";
text1.style.top = ((height-r.height)/2)+"px";
}
});

参见 DEMO

可以将其简化,但是将文本放入 Canvas 中可能更简单,并且可以使用事件侦听器或简单的CSS样式。例如添加:
.chart-text:hover { color: red; }

悬停时会变红。

在 Canvas 上的空div

在问题中未包含的注释中发布了其他要求之后,这是又一个更新。

您可以使用上述版本中的HTML:
<div id="chart">
<canvas id="myChart"></canvas>
<div class="chart-text" id="text1"></div>
</div>

但是这一次您可以在 Canvas 上添加一个空的div,以使文本包含在 Canvas 中,保存后将包含文本。

这是所需的CSS:
#chart { position: relative; }
.chart-text { position: absolute; }

这是CSS,它将向您显示不可见div的位置:
#chart { position: relative; }
.chart-text { position: absolute; border: 1px solid red; }

现在,将div放置在应有的代码:
var text1 = document.getElementById('text1');
text1.addEventListener("click", function (e) {
alert("CLICKED!");
});

Chart.pluginService.register({
beforeDraw: function(chart) {
var width = chart.chart.width,
height = chart.chart.height,
ctx = chart.chart.ctx;

ctx.restore();
var fontSize = (height / 114).toFixed(2);
ctx.font = fontSize + "em sans-serif";
ctx.textBaseline = "middle";

var text = "75%",
m = ctx.measureText(text),
textX = Math.round((width - m.width) / 2),
textY = height / 2;

var emInPx = 16;
text1.style.left = textX + "px";
text1.style.top = (textY - fontSize*emInPx/2) + "px";
text1.style.width = m.width + "px";
text1.style.height = fontSize+"em";

ctx.fillText(text, textX, textY);
ctx.save();
}
});

确保 emInPx每1个 px单位具有正确的 em数(CSS像素)。您以 fontSize单位定义 em,我们需要像素来计算正确的位置。

参见 DEMO
(它有一个红色边框,使div可见-只需从CSS删除 border: 1px solid red;使其消失即可)

Canvas 上的大空div

另一个示例-这次的div大于文本:
var text1 = document.getElementById('text1');
text1.addEventListener("click", function (e) {
alert("CLICKED!");
});

Chart.pluginService.register({
beforeDraw: function(chart) {
var width = chart.chart.width,
height = chart.chart.height,
ctx = chart.chart.ctx;

ctx.restore();
var fontSize = (height / 114).toFixed(2);
ctx.font = fontSize + "em sans-serif";
ctx.textBaseline = "middle";

var text = "75%",
m = ctx.measureText(text),
textX = Math.round((width - m.width) / 2),
textY = height / 2;

var d = Math.min(width, height);
var a = d/2.5;

text1.style.left = ((width - a) / 2) + "px";
text1.style.top = ((height - a) / 2) + "px";
text1.style.width = a + "px";
text1.style.height = a + "px";

ctx.fillText(text, textX, textY);
ctx.save();
}
});

参见 DEMO
它不取决于 em中的 px大小和文本大小。
这条线改变了正方形的大小:
var a = d / 2.5;

您可以尝试将2.5更改为2或3或其他。

在 Canvas 上舍入空div

这是一种使用 border-radius而不是矩形的圆形div的变体,并且似乎完美地填充了内部白色圆圈。

HTML:
<div id="chart">
<canvas id="myChart"></canvas>
<div class="chart-text" id="text1"></div>
</div>

CSS:
#chart, #myChart, .chart-text {  padding: 0; margin: 0; }
#chart { position: relative; }
.chart-text { position: absolute; border-radius: 100%; }

JS:
var text1 = document.getElementById('text1');
text1.addEventListener("click", function (e) {
alert("CLICKED!");
});

Chart.pluginService.register({
beforeDraw: function(chart) {
var width = chart.chart.width,
height = chart.chart.height,
ctx = chart.chart.ctx;

ctx.restore();
var fontSize = (height / 114).toFixed(2);
ctx.font = fontSize + "em sans-serif";
ctx.textBaseline = "middle";

var text = "75%",
m = ctx.measureText(text),
textX = Math.round((width - m.width) / 2),
textY = height / 2;

var d = Math.min(width, height);
var a = d / 2;

text1.style.left = (((width - a) / 2 - 1)|0) + "px";
text1.style.top = (((height - a) / 2 - 1)|0) + "px";
text1.style.width = a + "px";
text1.style.height = a + "px";

ctx.fillText(text, textX, textY);
ctx.save();
}
});

参见 DEMO

关于javascript - 使用chart.js在 donut chart 中心的事件处理程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38243032/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com