Моя цель — создать плагин, который позволяет выполнять операции масштабирования и панорамирования в области страницы, точно так же, как в настоящее время работают Карты Google (, что означает :прокрутка с помощью мыши = увеличение/уменьшение области, нажмите и удерживайте и перемещайте & выпуск = панорамирование ).
При прокрутке я хочу, чтобы операция масштабирования была сосредоточена на курсоре мыши.
Для этого я использую -матричные преобразования CSS3 fly -. Единственным, но обязательным ограничением является то, что я не могу использовать ничего, кроме трансформаций преобразования и масштабирования CSS3 с исходной точкой преобразования 0px 0px.
Панорамирование выходит за рамки моего вопроса, так как оно у меня уже работает. Когда дело доходит до масштабирования, я изо всех сил пытаюсь понять, где сбой в моем коде javascript.
Проблема должна быть где-то в функции MouseZoom.prototype.zoom, в вычислении перемещения по оси x и оси y.
Во-первых, вот мой HTML-код:
Test
Как видите, я использую Jquery и подключаемый модуль колесика мыши 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);
}