gpt4 book ai didi

javascript - CSS3 缩放鼠标光标

转载 作者:技术小花猫 更新时间:2023-10-29 10:21:39 25 4
gpt4 key购买 nike

我的目标是创建一个插件,允许在页面区域上进行缩放和平移操作,就像 Google map 目前的工作方式一样(意思是:用鼠标滚动 = 放大/缩小区域,单击并按住并移动 &释放 = 平移)。

滚动时,我希望有一个以鼠标光标为中心的缩放操作。

为此,我使用了动态 CSS3 矩阵转换。唯一但也是强制性的约束是,除了 CSS3 平移和缩放转换之外,我不能使用任何其他转换原点为 0px 0px 的转换。

平移不在我的问题范围内,因为我已经在使用它了。谈到缩放时,我很难找出我的 Javascript 代码中的错误所在。

问题一定出在 MouseZoom.prototype.zoom 函数的某处,在计算 x 轴和 y 轴上的平移时。

首先,这是我的 HTML 代码:

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width = device-width, initial-scale = 1.0, user-scalable = no" />
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script src="jquery.mousewheel.min.js"></script>
<script src="StackOverflow.js"></script>
<style type="text/css" media="all">
#drawing {
position: absolute;
top: 0px;
left: 0px;
right:0;
bottom:0;
z-index: 0;
background: url(http://catmacros.files.wordpress.com/2009/09/cats_banzai.jpg) no-repeat;
background-position: 50% 50%;
}
</style>
<title>Test</title>
</head>
<body>
<div id="drawing"></div>
<script>
var renderer = new ZoomPanRenderer("drawing");
</script>
</body>
</html>

如您所见,我使用的是 Jquery 和来自 Brandon Aaron 的 jquery 鼠标滚轮插件,可在此处找到: https://github.com/brandonaaron/jquery-mousewheel/

这是 StackOverflow.js 文件的内容:

/***************************************************** 
* Transformations
****************************************************/
function Transformations(translateX, translateY, scale){
this.translateX = translateX;
this.translateY = translateY;
this.scale = scale;
}

/* Getters */
Transformations.prototype.getScale = function(){ return this.scale; }
Transformations.prototype.getTranslateX = function(){ return this.translateX; }
Transformations.prototype.getTranslateY = function(){ return this.translateY; }

/*****************************************************
* Zoom Pan Renderer
****************************************************/
function ZoomPanRenderer(elementId){
this.zooming = undefined;
this.elementId = elementId;
this.current = new Transformations(0, 0, 1);
this.last = new Transformations(0, 0, 1);
new ZoomPanEventHandlers(this);
}

/* setters */
ZoomPanRenderer.prototype.setCurrentTransformations = function(t){ this.current = t; }
ZoomPanRenderer.prototype.setZooming = function(z){ this.zooming = z; }

/* getters */
ZoomPanRenderer.prototype.getCurrentTransformations = function(){ return this.current; }
ZoomPanRenderer.prototype.getZooming = function(){ return this.zooming; }
ZoomPanRenderer.prototype.getLastTransformations = function(){ return this.last; }
ZoomPanRenderer.prototype.getElementId = function(){ return this.elementId; }

/* Rendering */
ZoomPanRenderer.prototype.getTransform3d = function(t){
var transform3d = "matrix3d(";
transform3d+= t.getScale().toFixed(10) + ",0,0,0,";
transform3d+= "0," + t.getScale().toFixed(10) + ",0,0,";
transform3d+= "0,0,1,0,";
transform3d+= t.getTranslateX().toFixed(10) + "," + t.getTranslateY().toFixed(10) + ",0,1)";
return transform3d;
}

ZoomPanRenderer.prototype.getTransform2d = function(t){
var transform3d = "matrix(";
transform3d+= t.getScale().toFixed(10) + ",0,0," + t.getScale().toFixed(10) + "," + t.getTranslateX().toFixed(10) + "," + t.getTranslateY().toFixed(10) + ")";
return transform3d;
}

