JS 中的栅格图层 Canvas
Raster Layers in JS Canvas
我需要你的帮助来制作一个带有图层的小绘画应用程序。
我希望我的程序能够处理不同的层,但不使用多个 canvas 或使用外部库,以便更多地了解整个 canvas 的工作原理。
我想记住位于不同层对象的数组中的每个数据,而不是将它们从最低到最高打印在 canvas 上。问题是我想用手绘画,而不仅仅是用圆圈和正方形。如果我会记住我手绘的所有东西,那么它会很慢(已经尝试过)。
谢谢大家的帮助!
您当然可以仅使用一个 canvas 来应用非正式的 z-index。
并且您已经确定了一种正确的方法:
- 序列化("remember")所有绘图命令和参数。
- 清除 canvas.
- 按正确顺序重新绘制每一层上的所有多段线。
然后您可以重播那些保存的命令。显示将很快出现。
这是您的 Layer.draw
方法 的一个版本,它经过重构以获得更好的性能:
// draw() will define & stroke all polylines on this layer
// The 1st point in each polyline contains that line's styling
Layer.prototype.draw = function( ctx ) {
// just return if there's no points to draw
if(this.points.length<2){return;}
// cache an often used array
var pts=this.points;
// index for points
var i=0;
// process all points in the
while(i<pts.length){
// cache the often used first point in a new polyline
var p=pts[i];
// set styles for this polyline
ctx.lineWidth = p.lineWidth;
ctx.lineJoin = p.lineJoin;
ctx.lineCap = p.lineCap;
ctx.strokeStyle = p.strokeStyle;
// begin this polyline path
ctx.beginPath();
ctx.moveTo(p.x, p.y);
i++;
// define all segment points on this polyline
while( i<pts.length && pts[i].lineWidth==undefined ) {
ctx.lineTo( pts[i].x , pts[i].y );
i++;
}
// stroke this polyline
ctx.stroke();
} // end while(i<pts.length)
}
下面是示例代码和演示:
Point = function( x , y ) {
this.x = x;
this.y = y;
}
Point.prototype.invert = function() {
var t = this.x;
this.x = this.y;
this.y = t;
}
Layer = function() {
this.points = [];
}
Layer.prototype.draw = function( ctx ) {
// just return if there's no points to draw
if(this.points.length<2){return;}
// cache an often used array
var pts=this.points;
// index for points
var i=0;
// process all points in the
while(i<pts.length){
// cache the often used first point in a new polyline
var p=pts[i];
// set styles for this polyline
ctx.lineWidth = p.lineWidth;
ctx.lineJoin = p.lineJoin;
ctx.lineCap = p.lineCap;
ctx.strokeStyle = p.strokeStyle;
// begin this polyline path
ctx.beginPath();
ctx.moveTo(p.x, p.y);
i++;
// define all segment points on this polyline
while( i<pts.length && pts[i].lineWidth==undefined ) {
ctx.lineTo( pts[i].x , pts[i].y );
i++;
}
// stroke this polyline
ctx.stroke();
} // end while(i<pts.length)
}
ExtendedPoint = function( x , y , style ) {
this.x = x;
this.y = y;
this.lineWidth = style.lineWidth;
this.lineJoin = style.lineJoin;
this.lineCap = style.lineCap;
this.strokeStyle = style.strokeStyle;
}
function startLine( e ) {
var x = e.clientX - canvas.offsetLeft;
var y = e.clientY - canvas.offsetTop;
var p = new ExtendedPoint( x , y , {
lineWidth: 5,
lineJoin: "round",
lineCap: "round",
// testing only: make each new polyline a different color
// strokeStyle: "black"
strokeStyle: randomColor(),
});
selectedLayer.points.push(p);
isDrawing = true;
}
function continueLine( e ) {
if (isDrawing == true) {
var x = e.clientX - canvas.offsetLeft;
var y = e.clientY - canvas.offsetTop;
var p = new Point( x , y );
selectedLayer.points.push( p );
}
}
function endLine() {
isDrawing = false;
}
function redraw() {
context.clearRect( 0, 0, 400, 400 );
for ( var i = 0 ; i < layers.length ; i++ ) {
layers[i].draw( context );
}
}
var canvas = document.getElementById("cvs");
canvas.setAttribute("width" , 400);
canvas.setAttribute("height", 400);
var context = canvas.getContext("2d");
var layers = [];
layers.push( new Layer() );
var selectedLayer = layers[0];
var isDrawing = false;
canvas.addEventListener( "mousedown" , startLine );
canvas.addEventListener( "mousemove" , continueLine );
canvas.addEventListener( "mousemove" , redraw );
canvas.addEventListener( "mouseup" , endLine );
// testing only: make each polyline a different color
function randomColor(){
return('#'+Math.floor(Math.random()*16777215).toString(16));
}
body{ background-color: ivory; }
canvas{border:1px solid red;}
<h4>Drag to draw layered lines</h4>
<canvas id="cvs" width=400 height=400></canvas>
我需要你的帮助来制作一个带有图层的小绘画应用程序。 我希望我的程序能够处理不同的层,但不使用多个 canvas 或使用外部库,以便更多地了解整个 canvas 的工作原理。 我想记住位于不同层对象的数组中的每个数据,而不是将它们从最低到最高打印在 canvas 上。问题是我想用手绘画,而不仅仅是用圆圈和正方形。如果我会记住我手绘的所有东西,那么它会很慢(已经尝试过)。 谢谢大家的帮助!
您当然可以仅使用一个 canvas 来应用非正式的 z-index。
并且您已经确定了一种正确的方法:
- 序列化("remember")所有绘图命令和参数。
- 清除 canvas.
- 按正确顺序重新绘制每一层上的所有多段线。
然后您可以重播那些保存的命令。显示将很快出现。
这是您的 Layer.draw
方法 的一个版本,它经过重构以获得更好的性能:
// draw() will define & stroke all polylines on this layer
// The 1st point in each polyline contains that line's styling
Layer.prototype.draw = function( ctx ) {
// just return if there's no points to draw
if(this.points.length<2){return;}
// cache an often used array
var pts=this.points;
// index for points
var i=0;
// process all points in the
while(i<pts.length){
// cache the often used first point in a new polyline
var p=pts[i];
// set styles for this polyline
ctx.lineWidth = p.lineWidth;
ctx.lineJoin = p.lineJoin;
ctx.lineCap = p.lineCap;
ctx.strokeStyle = p.strokeStyle;
// begin this polyline path
ctx.beginPath();
ctx.moveTo(p.x, p.y);
i++;
// define all segment points on this polyline
while( i<pts.length && pts[i].lineWidth==undefined ) {
ctx.lineTo( pts[i].x , pts[i].y );
i++;
}
// stroke this polyline
ctx.stroke();
} // end while(i<pts.length)
}
下面是示例代码和演示:
Point = function( x , y ) {
this.x = x;
this.y = y;
}
Point.prototype.invert = function() {
var t = this.x;
this.x = this.y;
this.y = t;
}
Layer = function() {
this.points = [];
}
Layer.prototype.draw = function( ctx ) {
// just return if there's no points to draw
if(this.points.length<2){return;}
// cache an often used array
var pts=this.points;
// index for points
var i=0;
// process all points in the
while(i<pts.length){
// cache the often used first point in a new polyline
var p=pts[i];
// set styles for this polyline
ctx.lineWidth = p.lineWidth;
ctx.lineJoin = p.lineJoin;
ctx.lineCap = p.lineCap;
ctx.strokeStyle = p.strokeStyle;
// begin this polyline path
ctx.beginPath();
ctx.moveTo(p.x, p.y);
i++;
// define all segment points on this polyline
while( i<pts.length && pts[i].lineWidth==undefined ) {
ctx.lineTo( pts[i].x , pts[i].y );
i++;
}
// stroke this polyline
ctx.stroke();
} // end while(i<pts.length)
}
ExtendedPoint = function( x , y , style ) {
this.x = x;
this.y = y;
this.lineWidth = style.lineWidth;
this.lineJoin = style.lineJoin;
this.lineCap = style.lineCap;
this.strokeStyle = style.strokeStyle;
}
function startLine( e ) {
var x = e.clientX - canvas.offsetLeft;
var y = e.clientY - canvas.offsetTop;
var p = new ExtendedPoint( x , y , {
lineWidth: 5,
lineJoin: "round",
lineCap: "round",
// testing only: make each new polyline a different color
// strokeStyle: "black"
strokeStyle: randomColor(),
});
selectedLayer.points.push(p);
isDrawing = true;
}
function continueLine( e ) {
if (isDrawing == true) {
var x = e.clientX - canvas.offsetLeft;
var y = e.clientY - canvas.offsetTop;
var p = new Point( x , y );
selectedLayer.points.push( p );
}
}
function endLine() {
isDrawing = false;
}
function redraw() {
context.clearRect( 0, 0, 400, 400 );
for ( var i = 0 ; i < layers.length ; i++ ) {
layers[i].draw( context );
}
}
var canvas = document.getElementById("cvs");
canvas.setAttribute("width" , 400);
canvas.setAttribute("height", 400);
var context = canvas.getContext("2d");
var layers = [];
layers.push( new Layer() );
var selectedLayer = layers[0];
var isDrawing = false;
canvas.addEventListener( "mousedown" , startLine );
canvas.addEventListener( "mousemove" , continueLine );
canvas.addEventListener( "mousemove" , redraw );
canvas.addEventListener( "mouseup" , endLine );
// testing only: make each polyline a different color
function randomColor(){
return('#'+Math.floor(Math.random()*16777215).toString(16));
}
body{ background-color: ivory; }
canvas{border:1px solid red;}
<h4>Drag to draw layered lines</h4>
<canvas id="cvs" width=400 height=400></canvas>