>我想要的是10幅画布,5幅在顶部,5幅在底部,每幅宽17%,高25.5%,间距适当(见下图)。在画布上绘制的每个图像对应于完整图像的相同区域(参见顶部图像)。这有点像目的地,但这实际上只是在使用context.translate和context.drawImage()的较小画布上完整图像的裁剪。请查看最里面的for循环中的两行,其中的注释与context.translate和context.drawImage相关,以获取可能发生的事情的线索。
请参阅附图,了解我想用html5 context.translate()和context.drawImage()实现的目标。
任何帮助非常感谢。谢谢。
//get parent's width and height
var parent = document.getElementById("parent");
var parentWidth = parent.offsetWidth;
var parentHeight = parent.offsetHeight;
//get below canvas
var belowCanvas = document.getElementById('belowCanvas');
var belowCtx = belowCanvas.getContext('2d');
//create temporary canvas
var tmpCanvas = document.createElement('canvas');
var tmpCtx = tmpCanvas.getContext('2d');
//initialize width and height of temporary canvas and below canvas to equal parent
tmpCanvas.width = belowCanvas.width = parentWidth;
tmpCanvas.height = belowCanvas.height = parentHeight;
//draw below canvas in black for visual aid of how things are cropped in above canvases
belowCtx.rect(0,0,parentWidth,parentHeight);
belowCtx.fillStyle = 'black';
belowCtx.fill();
//draw temporary canvas
var centerX = parentWidth/4;
var centerY = parentHeight/4;
var radius = parentHeight/4;
tmpCtx.rect(0,0,parentWidth,parentHeight);
tmpCtx.fillStyle = 'blue';
tmpCtx.fill();
tmpCtx.beginPath();
tmpCtx.arc(centerX, centerY, radius*1.5, 0, 2 * Math.PI, false);
tmpCtx.fillStyle = 'green';
tmpCtx.fill();
tmpCtx.lineWidth = 2
tmpCtx.strokeStyle = '#003300';
tmpCtx.stroke();
tmpCtx.beginPath();
tmpCtx.arc(parentWidth - centerX, centerY, radius*1.5, 0, 2 * Math.PI, false);
tmpCtx.fillStyle = 'purple';
tmpCtx.fill();
tmpCtx.lineWidth = 2
tmpCtx.strokeStyle = '#003300';
tmpCtx.stroke();
tmpCtx.beginPath();
tmpCtx.arc(parentWidth/2, parentHeight/2, radius*2, 0, 2 * Math.PI, false);
tmpCtx.fillStyle = 'white';
tmpCtx.fill();
tmpCtx.lineWidth = 2
tmpCtx.strokeStyle = '#003300';
tmpCtx.stroke();
tmpCtx.beginPath();
tmpCtx.arc(centerX, parentHeight - centerY, radius*1.5, 0, 2 * Math.PI, false);
tmpCtx.fillStyle = 'red';
tmpCtx.fill();
tmpCtx.lineWidth = 2
tmpCtx.strokeStyle = '#003300';
tmpCtx.stroke();
tmpCtx.beginPath();
tmpCtx.arc(parentWidth - centerX, parentHeight - centerY, radius*1.5, 0, 2 * Math.PI, false);
tmpCtx.fillStyle = 'yellow';
tmpCtx.fill();
tmpCtx.lineWidth = 2
tmpCtx.strokeStyle = '#003300';
tmpCtx.stroke();
//set spacing between canvases
var horizontalSpacing = parentWidth*0.025
var verticalSpacing = parentWidth*0.03
//initialize canvases width and height
var widthCanvas = parentWidth*0.17;
var heightCanvas = parentWidth*0.255;
var xStart;
var yStart = verticalSpacing;
for(var i=0; i< 2; i++)
{
xStart = horizontalSpacing;
for(var j=0; j < 5; j++)
{
//get specific destinationInCanvas by id and its respective context
var canvas = document.getElementById("canvas" + ((i*5)+j));
var ctx = canvas.getContext('2d');
canvas.width = widthCanvas;
canvas.height = heightCanvas;
/***!!!
Problem next two lines
if the next line is commented out, each canvas is drawn, but of course not translated; so you only see last canvas, canvas9
if the next line is NOT commented out, only canvas0 is drawn and translated, the rest of the canvases 1-9 are not drawn*/
ctx.translate(xStart, yStart);//comment out this line to see effect
ctx.drawImage(tmpCanvas, xStart, yStart, widthCanvas, heightCanvas, 0, 0, widthCanvas, heightCanvas);
xStart += (horizontalSpacing + widthCanvas);
}
yStart += (verticalSpacing + heightCanvas);
}
&#13;
#parent {
width: 1000px;
height: 600px;
}
#belowCanvas{
position: absolute;
z-index:-1;
}
#canvas0 {
position: absolute;
z-index:0;
}
#canvas1 {
position: absolute;
z-index:1;
}
#canvas2 {
position: absolute;
z-index:2;
}
#canvas3 {
position: absolute;
z-index:3;
}
#canvas4 {
position: absolute;
z-index:4;
}
#canvas5 {
position: absolute;
z-index:5;
}
#canvas6 {
position: absolute;
z-index:6;
}
#canvas7 {
position: absolute;
z-index:7;
}
#canvas8 {
position: absolute;
z-index:8;
}
#canvas9 {
position: absolute;
z-index:9;
}
&#13;
<!DOCTYPE HTML>
<html>
<head>
<link rel="stylesheet" type="text/css" href="style-test.css">
</head>
<body>
<div id="parent">
<canvas id="belowCanvas"></canvas>
<canvas id="canvas0"></canvas>
<canvas id="canvas1"></canvas>
<canvas id="canvas2"></canvas>
<canvas id="canvas3"></canvas>
<canvas id="canvas4"></canvas>
<canvas id="canvas5"></canvas>
<canvas id="canvas6"></canvas>
<canvas id="canvas7"></canvas>
<canvas id="canvas8"></canvas>
<canvas id="canvas9"></canvas>
</div>
<script type="text/javascript" src="script-test.js"></script>
</body>
</html>
&#13;
答案 0 :(得分:1)
在增加yStart
和xStart
时,您遇到了一些问题:
您应该将heightCanvas
/ widthCanvas
乘以循环的i
/ j
状态。
此外,在您的CSS中,如果您确实在未设置position:absolute
或margins
/ left
值的情况下添加top
,那么您的画布将会进入堆叠状态#39; ll只能看到最后一个。只需将position:absolute
添加到#belowCanvas
即可。实际上,如果您只需要黑色背景,则可以考虑将所有画布包装成div
background:black;
。那么对齐元素会更容易。
最后,由于ctx.translate
已经对源图片(ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
,sx
)进行了翻译,因此您不会需要sy
。
编辑:
实际上,他想要画布&#39;适合布局的孔,使用 context.globalCompositeOperation='destination-out';
创建。
我删除了belowCanvas
并将其替换为div
,其背景通过CSS设置为黑色。
为了防止您的小画布出现鬼魂边缘,您需要设置vertical-align:bottom; float: left
,因为浏览器会将画布元素显示为字符。
我重构了代码以编程方式创建小画布,这将允许您更改网格格式。
例如,我添加了点击监听器来显示/隐藏图层:
左键单击触发器destinationOutLayer
和右键单击触发小画布层。
//get parent's width and height
var parent = document.getElementById("parent");
var parentWidth = parent.offsetWidth;
var parentHeight = parent.offsetHeight;
var destinationOutCanvas = document.getElementById('destinationOutCanvas');
var destinationOutCtx = destinationOutCanvas.getContext('2d');
//create temporary canvas
var tmpCanvas = document.createElement('canvas');
var tmpCtx = tmpCanvas.getContext('2d');
//initialize width and height of temporary canvas and destOut canvas to equal parent
destinationOutCanvas.width = tmpCanvas.width = parentWidth;
destinationOutCanvas.height = tmpCanvas.height = parentHeight;
//draw temporary canvas
var centerX = parentWidth / 4;
var centerY = parentHeight / 4;
var radius = parentHeight / 4;
tmpCtx.rect(0, 0, parentWidth, parentHeight);
tmpCtx.fillStyle = 'blue';
tmpCtx.fill();
tmpCtx.beginPath();
tmpCtx.arc(centerX, centerY, radius * 1.5, 0, 2 * Math.PI, false);
tmpCtx.fillStyle = 'green';
tmpCtx.fill();
tmpCtx.lineWidth = 2
tmpCtx.strokeStyle = '#003300';
tmpCtx.stroke();
tmpCtx.beginPath();
tmpCtx.arc(parentWidth - centerX, centerY, radius * 1.5, 0, 2 * Math.PI, false);
tmpCtx.fillStyle = 'purple';
tmpCtx.fill();
tmpCtx.lineWidth = 2
tmpCtx.strokeStyle = '#003300';
tmpCtx.stroke();
tmpCtx.beginPath();
tmpCtx.arc(parentWidth / 2, parentHeight / 2, radius * 2, 0, 2 * Math.PI, false);
tmpCtx.fillStyle = 'white';
tmpCtx.fill();
tmpCtx.lineWidth = 2
tmpCtx.strokeStyle = '#003300';
tmpCtx.stroke();
tmpCtx.beginPath();
tmpCtx.arc(centerX, parentHeight - centerY, radius * 1.5, 0, 2 * Math.PI, false);
tmpCtx.fillStyle = 'red';
tmpCtx.fill();
tmpCtx.lineWidth = 2
tmpCtx.strokeStyle = '#003300';
tmpCtx.stroke();
tmpCtx.beginPath();
tmpCtx.arc(parentWidth - centerX, parentHeight - centerY, radius * 1.5, 0, 2 * Math.PI, false);
tmpCtx.fillStyle = 'yellow';
tmpCtx.fill();
tmpCtx.lineWidth = 2
tmpCtx.strokeStyle = '#003300';
tmpCtx.stroke();
//set the grid
//Strange bugs can occur with some fractions (e.g 18 rows);
var rows = 5;
var lines = 2;
//set spacing between canvases
//rounded to the nearest even number, since we divide this by 2 below
var horizontalSpacing = 2*Math.round((parentWidth*0.025)/2); // or whatever you want
var verticalSpacing = 2*Math.round((parentHeight*0.03)/2); // or whatever you want
//initialize canvases width and height
var widthCanvas = 2*(Math.round(parentWidth / rows)/2);
var heightCanvas = 2*(Math.round(parentHeight / lines)/2);
destinationOutCtx.drawImage(tmpCanvas, 0, 0);
destinationOutCtx.globalCompositeOperation = 'destination-out';
destinationOutCtx.fillStyle = 'orange';
for (var i = 0; i < lines; i++) {
for (var j = 0; j < rows; j++) {
//get specific destinationInCanvas by id and its respective context
//var canvas = document.getElementById("canvas" + ((i * rows) + j));
//create the canvases on the go
var canvas= document.createElement('canvas');
canvas.width = widthCanvas;
canvas.height = heightCanvas;
var ctx = canvas.getContext('2d');
//only needed for the demonstration toggler
canvas.className = "small";
//set the transform variables
var hS = horizontalSpacing/2,
vS = verticalSpacing/2,
xStart = (widthCanvas*j)+hS,
yStart = (heightCanvas*i)+vS,
cropedWidth = widthCanvas-hS*2,
cropedHeight = heightCanvas-hS*2;
ctx.drawImage(tmpCanvas, xStart, yStart, cropedWidth, cropedHeight, hS, vS, cropedWidth, cropedHeight);
destinationOutCtx.fillRect(xStart, yStart, cropedWidth, cropedHeight);
parent.appendChild(canvas);
}
}
//Toggle opacity with right and left click
destinationOutCanvas.addEventListener('click', function () {
if (this.style.opacity == 0) {
this.style.opacity = 1
} else {
this.style.opacity = 0
}
});
destinationOutCanvas.style.opacity = 1;
destinationOutCanvas.addEventListener('contextmenu', function (e) {
console.log('triggered');
e.preventDefault();
var smalls = document.querySelectorAll('.small');
console.log(smalls[0].style.opacity);
if (smalls[0].style.opacity == 0) {
for (i = 0; i < smalls.length; i++) {
smalls[i].style.opacity = 1
}
} else {
for (i = 0; i < smalls.length; i++) {
smalls[i].style.opacity = 0;
};
}
});
&#13;
#parent {
width: 1000px !important;
height: 600px;
background:#000;
}
html, body {
margin:0
}
canvas {
vertical-align:bottom;
float: left
}
.destinationOutLayer, #tmp {
position: absolute;
z-index: 2;
top:0;
}
&#13;
<div id="parent">
</div>
<canvas id="destinationOutCanvas" class="destinationOutLayer"></canvas>
&#13;