在KineticJS中实现固定点缩放

8
我在缩放容器时遇到了一些问题,需要将内容缩放到一个固定点。
在我的情况下,我正在尝试将舞台(stage)缩放(放大/缩小)到鼠标光标位置。
以下是使用纯canvas的方法:http://phrogz.net/tmp/canvas_zoom_to_cursor.html (详见Zoom Canvas to Mouse Cursor)。
但我无法想出如何在使用KineticJS API时应用相同的逻辑。
以下是示例代码:
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();
4个回答

16

在经过许多挣扎、搜索和尝试后,使用 @Eric Rowell 提供的提示以及在SO问题Zoom in on a point (using scale and translate)中发布的代码,我终于使用KineticJS实现了固定点的缩放。

这是一个可以工作的演示

以下是代码:

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);
});​

嘿,谢谢,这个可以正常工作,但是我有很多层,所以我不能将层设置为“可拖动”。因此,我将舞台设置为可拖动。当我移动舞台时,我无法缩放到所需的缩放点。我必须重新计算一些东西,例如计算舞台的x和y,但我无法实现。你能帮我吗? - magirtopcu
@user1645941 请分享一些你正在处理的问题的工作示例(可以使用fiddle),我会尽力帮助你。 - juan.facorro
@juan.facorro 但在火狐浏览器中无法正常工作。你能修复一下吗? - DeLe
@trungkien 在Chrome中也不太正常,因此我将KineticJS版本更新到了4.4.3,现在一切似乎都正常了。 - juan.facorro

3

更新了@juan.facorro的演示,使其能够按比例缩放形状而不是整个舞台。

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);
});

3

您需要调整舞台的位置,使其中心点位于固定点。这是一个例子,因为舞台的中心点默认位于画布的左上角。假设您的舞台宽度为600px,高度为400px,并且您希望从中心缩放舞台。您需要执行以下操作:

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

2
上面的演示只有在舞台的x和y坐标为0时才有效。例如,如果舞台是可拖动的,则在拖动时它将更改这些坐标,因此它们需要包含在偏移量计算中。这可以通过从画布偏移量中减去它们来实现: 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;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接