什么是在HTML5 Canvas中实现符号绘图库的正确方法?
我将一个符号绘图库从Java移植到Javascript。符号将被绘制到HTML5 Canvas对象中。符号具有坐标和形状(正方形,圆形,十字形等等),大小和颜色的属性。什么是在HTML5 Canvas中实现符号绘图库的正确方法?
我在Java中有这样一个工作符号绘图库多年。在Javascript中,我很难用颜色。通常用正确的形状和大小绘制符号,但并不总是使用正确的颜色。一个符号的颜色也可以“流血”到我正在绘制的其他东西,如图表轴(通常是黑色)。那么,我该如何绘制一个符号作为绘图的“原子”单位,以便对我绘制的其他东西没有副作用?我觉得我不理解路径和子路径的概念以及上下文存储的状态。我已经做了大量的搜索解决这个问题的方法,但没有找到任何可行的方法。
这里是我的符号库中的一些典型代码:
function plotSymbol(ctx, symbol, h, v, width, symcolor) {
var i;
if (width == 0) return;
if (symbol == Resources.PlotSymbolsEnum.SYMBOL_SQUARE) {
ctx.strokeStyle = symcolor;
ctx.strokeRect(h - width/2.0, v - width/2.0, width, width);
}
else if (symbol == Resources.PlotSymbolsEnum.SYMBOL_SQUAREFILLED) {
ctx.fillStyle = symcolor;
ctx.fillRect(h - width/2.0, v - width/2.0, width, width);
}
else if (symbol == Resources.PlotSymbolsEnum.SYMBOL_CIRCLE) {
var x = h - width/2;
var y = v - width/2;
drawCircle(ctx, x, y, width/2, 1, symcolor, false);
}
else if (symbol == Resources.PlotSymbolsEnum.SYMBOL_CIRCLEFILLED) {
var x = h - width/2;
var y = v - width/2;
drawCircle(ctx, x, y, width/2, 1, symcolor, true);
}
else if (symbol == Resources.PlotSymbolsEnum.SYMBOL_DIAMOND) {
var xpoints1 = [ h, h + width/2, h, h - width/2 ];
var ypoints1 = [ v - width/2, v, v + width/2, v ];
ctx.strokeStyle = symcolor;
ctx.beginPath();
ctx.moveTo(xpoints1[0], ypoints1[0]);
for (i = 1; i < xpoints1.length; i++) {
ctx.lineTo(xpoints1[i], ypoints1[i]);
}
// ctx.closePath();
ctx.stroke();
ctx.strokeStyle = 'black';
}
else if (symbol == Resources.PlotSymbolsEnum.SYMBOL_DIAMONDFILLED) {
var xpoints2 = [ h, h + width/2, h, h - width/2 ];
var ypoints2 = [ v - width/2, v, v + width/2, v ];
ctx.fillStyle = symcolor;
ctx.beginPath();
ctx.moveTo(xpoints2[0], ypoints2[0]);
for (i = 1; i < xpoints2.length; i++) {
ctx.lineTo(xpoints2[i], ypoints2[i]);
}
// ctx.closePath();
ctx.fill();
ctx.stroke();
ctx.fillStyle = 'white';
}
else if (symbol == Resources.PlotSymbolsEnum.SYMBOL_TRIANGLE) {
var xpoints3 = [ h - width/2, h + width/2, h ];
var ypoints3 = [ v + width/2, v + width/2, v - width/2 ];
ctx.strokeStyle = symcolor;
ctx.beginPath();
ctx.moveTo(xpoints3[0], ypoints3[0]);
for (i = 1; i < xpoints3.length; i++) {
ctx.lineTo(xpoints3[i], ypoints3[i]);
}
// ctx.closePath();
ctx.stroke();
ctx.strokeStyle = 'black';
}
else if (symbol == Resources.PlotSymbolsEnum.SYMBOL_TRIANGLEFILLED) {
var xpoints3 = [ h - width/2, h + width/2, h ];
var ypoints3 = [ v + width/2, v + width/2, v - width/2 ];
ctx.strokeStyle = symcolor;
ctx.beginPath();
ctx.moveTo(xpoints3[0], ypoints3[0]);
for (i = 1; i < xpoints3.length; i++) {
ctx.lineTo(xpoints3[i], ypoints3[i]);
}
// ctx.closePath();
ctx.fill();
ctx.stroke();
ctx.strokeStyle = 'black';
}
else if (symbol == Resources.PlotSymbolsEnum.SYMBOL_CROSS1) {
ctx.strokeStyle = symcolor;
width += 1;
ctx.beginPath();
ctx.moveTo(h - width/2, v);
ctx.lineTo(h + width/2, v);
ctx.moveTo(h, v - width/2);
ctx.lineTo(h, v + width/2);
// ctx.closePath();
ctx.stroke();
ctx.strokeStyle = 'black';
}
else if (symbol == Resources.PlotSymbolsEnum.SYMBOL_CROSS2) {
ctx.strokeStyle = symcolor;
ctx.beginPath();
ctx.moveTo(h - width/2, v - width/2);
ctx.lineTo(h + width/2, v + width/2);
ctx.moveTo(h - width/2, v + width/2);
ctx.lineTo(h + width/2, v - width/2);
// ctx.closePath();
ctx.stroke();
ctx.strokeStyle = 'black';
}
}
我已经注释掉closepaths,因为我并不总是想要的形状返回到原点。我想我把它们放在最初是因为我误解了closePath()所做的事情,并认为它们会绘制独立于其他符号的符号。
这里是它如何被称为:
ctx.save();
ctx.rect(left, y1, width, height);
ctx.clip();
.
.
.
y = this.mMonthlyMeans[i];
y = (y - yOrigin) * yScale;
y = Math.floor(y) + 0.5;
plotSymbol(ctx, theMeanSym, this.getPlotLeft() + xCtr, y, theMeanSymSize, theMeanSymbolColor);
ctx.strokeStyle = 'black'; // this call is perhaps unnecessary in properly written code but seems to head off some problems
.
.
.
ctx.restore() // to restore the clip
我将不胜感激在HTML5画布正确地做这个有什么建议和指针。它似乎并不简单到只是绘制像素成Graphics2D对象,如Java,
你应该叫ctx.stroke()
或ctx.strokeXXX()
之前设置strokeStyle
,并且ctx.fill()
或ctx.fillXXX()
之前设置fillStyle
,在每个条件块的。
you missed strokeStyle
in SYMBOL_DIAMONDFILLED
block and fillStyle
in SYMBOL_TRIANGLEFILLED
block。
我相信我找到了解决方案。谷歌搜索今天我找到了一个教程(http://eloquentjavascript.net/16_canvas.html)绘制到画布对象。作者声明:
“一个路径可以包含多个形状 - 每moveTo运动开始一个新的。”
这是寻找的线索。我有使用moveTo和lineTo绘制交叉和x符号的方法。这是我的十字符号的代码(从Java移植)看了喜欢:
ctx.strokeStyle = symcolor;
ctx.beginPath();
ctx.moveTo(h - width/2, v);
ctx.lineTo(h + width/2, v);
ctx.moveTo(h, v - width/2);
ctx.lineTo(h, v + width/2);
ctx.stroke();
的错误是内部的moveTo开始一个新的子路径和冲程命令似乎仅使第一子路径中的StrokeStyle颜色或使用默认颜色。最终结果是大多数符号都以正确的颜色绘制,但是(我认为)最后一个符号是以默认的颜色绘制的,看起来是黑色的。
更改代码,使我行程段分别导致所有的符号在正确的颜色可以得出:
ctx.strokeStyle = symcolor;
ctx.beginPath();
ctx.moveTo(h - width/2, v);
ctx.lineTo(h + width/2, v);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(h, v - width/2);
ctx.lineTo(h, v + width/2);
ctx.stroke();
感谢您指出那些遗漏! –