ZoomPanRenderer.prototype.applyTransformations = function(t){
var elem = $("#" + this.getElementId());
elem.css("transform-origin", "0px 0px");
elem.css("-ms-transform-origin", "0px 0px");
elem.css("-o-transform-origin", "0px 0px");
elem.css("-moz-transform-origin", "0px 0px");
elem.css("-webkit-transform-origin", "0px 0px");
var transform2d = this.getTransform2d(t);
elem.css("transform", transform2d);
elem.css("-ms-transform", transform2d);
elem.css("-o-transform", transform2d);
elem.css("-moz-transform", transform2d);
elem.css("-webkit-transform", this.getTransform3d(t));
}

/*****************************************************
* Event handler
****************************************************/
function ZoomPanEventHandlers(renderer){
this.renderer = renderer;

/* Disable scroll overflow - safari */
document.addEventListener('touchmove', function(e) { e.preventDefault(); }, false);

/* Disable default drag opeartions on the element (FF makes it ready for save)*/
$("#" + renderer.getElementId()).bind('dragstart', function(e) { e.preventDefault(); });

/* Add mouse wheel handler */
$("#" + renderer.getElementId()).bind("mousewheel", function(event, delta) {
if(renderer.getZooming()==undefined){
var offsetLeft = $("#" + renderer.getElementId()).offset().left;
var offsetTop = $("#" + renderer.getElementId()).offset().top;
var zooming = new MouseZoom(renderer.getCurrentTransformations(), event.pageX, event.pageY, offsetLeft, offsetTop, delta);
renderer.setZooming(zooming);

var newTransformation = zooming.zoom();
renderer.applyTransformations(newTransformation);
renderer.setCurrentTransformations(newTransformation);
renderer.setZooming(undefined);
}
return false;
});
}

/*****************************************************
* Mouse zoom
****************************************************/
function MouseZoom(t, mouseX, mouseY, offsetLeft, offsetTop, delta){
this.current = t;
this.offsetLeft = offsetLeft;
this.offsetTop = offsetTop;
this.mouseX = mouseX;
this.mouseY = mouseY;
this.delta = delta;
}

MouseZoom.prototype.zoom = function(){
var previousScale = this.current.getScale();
var newScale = previousScale + this.delta/5;
if(newScale<1){
newScale = 1;
}
var ratio = newScale / previousScale;

var imageX = this.mouseX - this.offsetLeft;
var imageY = this.mouseY - this.offsetTop;

var previousTx = - this.current.getTranslateX() * previousScale;
var previousTy = - this.current.getTranslateY() * previousScale;
var previousDx = imageX * previousScale;
var previousDy = imageY * previousScale;

var newTx = (previousTx * ratio + previousDx * (ratio - 1)) / newScale;
var newTy = (previousTy * ratio + previousDy * (ratio - 1)) / newScale;

return new Transformations(-newTx, -newTy, newScale);
}

最佳答案

使用 transformdiv 元素 上获得 google maps 缩放 行为似乎是一个有趣的想法,所以我付了一点钱 =)

我会使用 transform-origin(及其浏览器兼容性的姊妹属性)将缩放调整到您正在缩放的​​ div 上的鼠标位置。我认为这可以做你想做的。我在 fiddle 上放了一些例子来说明:

调整transform-origin

因此,在您的applyTransformations 函数中,我们可以根据imageXimageY 动态调整transform-origin >,如果我们从 MouseZoom(鼠标监听器)函数传递此值。

    var orig = t.getTranslateX().toFixed() + "px " + t.getTranslateY().toFixed() + "px";
elem.css("transform-origin", orig);
elem.css("-ms-transform-origin", orig);
elem.css("-o-transform-origin", orig);
elem.css("-moz-transform-origin", orig);
elem.css("-webkit-transform-origin", orig);

(在这个 first fiddle example 中,我只是在 Transformations 中使用了你的 translateXtranslateY 来传递鼠标在 div 元素上的位置- 在第二个示例中,我将其重命名为 originXoriginY 以区别于翻译变量。)

计算变换原点

在您的 MouseZoom 中,我们可以简单地使用 imageX/previousScale 计算原点位置。

    MouseZoom.prototype.zoom = function(){
var previousScale = this.current.getScale();
var newScale = previousScale + this.delta/10;
if(newScale<1){
newScale = 1;
}
var ratio = newScale / previousScale;

var imageX = this.mouseX - this.offsetLeft;
var imageY = this.mouseY - this.offsetTop;

var newTx = imageX/previousScale;
var newTy = imageY/previousScale;

return new Transformations(newTx, newTy, newScale);
}

