2012-09-11 13 views
8

Tengo algunos problemas para escalar un contenedor a un punto fijo.
En mi caso estoy tratando de escalar (acercar) un escenario al cursor del mouse.Escalado a un punto fijo en KineticJS

Aquí es una manera de hacerlo con una lona pura: http://phrogz.net/tmp/canvas_zoom_to_cursor.html (como se discutió en Zoom Canvas to Mouse Cursor)

que no se puede conseguir la manera de aplicar la misma lógica durante el uso de la API KineticJS.

Código de ejemplo:

var position = this.stage.getUserPosition(); 
var scale = Math.max(this.stage.getScale().x + (0.05 * (scaleUp ? 1 : -1)), 0); 
this.stage.setScale(scale); 
// Adjust scale to position...? 
this.stage.draw(); 

Respuesta

16

Después de mucha lucha y buscando y tratando, utilizando la punta proporcionada por @Eric Rowell y el código publicado en el pliego de cuestionar Zoom in on a point (using scale and translate) finalmente me dieron el zoom dentro y fuera de un determinado punto trabajando usando KineticJS.

Aquí hay un DEMO que funciona.

Y aquí está el código:

var ui = { 
    stage: null, 
    scale: 1, 
    zoomFactor: 1.1, 
    origin: { 
     x: 0, 
     y: 0 
    }, 
    zoom: function(event) { 
     event.preventDefault(); 
     var evt = event.originalEvent, 
      mx = evt.clientX /* - canvas.offsetLeft */, 
      my = evt.clientY /* - canvas.offsetTop */, 
      wheel = evt.wheelDelta/120; 
     var zoom = (ui.zoomFactor - (evt.wheelDelta < 0 ? 0.2 : 0)); 
     var newscale = ui.scale * zoom; 
     ui.origin.x = mx/ui.scale + ui.origin.x - mx/newscale; 
     ui.origin.y = my/ui.scale + ui.origin.y - my/newscale; 

     ui.stage.setOffset(ui.origin.x, ui.origin.y); 
     ui.stage.setScale(newscale); 
     ui.stage.draw(); 

     ui.scale *= zoom; 
    } 
}; 

$(function() { 
    var width = $(document).width() - 2, 
     height = $(document).height() - 5; 
    var stage = ui.stage = new Kinetic.Stage({ 
     container: 'container', 
     width: width, 
     height: height 
    }); 
    var layer = new Kinetic.Layer({ 
     draggable: true 
    }); 
    var rectX = stage.getWidth()/2 - 50; 
    var rectY = stage.getHeight()/2 - 25; 

    var box = new Kinetic.Circle({ 
     x: 100, 
     y: 100, 
     radius: 50, 
     fill: '#00D200', 
     stroke: 'black', 
     strokeWidth: 2, 
    }); 

    // add cursor styling 
    box.on('mouseover', function() { 
     document.body.style.cursor = 'pointer'; 
    }); 
    box.on('mouseout', function() { 
     document.body.style.cursor = 'default'; 
    }); 

    layer.add(box); 
    stage.add(layer); 

    $(stage.content).on('mousewheel', ui.zoom); 
});​ 
+0

Gracias! Esto funciona. Lo siento por la respuesta tardía. – Skarbo

+0

Oye, gracias, esto funciona bien, pero tengo muchas capas, así que no puedo configurar las capas como "arrastrables". por lo tanto, configuro la etapa arrastrable. Cuando muevo el escenario como arrastrando, no puedo acercarme al punto de zoom deseado. Tengo que recalcular algunas cosas como contar la etapa x y y pero no pude lograrlo. ¿Podrías ayudarme? – magirtopcu

+0

@ user1645941 Por favor, comparta algunos ejemplos de trabajo del problema que está tratando (tal vez como [violín] (http://jsfiddle.net/)) y haré lo que pueda para ayudar. –

3

Usted necesita para compensar la etapa de tal manera que su punto central se sitúa en el punto fijo. Aquí hay un ejemplo, porque el punto central de la etapa está predeterminado en la esquina superior izquierda del lienzo. Digamos que su etapa es de 600 px de ancho y 400 px de alto, y desea que la etapa se acerque desde el centro. Usted tendría que hacer esto:

var stage = new Kinetic.Stage({ 
    container: 'container', 
    width: 600, 
    height: 400, 
    offset: [300, 200] 
}; 
3

actualizado demostración @juan.facorro 's para escalar la forma en lugar de la etapa

jsFiddle

var ui = { 
    stage: null, 
    box: null, 
    scale: 1, 
    zoomFactor: 1.1, 
    zoom: function(event) { 
     event.preventDefault(); 
     var evt = event.originalEvent, 
      mx = evt.offsetX, 
      my = evt.offsetY, 
      wheel = evt.wheelDelta/120; //n or -n 
     var zoom = (ui.zoomFactor - (evt.wheelDelta < 0 ? 0.2 : 0)); 
     var newscale = ui.scale * zoom; 

     var origin = ui.box.getPosition(); 
     origin.x = mx - (mx - origin.x) * zoom; 
     origin.y = my - (my - origin.y) * zoom; 

     ui.box.setPosition(origin.x, origin.y); 
     ui.box.setScale(newscale); 
     ui.stage.draw(); 

     ui.scale *= zoom; 
    } 
}; 

$(function() { 
    var width = $(document).width() - 2, 
     height = $(document).height() - 5; 
    var stage = ui.stage = new Kinetic.Stage({ 
     container: 'container', 
     width: width, 
     height: height 
    }); 
    var layer = new Kinetic.Layer(); 
    var rectX = stage.getWidth()/2 - 50; 
    var rectY = stage.getHeight()/2 - 25; 

    var box = ui.box = new Kinetic.Circle({ 
     x: 100, 
     y: 100, 
     radius: 50, 
     fill: '#00D200', 
     stroke: 'black', 
     strokeWidth: 2, 
     draggable: true 
    }); 

    // add cursor styling 
    box.on('mouseover', function() { 
     document.body.style.cursor = 'pointer'; 
    }); 
    box.on('mouseout', function() { 
     document.body.style.cursor = 'default'; 
    }); 

    layer.add(box); 
    stage.add(layer); 

    $(stage.content).on('mousewheel', ui.zoom); 
}); 
2

La demostración anterior sólo funciona si las coordenadas X e Y de la etapa son 0. Si, por ejemplo la etapa es arrastrable, cambiará estas coordenadas mientras arrastra, por lo que deben incluirse en el cálculo de compensación. Esto puede lograrse mediante restarlos de los desplazamientos de la lona:

jsfiddle

zoom: function(event) { 
    event.preventDefault(); 
    var evt = event.originalEvent, 
     mx = evt.offsetX - ui.scale.getX(), 
     my = evt.offsetY - ui.scale.getY(), 
    var zoom = (ui.zoomFactor - (evt.wheelDelta < 0 ? 0.2 : 0)); 
    var newscale = ui.scale * zoom; 

    var origin = ui.box.getPosition(); 
    origin.x = mx - (mx - origin.x) * zoom; 
    origin.y = my - (my - origin.y) * zoom; 

    ui.box.setPosition(origin.x, origin.y); 
    ui.box.setScale(newscale); 
    ui.stage.draw(); 

    ui.scale *= zoom; 
} 
Cuestiones relacionadas