wise9 / enchant.js

A simple JavaScript framework for creating games and apps
http://enchantjs.com
MIT License
1.69k stars 314 forks source link

touchevent objects not responding after window resize #324

Open seanbeauchamp opened 8 years ago

seanbeauchamp commented 8 years ago

If there's an obvious fix I'm missing then feel free to disregard, but it appears items designed to be clicked on in an Enchant game no longer respond when a window is resized. Returning the window back to the original size returns functionality, but there doesn't seem to be a way to reposition the touch-area for objects with a command like window.onresize.

seraku24 commented 8 years ago

The underlying issue seems clear upon a quick code review. Touch/mouse events are relying on pageX and pageY which need to be translated to match the stage element's positioning. The Core object defines and initially sets the values _pageX and _pageY to the upper-left bounds of the stage element, however they are never updated beyond first initialization. I suspect the original authors reasoned that, in most cases, the absolute position of the stage element would not change.

I am no expert in web development, so my knowledge is definitely lacking in areas; however, I have to wonder: why are absolute coordinates being used in the first place? If it is possible to obtain coordinates relative to the stage element from the original touch/mouse events, then no coordinate conversion would be needed. This would probably be a good line of investigation, unfortunately I do not have any more time to devote beyond this post.

Provided page-centric coordinates must be used, one possible fix involves monitoring the stage element for changes in positioning, to allow the Core object to maintain those two member variables. Alternatively, the Event._initPosition function could query the current location of the stage element dynamically, making the cached values unnecessary. Profiling would be required to determine if this on-demand approach is acceptable from a performance standpoint.

Until the best course of action is determined and implemented, it should be easy enough to work around the issue. When you detect the position of the stage element has changed, manually recompute the values within the Core object using something like the following:

if (enchant.Core.instance) {
    var core = enchant.Core.instance;
    var bounding = core._element.getBoundingClientRect();
    core._pageX = Math.round(window.scrollX || window.pageXOffset + bounding.left);
    core._pageY = Math.round(window.scrollY || window.pageYOffset + bounding.top);
}

If it is not practical to monitor the stage element, you instead could replace the Event._initPosition function with one that dynamically queries the placement of the stage element, similar to the following:

if (enchant.Core.instance) {
    console.log("enchant.js detected.  Patching Event._initPosition to workaround issue #324.");
    enchant.Event.prototype._initPosition = function(pageX, pageY) {
        var core = enchant.Core.instance;
        var bounding = core._element.getBoundingClientRect();
        var stageX = Math.round(window.scrollX || window.pageXOffset + bounding.left);
        var stageY = Math.round(window.scrollY || window.pageYOffset + bounding.top);
        this.x = this.localX = (pageX - stageX) / core.scale;
        this.y = this.localY = (pageY - stageY) / core.scale;
    };
}

NOTE: I have done only minimal testing of these snippets, so do take care to test them carefully to ensure they function well in your environment.

wenoptics commented 7 years ago

Thank you for your work @seraku24