tec*_*_28 5 javascript jquery charts canvas raphael
我在页面上创建了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
}
});
Run Code Online (Sandbox Code Playgroud)
但是,如果屏幕的分辨率不同(坐标会变化),则此方法将无效。
有任何想法吗?
我尝试使用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();
}
}
})
Run Code Online (Sandbox Code Playgroud)
这是有关此代码的原始问题的答案。自发布以来,该问题已多次更改-添加了另存为PNG的要求,图表的数量从原始代码中的1更改为4,并且所使用的框架从HTML Canvas上的Chart.js呈现更改为SVG上的Raphaël渲染。我离开了我发布的解决方案,希望它对将来的某人有用。
我在这里没有什么主意:
一种较慢但确定的方法:知道您对黑色像素感兴趣,可以遍历画布的所有像素并记住4个数字:找到的任何黑色像素的最小和最大x和y坐标。您可以为此添加一些边距,并且即使在将来的版本中库开始在其他位置写入文本时,也将始终有一个矩形。
重新绘制画布后,每次调整窗口大小时都必须重新计算它。
为此,您的文本必须使用画布上其他任何地方都没有的颜色(目前是这种情况)。
您可以猜测坐标-或更精确地计算它们-了解如何绘制坐标。似乎大圆圈在较小的维度上占据了整个空间(在这种情况下为整个高度),并且在另一个轴上居中(在这种情况下,它在水平方向上居中)。
使用该知识,您可以通过类似于以下方式来计算仅具有画布尺寸的内(白色)圆的大小和位置:
查找画布的宽度或高度较小,并将其用作基数。将其除以2将得到R-大圆圈的半径。划分R/2将大致给您r-内部小的白色圆圈的半径。计算x和y坐标画布的中心- x = width/2和y = height /2。
现在,您可以尝试在其中放置文本的矩形。这可能是这样的:x - 0.7*r和x + 0.7*r左,右边缘y - 0.4*r以及y + 0.4*r对底部和顶部边缘。这些仅是示例,您可以使这些数字满足您的要求。
这些数字不一定是完美的,因为无论如何,您应该在文本周围留出几个像素的空白。
在这种情况下,当库将来开始完全不同地绘制它时,它可能无法工作,但对于像这样的简单图表来说可能就不会。
好消息是,您不必寻找特定的颜色,并且计算将比检查每个像素更快。
同样,如果以其他大小重绘了图表,则必须重新计算这些尺寸。
另一个想法是更改您pluginService的beforeDraw功能,以便保存已经拥有的数字。
特别是,您已经具有:
textX = Math.round((width - ctx.measureText(text).width) / 2),
textY = height / 2;
Run Code Online (Sandbox Code Playgroud)
如果将其更改为:
var measured = ctx.measureText(text);
textX = Math.round((width - measured.width) / 2),
textY = height / 2;
Run Code Online (Sandbox Code Playgroud)
(只是为了避免以后重新计算文本尺寸),您可以在以下位置存储以下数字:
无论是刚textX和textY一起measured.width与measured.height或可能与以下属性的对象:
var textPos = {
x1: textX,
y1: textY,
x2: textX + measured.width,
y2: textY + measured.height
}
Run Code Online (Sandbox Code Playgroud)
如果需要,请确保使用舍入。例如,您可以将该对象存储在某些全局对象中,或作为data-*某些HTML元素的属性存储(例如在画布本身上)。
最后一个解决方案很好,因为您不必担心颜色,也不必猜测文本的放置位置,因为您知道的非常清楚,也不必担心调整大小时会重新计算该值,因为该代码在每次绘制文本本身时运行。
缺点是您需要修改pluginService。
另一种方法是将div放在画布上,然后将文本放在该div中而不是在画布中。这样,您便可以轻松添加事件侦听器等。
您可以执行以下操作:
将画布和空div(或更多div)放入更大的div中:
<div id="chart">
<canvas id="myChart"></canvas>
<div class="chart-text" id="text1"></div>
</div>
Run Code Online (Sandbox Code Playgroud)
您可以添加更多的div(例如text1)来获得更多的圈子/图表,如下所示:
<div id="chart">
<canvas id="myChart"></canvas>
<div class="chart-text" id="text1"></div>
<div class="chart-text" id="text2"></div>
</div>
Run Code Online (Sandbox Code Playgroud)
添加此CSS以使其正确堆叠:
#chart { position: relative; }
.chart-text { position: absolute; }
Run Code Online (Sandbox Code Playgroud)
现在,您将文本添加到该内部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;
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";
}
});
Run Code Online (Sandbox Code Playgroud)
参见DEMO。
可以将其简化,但是将文本放在画布中可能更简单,并且可以使用事件侦听器或简单的CSS样式。例如添加:
.chart-text:hover { color: red; }
Run Code Online (Sandbox Code Playgroud)
悬停时会变红。
在问题中未包含的注释中发布了其他要求之后,这是又一个更新。
您可以使用上述版本中的HTML:
<div id="chart">
<canvas id="myChart"></canvas>
<div class="chart-text" id="text1"></div>
</div>
Run Code Online (Sandbox Code Playgroud)
但是这一次您可以在画布上添加一个空的div,这样,文本将包含在画布中,保存后将包含文本。
这是所需的CSS:
#chart { position: relative; }
.chart-text { position: absolute; }
Run Code Online (Sandbox Code Playgroud)
这是CSS,它将向您显示不可见div的位置:
#chart { position: relative; }
.chart-text { position: absolute; border: 1px solid red; }
Run Code Online (Sandbox Code Playgroud)
现在将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();
}
});
Run Code Online (Sandbox Code Playgroud)
确保每1 单位emInPx具有正确的px(CSS像素)位数em。您以fontSizein为em单位定义,我们需要像素来计算正确的位置。
参见DEMO
(它带有红色边框,使div可见-只需将其border: 1px solid red;从CSS中删除即可使其消失)
另一个示例-这次的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();
}
});
Run Code Online (Sandbox Code Playgroud)
参见DEMO。它不依赖于em大小px和文字大小。这条线改变了正方形的大小:
var a = d / 2.5;
Run Code Online (Sandbox Code Playgroud)
您可以尝试将2.5更改为2或3或其他。
这是一种变体,用于border-radius制作一个圆div而不是矩形,并且似乎完美地填充了内部白色圆圈。
HTML:
<div id="chart">
<canvas id="myChart"></canvas>
<div class="chart-text" id="text1"></div>
</div>
Run Code Online (Sandbox Code Playgroud)
CSS:
#chart, #myChart, .chart-text { padding: 0; margin: 0; }
#chart { position: relative; }
.chart-text { position: absolute; border-radius: 100%; }
Run Code Online (Sandbox Code Playgroud)
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();
}
});
Run Code Online (Sandbox Code Playgroud)
参见DEMO。
| 归档时间: |
|
| 查看次数: |
2600 次 |
| 最近记录: |