Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

viewport.zoomTowards #1016

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open

viewport.zoomTowards #1016

wants to merge 1 commit into from

Conversation

naasking
Copy link
Contributor

@naasking naasking commented Mar 6, 2016

Extended viewport with a zoomTowards function that zooms from the current center towards a target point

@mucaho
Copy link
Contributor

mucaho commented Mar 6, 2016

That's a nice feature, it's a really natural way to zoom in, especially when combined with mouse scrolling.

I tested your implementation: It works for zooming in with absolute mouse coordinates (like when used in your JSFiddle you posted on the forum), but there is something a little bit off when using positions of entities in the game.
Run the following code with Crafty library built from your develop branch:

<html>
  <head>
    <script src="crafty.js"></script>
    <script>
      Crafty.viewport.zoomTowardsNew = function (amt, posX, posY, time, easingFn) {
        var scale = Crafty.viewport._scale,
            // current viewport center
            centX = -Crafty.viewport._x + Crafty.viewport._width / 2 / scale,
            centY = -Crafty.viewport._y + Crafty.viewport._height / 2 / scale,
            // direction vector from viewport center to position
            deltaX = posX - centX,
            deltaY = posY - centY;
        var f = amt - 1;

        Crafty.viewport.zoom(amt, centX + deltaX * f, centY + deltaY * f, time, easingFn);
      };
    </script>
  </head>
  <body>
    <div id="game"></div>
    <script>
      Crafty.init(300, 300, document.getElementById('game'));
      Crafty.background('rgb(127,127,127)');

      var green = Crafty.e('2D, Canvas, Color')
        .attr({ x: 200, y: 200, w: 100, h: 100})
        .color('green');
      var blue = Crafty.e('2D, Canvas, Color')
        .attr({x: -200, y: -200, w: 100, h: 100})
        .color('blue');

      Crafty.viewport.clampToEntities = false;
      Crafty.viewport.x = -100;
      Crafty.viewport.y = -100;
      // SWITCH COMMENTED STATEMENT HERE
      Crafty.viewport.zoomTowards(2, 250, 250, 3000);
      //Crafty.viewport.zoomTowardsNew(2, 250, 250, 3000)

      Crafty.viewport.mouselook(true);
      Crafty.bind("MouseWheelScroll", function (evt) {
        var pos = Crafty.domHelper.translate(evt.clientX, evt.clientY);
        Crafty.viewport.zoomTowardsNew(1 + evt.direction/10, pos.x, pos.y, 5);
      });
    </script>
  </body>
</html>

If I'm not mistaken: In the first 3 seconds, the Crafty.viewport.zoomTowards function should zoom in on the green box directly in the box's center, but the zoom center sways off to the bottom right corner (I will comment on the piece of code that I think is the culprit responsible for this). With new implementation the zoom centers stays.

Notice how Crafty.domHelper.translate is used to transform between browser space coordinates to Crafty's game world coordinate system.

var ybound = yorig + (Crafty.viewport.height / scale);
// target in scaled coords
pos_x = xorig + (pos_x || xorig) / scale;
pos_y = yorig + (pos_y || yorig) / scale;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think pos_x and pos_x need to be changed here

@starwed
Copy link
Member

starwed commented Mar 7, 2016

Silly question that I can't quite get from reading the code: what is the intended difference between this and the existing Crafty.zoom, which does move towards a point while it zooms?

@mucaho
Copy link
Contributor

mucaho commented Mar 7, 2016

what is the intended difference between this and the existing Crafty.zoom, which does move towards a point while it zooms?

It's particularly well suited for mousewheel scrolling, I didn't understand it myself until I tried it. Crafty.viewport.zoom snaps the viewport center promptly to the specified position when it's done zooming. Crafty.viewport.zoomTowards moves the viewport center just a bit in the direction of the specified position when it's done zooming. It's essentially just a thin convenience wrapper around zoom which calculates the "interpolated" position between current viewport center and the specified point for you.

@naasking
Copy link
Contributor Author

naasking commented Mar 7, 2016

Cool, wasn't aware of domHelper.translate. You're probably correct that the pos_x/y don't need to be changed. It looks like a hold over from the DOM translations needed in my viewing area, which I'll now look into replacing with domHelper.translate.

I was updating pos_x/y there also to accomodate them as optional parameters, the way viewport.zoom works, but I'm not sure it makes sense for them to be optional in this case. Your more concise version works as expected.

@naasking naasking closed this Mar 7, 2016
@naasking
Copy link
Contributor Author

naasking commented Mar 7, 2016

Oops, wrong button push. I'm not sure if you want me to make the changes on my repo and re-push, or if you just want to adopt the code you already wrote.

@naasking naasking reopened this Mar 7, 2016
@mucaho
Copy link
Contributor

mucaho commented Mar 8, 2016

Hmm, I'm still on the fence whether this should be merged into the library as a dedicated functionality, or provided as a full-fledged example to the MouseScroll documentation.
Currently I can see it only being used for map-like scrolling, so I kind of weigh towards the 2nd option. I'm also planning to augment the MouseScroll event with coordinates from Crafty.domHelper.translate, so the code above would be very concise.
If you or @starwed have some other use-cases or thoughts about it, please share.

@starwed
Copy link
Member

starwed commented Apr 3, 2016

Something to think about: the zoom function api is written as though the state of the viewport is determined by a scale factor and a center position. But to actually figure out the correct zoom behavior, I found it helpful to think about the viewport as being determined by it's top left and bottom right corners instead. (i.e., what Crafty coordinates are at those two positions.)

As an example, if you have a 100x100 viewport and double the scale while zooming in on the center, you can think of this as taking the points (0,0) and (100, 100) to (25, 25) and (75, 75) over the desired time.

If we had an api call that simply let you transition to a new set of corners, maybe that would make it easier to write a function like this? (I guess currently we don't allow separate scaling along the X or Y axis, but that would actually be pretty easy to allow.)

@mucaho
Copy link
Contributor

mucaho commented May 4, 2016

EDIT: Ported this to apidocs (see f1a60f0).

However, this could be a viewport option, which would automatically set up the map-like zooming for you. Similar to how Crafty.mouselook(true) enables you to drag the viewport, Crafty.mousezoom(true, mode) could enable you to scale the viewport:

  • mode === 'static': zoom the viewport, preserving current center
  • mode === 'dynamic': zoom viewport, moving current center (as proposed in this PR)

Note that Crafty.mousezoom would not work on mobile platforms.

(Additionally, in RTS games you can pan the viewport by moving the mouse to the screen edge, which could be another potential feature to be included into Crafty.mouselook).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants