调用context.translate()后,HTML5 context.drawImage()裁剪无效

时间:2015-02-19 20:17:22

标签: javascript html5

full image 10 individual canases that correspond to areas of full image, WHAT I AM TRYING TO DO>我想要的是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;
&#13;
&#13;

1 个答案:

答案 0 :(得分:1)

  • 在增加yStartxStart时,您遇到了一些问题:
    您应该将heightCanvas / widthCanvas乘以循环的i / j状态。

  • 此外,在您的CSS中,如果您确实在未设置position:absolutemargins / 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

chat上与OP交谈后,

编辑
实际上,他想要画布&#39;适合布局的孔,使用 context.globalCompositeOperation='destination-out';创建。

  • 我删除了belowCanvas并将其替换为div,其背景通过CSS设置为黑色。

  • 为了防止您的小画布出现鬼魂边缘,您需要设置vertical-align:bottom; float: left,因为浏览器会将画布元素显示为字符。

  • 我重构了代码以编程方式创建小画布,这将允许您更改网格格式。

例如,我添加了点击监听器来显示/隐藏图层:
左键单击触发器destinationOutLayer右键单击触发小画布层。

&#13;
&#13;
//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;
&#13;
&#13;