我的示例用法:
使用鼠标单击并拖动,您可以在画布上绘图。
使用鼠标滚轮可以放大和缩小。
我的问题: 在使用函数 drawImage 重新绘制之前,可以使用它 在重新绘图之间平稳过渡。如果有可能如何?
类似的代码:http://jsfiddle.net/59Bhb/3/
如果我在第237-238行的 drawImage 函数中使用鼠标缩放:
contextBg.beginPath();
contextBg.drawImage(canvasPaint, paskutinisX, paskutinisY, imageWidthZoomed, imageHeightZoomed);
有两个原始大小并且隐藏的画布。另一个具有缩放尺寸。 首先绘制第二个获取所有信息以重新绘制缩放绘图。 在进行比例变换后,像素数量增加,反之亦然。
答案 0 :(得分:1)
一种方法是收听鼠标滚轮事件并缩放图像......
根据车轮移动的次数
并根据车轮的移动方向
以小增量缩放图像,使缩放显得平滑。
示例代码和演示:http://jsfiddle.net/m1erickson/aCt64/
// all browsers listen for mousewheel except FF
canvas.addEventListener('mousewheel',handleMouseScrollDirection, false);
canvas.addEventListener('DOMMouseScroll',handleMouseScrollDirection,false);
// listen for mousewheel events
// rescale based on the number of times the mousewheel event has been triggered
function handleMouseScrollDirection(e){
var direction;
if(e.wheelDelta){
direction=(e.wheelDelta>0)?1:-1;
}else{
// FF does not have e.wheelDelta (it has e.detail instead)
// FF e.detail is negative when scrolling up
direction=(e.detail>0)?-1:1;
}
// scale the image by 10% each time the mousewheel event is triggered
scale+=direction/10;
draw();
}
完整示例代码:
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var scale=1.00;
var iw,ih;
var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house100x100.png";
function start(){
iw=img.width;
ih=img.height;
// all browsers listen for mousewheel except FF
canvas.addEventListener('mousewheel',handleMouseScrollDirection, false);
canvas.addEventListener('DOMMouseScroll',handleMouseScrollDirection,false);
//
function handleMouseScrollDirection(e){
var direction;
if(e.wheelDelta){
direction=(e.wheelDelta>0)?1:-1;
}else{
// FF does not have e.wheelDelta (it has e.detail instead)
// FF e.detail is negative when scrolling up
direction=(e.detail>0)?-1:1;
}
console.log(direction);
scale+=direction/10;
draw();
}
draw();
}
function draw(){
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.drawImage(img,
0,0,iw,ih,
(cw-iw*scale)/2,(ch-ih*scale)/2,iw*scale,ih*scale
);
}
}); // end $(function(){});
</script>
</head>
<body>
<h4>Use mousewheel to scale the image smoothly.</h4>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
答案 1 :(得分:1)
首先,要解决问题,您应该毫不犹豫地建立中间层以简化您的工作。
像“相机”类这样的东西可以帮到你。
另外,处理滚动事件的代码太复杂了。我知道我在这里重复一遍,但我宁愿拥有这19行代码:
var zoomSteps = [0.1, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0];
var zoomIndex = zoomSteps.indexOf(1);
function doScroll(e) {
e = window.event || e;
var delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)));
// increase zoom index by delta
var newZoomIndex = zoomIndex + delta;
// return if out of bounds
if (newZoomIndex < 0 || newZoomIndex >= zoomSteps.length) return;
// update previous scale
previousScale = scale;
// we have a new valid zoomIndex
zoomIndex = newZoomIndex;
// check we did not reach a boundary
zoomIsMin = (zoomIndex == 0);
zoomIsMax = (zoomIndex == zoomSteps.length - 1);
// compute new scale / image size
scale = zoomSteps[zoomIndex];
imageWidthZoomed = imageWidth * scale;
imageHeightZoomed = imageHeight * scale;
而不是这个代码在140个未注释的行中执行相同的操作,这只是7倍大(如果我们从代码中删除注释,则为12次):
function doScroll(e) {
e = window.event || e;
var delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)));
if (delta === 1) {
if (zoom < 5) {
zoom++;
zoomIsMax = false;
} else {
zoomIsMax = true;
}
} else if (delta === -1) {
if (zoom > -5) {
zoom--;
zoomIsMin = false;
} else {
zoomIsMin = true;
}
}
if (zoom === 1) {
if (delta === 1) {
previousScale = 1;
} else {
previousScale = 1.4;
}
scale = 1.2;
imageWidthZoomed = imageWidth * 1.2;
imageHeightZoomed = imageHeight * 1.2;
} else if (zoom === 2) {
if (delta === 1) {
previousScale = 1.2;
} else {
previousScale = 1.6;
}
scale = 1.4;
imageWidthZoomed = imageWidth * 1.4;
imageHeightZoomed = imageHeight * 1.4;
} else if (zoom === 3) {
if (delta === 1) {
previousScale = 1.4;
} else {
previousScale = 1.8;
}
scale = 1.6;
imageWidthZoomed = imageWidth * 1.6;
imageHeightZoomed = imageHeight * 1.6;
} else if (zoom === 4) {
if (delta === 1) {
previousScale = 1.6;
} else {
previousScale = 2;
}
scale = 1.8;
imageWidthZoomed = imageWidth * 1.8;
imageHeightZoomed = imageHeight * 1.8;
} else if (zoom === 5) {
if (delta === 1) {
previousScale = 1.8;
} else {
//out of range
}
scale = 2;
imageWidthZoomed = imageWidth * 2;
imageHeightZoomed = imageHeight * 2;
} else if (zoom === 0) {
if (delta === 1) {
previousScale = 0.8;
} else {
previousScale = 1.2;
}
scale = 1;
imageWidthZoomed = imageWidth;
imageHeightZoomed = imageHeight;
} else if (zoom === -1) {
if (delta === 1) {
previousScale = 0.6;
} else {
previousScale = 1;
}
scale = 0.8;
imageWidthZoomed = imageWidth * 0.8;
imageHeightZoomed = imageHeight * 0.8;
} else if (zoom === -2) {
if (delta === 1) {
previousScale = 0.4;
} else {
previousScale = 0.8;
}
scale = 0.6;
imageWidthZoomed = imageWidth * 0.6;
imageHeightZoomed = imageHeight * 0.6;
} else if (zoom === -3) {
if (delta === 1) {
previousScale = 0.2;
} else {
previousScale = 0.6;
}
scale = 0.4;
imageWidthZoomed = imageWidth * 0.4;
imageHeightZoomed = imageHeight * 0.4;
} else if (zoom === -4) {
if (delta === 1) {
previousScale = 0.1;
} else {
previousScale = 0.4;
}
scale = 0.2;
imageWidthZoomed = imageWidth * 0.2;
imageHeightZoomed = imageHeight * 0.2;
} else if (zoom === -5) {
if (delta === 1) {
//out of range
} else {
previousScale = 0.2;
}
scale = 0.1;
imageWidthZoomed = imageWidth * 0.1;
imageHeightZoomed = imageHeight * 0.1;
}
doScroll的结束肯定会受益于中间Camera Class的使用。
现在进行转换,想法如下:您只需记录需要更新及其参数,而不是绘制缩放更改:
currentDrawParameters = [canvasPaint, paskutinisX, paskutinisY, imageWidthZoomed, imageHeightZoomed];
lastChangeTime = Date.now();
然后你有一个单独的计时器,如果需要的话会更新画布,为什么不使用缓动函数(意思是:函数[0.0; 1.0] - &gt; [0.0; 1.0])。
var currentDrawParameters = null;
var transitionTime = 500;
var lastChangeTime = -1;
var easingFunction = function (x) {
return Math.sqrt(x); // try : x , x*x, 0.2+0.8*x, ...
};
function drawSmoothly() {
// return if no need to draw
if (!currentDrawParameters) return;
var timeElapsed = Date.now() - lastChangeTime;
// return if transition ended
if (timeElapsed > transitionTime) {
currentDrawParameters = null;
return;
}
// compute time ratio = % time elapsed vs transitionTime
var ratio = timeElapsed / transitionTime;
// ease the ratio
var easedRatio = easingFunction(ratio);
contextBg.save();
contextBg.globalAlpha = 0.1;
contextBg.fillStyle = '#000';
// erase previous image progressively
contextBg.fillRect(0, 0, windowWidth, windowHeightUsed);
// draw the image with an opacity 0.0 ===>>> 1.0
contextBg.globalAlpha = easedRatio;
contextBg.drawImage.apply(contextBg, currentDrawParameters);
contextBg.restore();
}
setInterval(drawSmoothly, 50);
小提琴在这里:
http://jsfiddle.net/gamealchemist/cDXj3/3/
尝试几种缓和功能/时间设置。