admin管理员组文章数量:1327524
I have made a canvas in html5. I'm using it to show parts of a bigger image that you can move and I want to make it possible to zoom both in and out. But I do not know how to make the image scale from a certain point. When I increase the size of the image the part which is shown by the canvas is moved, I want the part in the center of the canvas to be the focus point when the scaling is plete, but no matter how I try it gets distorted some how. It seems like depending on which part of the image is shown, when the scaling happens that part of the picture is going to get moved to different coordinates. I do not know what type of algorithm I would have to use so calculate the movement of the image.
This is a link to a visual example of the movement i mean, .jpg, the two images are scaled the same but depending on which part of the image that is visible in the canvas, the amount the image needs to be moved tor the zoom differs.
This is my code, but it isn't really working that well.
<!DOCTYPE HTML>
<html>
<head>
<script type="text/javascript" src=".3.2/jquery.js"></script>
<style>
body {
padding: 0px;
margin: 0px;
}
</style>
</head>
<body>
<div id="map" style="position:absolute;top:10px;left:50px;">
<canvas id="canvas" width="800" height="600" style="float:left;border:1px solid #000000;">Your browser doesn't support canvas</canvas>
<div id="floorDown" onMouseDown="zoomIn()" style="width:200px;height:50px;float:left;">Zoom in</div><br>
<div id="floorDown" onMouseDown="zoomOut()" style="width:200px;height:50px;float:left;">Zoom out</div>
</div>
<script>
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var startX;
var startY;
var isDown=false;
//start position
var imageX=0;
var imageY=0;
var imageWidth,imageHeight,imageRight,imageBottom;
var draggingImage=false;
var startX;
var startY;
var img=new Image();
img.onload=function(){
imageWidth=img.width;
imageHeight=img.height;
draw();
}
img.src='.png';
function draw(){
// clear the canvas
ctx.clearRect(0,0,canvas.width,canvas.height);
//Disable anti-aliasing
ctx.imageSmoothingEnabled=false;
// draw the image
ctx.drawImage(img,0,0,img.width,img.height,imageX,imageY,imageWidth,imageHeight);
}
function handleMouseDown(e){
startX=parseInt(e.clientX-offsetX);
startY=parseInt(e.clientY-offsetY);
draggingImage= true;
}
function handleMouseUp(e){
draggingImage=false;
draw();
}
function handleMouseOut(e){
handleMouseUp(e);
}
function handleMouseMove(e){
if(draggingImage){
imageClick=false;
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// move the image by the amount of the latest drag
var dx=mouseX-startX;
var dy=mouseY-startY;
imageX+=dx;
imageY+=dy;
// reset the startXY for next time
startX=mouseX;
startY=mouseY;
// redraw the image with border
draw();
}
}
// TEST zoom in/out functions
function zoomIn() {
imageX=imageX*2;
imageY=imageY*2;
imageWidth=imageWidth*2;
imageHeight=imageHeight*2;
draw();
}
function zoomOut() {
imageX=imageX/2;
imageY=imageY/2;
imageWidth=imageWidth/2;
imageHeight=imageHeight/2;
draw();
}
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
$("#canvas").mouseup(function(e){handleMouseUp(e);});
$("#canvas").mouseout(function(e){handleMouseOut(e);});
</script>
</body>
I have made a canvas in html5. I'm using it to show parts of a bigger image that you can move and I want to make it possible to zoom both in and out. But I do not know how to make the image scale from a certain point. When I increase the size of the image the part which is shown by the canvas is moved, I want the part in the center of the canvas to be the focus point when the scaling is plete, but no matter how I try it gets distorted some how. It seems like depending on which part of the image is shown, when the scaling happens that part of the picture is going to get moved to different coordinates. I do not know what type of algorithm I would have to use so calculate the movement of the image.
This is a link to a visual example of the movement i mean, https://i.sstatic/66oWo.jpg, the two images are scaled the same but depending on which part of the image that is visible in the canvas, the amount the image needs to be moved tor the zoom differs.
This is my code, but it isn't really working that well.
<!DOCTYPE HTML>
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis./ajax/libs/jquery/1.3.2/jquery.js"></script>
<style>
body {
padding: 0px;
margin: 0px;
}
</style>
</head>
<body>
<div id="map" style="position:absolute;top:10px;left:50px;">
<canvas id="canvas" width="800" height="600" style="float:left;border:1px solid #000000;">Your browser doesn't support canvas</canvas>
<div id="floorDown" onMouseDown="zoomIn()" style="width:200px;height:50px;float:left;">Zoom in</div><br>
<div id="floorDown" onMouseDown="zoomOut()" style="width:200px;height:50px;float:left;">Zoom out</div>
</div>
<script>
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var startX;
var startY;
var isDown=false;
//start position
var imageX=0;
var imageY=0;
var imageWidth,imageHeight,imageRight,imageBottom;
var draggingImage=false;
var startX;
var startY;
var img=new Image();
img.onload=function(){
imageWidth=img.width;
imageHeight=img.height;
draw();
}
img.src='http://orig00.deviantart/35cb/f/2013/030/f/0/tripolar_by_zy0rg-d5t9tqh.png';
function draw(){
// clear the canvas
ctx.clearRect(0,0,canvas.width,canvas.height);
//Disable anti-aliasing
ctx.imageSmoothingEnabled=false;
// draw the image
ctx.drawImage(img,0,0,img.width,img.height,imageX,imageY,imageWidth,imageHeight);
}
function handleMouseDown(e){
startX=parseInt(e.clientX-offsetX);
startY=parseInt(e.clientY-offsetY);
draggingImage= true;
}
function handleMouseUp(e){
draggingImage=false;
draw();
}
function handleMouseOut(e){
handleMouseUp(e);
}
function handleMouseMove(e){
if(draggingImage){
imageClick=false;
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// move the image by the amount of the latest drag
var dx=mouseX-startX;
var dy=mouseY-startY;
imageX+=dx;
imageY+=dy;
// reset the startXY for next time
startX=mouseX;
startY=mouseY;
// redraw the image with border
draw();
}
}
// TEST zoom in/out functions
function zoomIn() {
imageX=imageX*2;
imageY=imageY*2;
imageWidth=imageWidth*2;
imageHeight=imageHeight*2;
draw();
}
function zoomOut() {
imageX=imageX/2;
imageY=imageY/2;
imageWidth=imageWidth/2;
imageHeight=imageHeight/2;
draw();
}
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
$("#canvas").mouseup(function(e){handleMouseUp(e);});
$("#canvas").mouseout(function(e){handleMouseOut(e);});
</script>
</body>
Share
Improve this question
asked Apr 15, 2017 at 3:49
asd fgasd fg
131 silver badge4 bronze badges
1 Answer
Reset to default 7Given the origin (pos) and scale to zoom at a point
var pos = {x : 0, y : 0};
var scale = 1;
function zoomAt(x,y,_scale)
scale *= _scale
pos.x = x - (x - pos.x) * scale;
pos.y = y - (y - pos.y) * scale;
}
You can then create the transform with
ctx.setTransform(scale, 0, 0, scale, pos.x, pos.y);
So to zoom at the center of screen
zoomAt(canvas.width / 2, canvas.height / 2, 1.1); // zoom in
zoomAt(canvas.width / 2, canvas.height / 2, 1 / 1.1); // zoom out
Put all together
// the following globals are available
// w, h, cw, ch, width height centerWidth centerHeight of canvas
// canvas, ctx, mouse, globalTime
const image = new Image;
image.src = "https://upload.wikimedia/wikipedia/mons/thumb/6/6d/KTZ_2TE10U_Aynabulak.jpg/800px-KTZ_2TE10U_Aynabulak.jpg";
const font = {
font : "28px Arial",
textAlign : "center",
textBaseline : "middle",
}
function setStyle(ctx, style){
Object.keys(style).forEach(key => ctx[key] = style[key]);
}
// Handle all key input
const keys = { // key input object
ArrowLeft : false, // only add key names you want to listen to
ArrowRight : false,
keyEvent (event) {
if (keys[event.code] !== undefined) { // are we interested in this key
keys[event.code] = event.type === "keydown";
}
}
}
// add key listeners
document.addEventListener("keydown", keys.keyEvent);
document.addEventListener("keyup", keys.keyEvent);
const view = (()=>{
const matrix = [1,0,0,1,0,0]; // current view transform
const invMatrix = [1,0,0,1,0,0]; // current inverse view transform
var m = matrix; // alias
var im = invMatrix; // alias
var rotate = 0; // current x axis direction in radians
var scale = 1; // current scale
const pos = { // current position of origin
x : 0,
y : 0,
}
var dirty = true;
return {
apply(ctx){
if(dirty){ this.update() }
var m = matrix;
ctx.setTransform(m[0],m[1],m[2],m[3],m[4],m[5]);
},
update(){ // call to update transforms
var xdx = Math.cos(rotate) * scale;
var xdy = Math.sin(rotate) * scale;
m[0] = xdx;
m[1] = xdy;
m[2] = -xdy;
m[3] = xdx;
m[4] = pos.x;
m[5] = pos.y;
// calculate the inverse transformation
cross = m[0] * m[3] - m[1] * m[2];
im[0] = m[3] / cross;
im[1] = -m[1] / cross;
im[2] = -m[2] / cross;
im[3] = m[0] / cross;
dirty = false;
},
toWorld(x,y,point = {}){ // convert screen to world coords
var xx, yy;
if(dirty){ this.update() }
xx = x - matrix[4];
yy = y - matrix[5];
point.x = xx * im[0] + yy * im[2];
point.y = xx * im[1] + yy * im[3];
return point;
},
toScreen(x,y,point = {}){ // convert world coords to coords
if(dirty){ this.update() }
point.x = x * m[0] + y * m[2] + m[4];
point.y = x * m[1] + y * m[3] + m[5];
return point;
},
movePos(x,y){
pos.x += x;
pos.y += y;
dirty = true;
},
setPos(x,y){
pos.x = x;
pos.y = y;
dirty = true;
},
setScale(sc){
scale = sc;
dirty = true;
},
scaleScale(sc){
scale *= sc;
dirty = true;
},
scaleAt(x,y,sc){
if(dirty){ this.update() }
scale *= sc;
pos.x = x - (x - pos.x) * sc;
pos.y = y - (y - pos.y) * sc;
dirty = true;
}
};
})();
function onResize(){
setStyle(ctx,font);
}
const drag = {
dragging : false,
lastX : 0,
lastY : 0,
update(){
var dx,dy;
if(mouse.w){
if(mouse.w < 0){
mouse.w += 10;
view.scaleAt(mouse.x,mouse.y,1/1.02);
if(mouse.w > 0){
mouse.w = 0;
}
} else if(mouse.w > 0){
mouse.w -= 10;
view.scaleAt(mouse.x,mouse.y,1.02);
if(mouse.w < 0){
mouse.w = 0;
}
}
}
if(mouse.buttonRaw){
if(!this.dragging){
this.dragging = true;
this.lastX = mouse.x;
this.lastY = mouse.y;
}else{
if(mouse.buttonRaw & 1){
dx = mouse.x-this.lastX;
dy = mouse.y-this.lastY;
this.lastX = mouse.x;
this.lastY = mouse.y;
view.movePos(dx,dy);
}
}
}else{
if(this.dragging){
this.dragging = false;
}
}
}
}
function display() { // call once per frame
ctx.setTransform(1, 0, 0, 1, 0, 0); // reset transform
ctx.globalAlpha = 1; // reset alpha
ctx.clearRect(0, 0, w, h);
if(keys.ArrowLeft ){ mouse.w += 10 }
if(keys.ArrowRight){ mouse.w -= 10 }
drag.update();
if(image.plete){
view.apply(ctx);
ctx.drawImage(image,0,0);
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.fillText("Click drag to pan. Wheel to zoom or left/right arrow.",cw,20)
}else{
ctx.fillText("Loading Image...",cw,ch)
}
}
/******************************************************************************
The code from here down is generic full page mouse and canvas boiler plate
code. As I do many examples which all require the same mouse and canvas
functionality I have created this code to keep a consistent interface. The
Code may or may not be part of the answer.
This code may or may not have ES6 only sections so will require a transpiler
such as babel.js to run on legacy browsers.
*****************************************************************************/
// V2.0 ES6 version for Stackoverflow and Groover QuickRun
var w, h, cw, ch, canvas, ctx, mouse, globalTime = 0;
// You can declare onResize (Note the capital R) as a callback that is also
// called once at start up. Warning on first call canvas may not be at full
// size.
;(function(){
const RESIZE_DEBOUNCE_TIME = 100;
var resizeTimeoutHandle;
var firstRun = true;
function createCanvas () {
var c,cs;
cs = (c = document.createElement("canvas")).style;
cs.position = "absolute";
cs.top = cs.left = "0px";
cs.zIndex = 10;
document.body.appendChild(c);
return c;
}
function resizeCanvas () {
if (canvas === undefined) { canvas = createCanvas() }
canvas.width = innerWidth;
canvas.height = innerHeight;
ctx = canvas.getContext("2d");
if (typeof setGlobals === "function") { setGlobals() }
if (typeof onResize === "function") {
clearTimeout(resizeTimeoutHandle);
if (firstRun) { onResize() }
else { resizeTimeoutHandle = setTimeout(onResize, RESIZE_DEBOUNCE_TIME) }
firstRun = false;
}
}
function setGlobals () {
cw = (w = canvas.width) / 2;
ch = (h = canvas.height) / 2;
}
mouse = (function () {
function preventDefault(e) { e.preventDefault() }
var m; // alias for mouse
var mouse = {
x : 0, y : 0, w : 0, // mouse position and wheel
alt : false, shift : false, ctrl : false, // mouse modifiers
buttonRaw : 0,
over : false, // true if mouse over the element
buttonOnMasks : [0b1, 0b10, 0b100], // mouse button on masks
buttonOffMasks : [0b110, 0b101, 0b011], // mouse button off masks
active : false,
bounds : null,
eventNames : "mousemove,mousedown,mouseup,mouseout,mouseover,mousewheel,DOMMouseScroll".split(","),
event(e) {
var t = e.type;
m.bounds = m.element.getBoundingClientRect();
m.x = e.pageX - m.bounds.left - scrollX;
m.y = e.pageY - m.bounds.top - scrollY;
m.alt = e.altKey;
m.shift = e.shiftKey;
m.ctrl = e.ctrlKey;
if (t === "mousedown") { m.buttonRaw |= m.buttonOnMasks[e.which - 1] }
else if (t === "mouseup") { m.buttonRaw &= m.buttonOffMasks[e.which - 1] }
else if (t === "mouseout") { m.over = false }
else if (t === "mouseover") { m.over = true }
else if (t === "mousewheel") {
m.w = e.wheelDelta
e.preventDefault();
}
else if (t === "DOMMouseScroll") {
m.w = -e.detail
e.preventDefault();
}
},
start(element) {
m.element = element === undefined ? document : element;
m.eventNames.forEach(name => document.addEventListener(name, mouse.event) );
document.addEventListener("contextmenu", preventDefault, false);
m.active = true;
},
}
m = mouse;
return mouse;
})();
function update(timer) { // Main update loop
globalTime = timer;
display(); // call demo code
requestAnimationFrame(update)
}
setTimeout(function(){
canvas = createCanvas();
mouse.start(canvas, true);
resizeCanvas();
window.addEventListener("resize", resizeCanvas);
requestAnimationFrame(update);
},0);
})();
/** SimpleFullCanvasMouse.js end **/
#imageCC {
font-family : arial;
font-size : 10px;
position : absolute;
z-index : 100;
bottom : 3px;
right : 10px;
background : rgba(255,255,255,0.7);
}
<div id=imageCC>Image rights.
<a href="https://mons.wikimedia/wiki/User:Kabelleger">Kabelleger</a> / David Gubler (<a href="http://www.bahnbilder.ch">http://www.bahnbilder.ch</a>), <a href="https://mons.wikimedia/wiki/File:KTZ_2TE10U_Aynabulak.jpg">KTZ 2TE10U Aynabulak</a>, <a href="https://creativemons/licenses/by-sa/3.0/legalcode">CC BY-SA 3.0</a>
</div>
本文标签: javascriptZoomscale from different point of image in canvasStack Overflow
版权声明:本文标题:javascript - Zoomscale from different point of image in canvas - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742171291a2426761.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论