因此,如果您在放大到不同位置之前完全缩小,这将非常有效。但是为了能够在任何缩放级别更改缩放原点,我们可以结合原点和平移功能。

移动缩放框(扩展我原来的答案)

图像上的变换原点仍然以相同的方式计算,但我们使用单独的 translateX 和 translateY 来移动缩放框(这里我引入了两个新变量来帮助我们完成这个技巧 - 所以现在我们有 originX originYtranslateXtranslateY)。

    MouseZoom.prototype.zoom = function(){
// current scale
var previousScale = this.current.getScale();
// new scale
var newScale = previousScale + this.delta/10;
// scale limits
var maxscale = 20;
if(newScale<1){
newScale = 1;
}
else if(newScale>maxscale){
newScale = maxscale;
}
// current cursor position on image
var imageX = (this.mouseX - this.offsetLeft).toFixed(2);
var imageY = (this.mouseY - this.offsetTop).toFixed(2);
// previous cursor position on image
var prevOrigX = (this.current.getOriginX()*previousScale).toFixed(2);
var prevOrigY = (this.current.getOriginY()*previousScale).toFixed(2);
// previous zooming frame translate
var translateX = this.current.getTranslateX();
var translateY = this.current.getTranslateY();
// set origin to current cursor position
var newOrigX = imageX/previousScale;
var newOrigY = imageY/previousScale;
// move zooming frame to current cursor position
if ((Math.abs(imageX-prevOrigX)>1 || Math.abs(imageY-prevOrigY)>1) && previousScale < maxscale) {
translateX = translateX + (imageX-prevOrigX)*(1-1/previousScale);
translateY = translateY + (imageY-prevOrigY)*(1-1/previousScale);
}
// stabilize position by zooming on previous cursor position
else if(previousScale != 1 || imageX != prevOrigX && imageY != prevOrigY) {
newOrigX = prevOrigX/previousScale;
newOrigY = prevOrigY/previousScale;
}
return new Transformations(newOrigX, newOrigY, translateX, translateY, newScale);
}

对于这个例子,我稍微调整了你的原始脚本并添加了 second fiddle example .

现在我们从任何缩放级别放大和缩小鼠标光标。但是由于帧偏移,我们最终移动了原始的 div(“测量地球”)...如果您使用宽度和高度有限的对象(在一端放大,在另一端缩小),这看起来很有趣另一端,我们像尺蠖一样向前移动)。

避免“尺蠖”效应

为了避免这种情况,您可以添加限制,例如,左图像边框不能移动到其原始 x 坐标的右侧,顶部图像边框不能移动到其原始 y 位置以下,等等两个边界。但是随后缩放/缩小将不会完全绑定(bind)到光标,还会绑定(bind)到 example 3 中的图像边缘(您会注意到图像滑入到位)。 .

    if(this.delta <= 0){
var width = 500; // image width
var height = 350; // image height
if(translateX+newOrigX+(width - newOrigX)*newScale <= width){
translateX = 0;
newOrigX = width;
}
else if (translateX+newOrigX*(1-newScale) >= 0){
translateX = 0;
newOrigX = 0;
}
if(translateY+newOrigY+(height - newOrigY)*newScale <= height){
translateY = 0;
newOrigY = height;
}
else if (translateY+newOrigY*(1-newScale) >= 0){
translateY = 0;
newOrigY = 0;
}
}

另一个(有点蹩脚)选项是在完全缩小时简单地重置帧转换(scale==1)。

但是,如果您要处理连续元素(左右边缘以及上下边缘绑定(bind)在一起)或仅处理非常大的元素,则不会遇到此问题。

为了轻而易举地完成所有事情——我们可以在我们的缩放对象周围添加一个带有 overflow hidden 的父框架。所以图像区域不会随着缩放而改变。参见 jsfiddle example 4 .

关于javascript - CSS3 缩放鼠标光标,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11504703/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com