【问题标题】:kinetic js ipad scrolling动力学 js ipad 滚动
【发布时间】:2012-11-21 05:56:08
【问题描述】:

我之前有一个基于 HTML5 画布的应用程序,我最近转换为使用 Kinetic JS。我能够通过简单地在包含的 div 上使用 overflow: auto 在桌面浏览器和 IOS 中启用滚动。由于转换为使用 Kinetic 滚动不再适用于移动/iPad 设备。

我尝试了几种不同的方法来解决这个问题,尽管我有点卡住了。首先,我尝试使用 touchscroll,但由于各种原因这对我不起作用(尽管库导致其他问题,但事情确实滚动了)。接下来,我尝试将 -webkit-overflow-scrolling: touch 选项添加到我的 div 样式中,尽管这似乎没有任何效果。

是否有滚动大于可视区域/div 的 Kinetic JS 画布的标准方法?

这是一个例子。如果您在 IOS 设备(iPad、iPhone 等)上查看示例,您会注意到顶部画布不会在 div 内滚动,而底部画布会滚动。

http://jsfiddle.net/blueshirts/uERVq/26/

<!-- KineticJS canvase, won't scroll on IOS devices. -->
<div id="container" style="overflow: auto; width: 400px; height: 400px; background-    color: gray">
</div>

<br/>

<!-- Vanilla HTML5 Canvas, does scroll on IOS devices. -->
<div id="canvasContainer"
     style="width: 400px; height: 400px; overflow: auto; background-color: red">
    <canvas id="vanillaCanvas"
            width="800" height="600">
    </canvas> 
</div>

// Create a stage instance that is larger than its parent div.
var stage = new Kinetic.Stage({
    container: 'container',
    width: 800,
    height: 600
});

// Create a layer.
var layer = new Kinetic.Layer();

// Add some text...
var text = new Kinetic.Text({
    text: "KineticJS generated Canvas that won't scroll to IOS touches...",
    x: 0,
    y: 0,
    fontSize: 12,
    fontFamily: 'Calibri',
    textFill: 'Black'                
});
layer.add(text);

// Add a rectangle to the layer so you can see if the content scrolls.
var rect = new Kinetic.Rect({
    x: 50,
    y: 50,
    width: 200,
    height: 100,
    fill: "yellow",
    stroke: "black",
    strokeWidth: 7
});
layer.add(rect);

// Add the layer to the stage.
stage.add(layer);


// Create a "vanilla" canvas instance and draw the same rectangle on it.
var canvas = document.getElementById('vanillaCanvas');
var context = canvas.getContext('2d');

context.beginPath();
context.rect(50, 50, 200, 100);
context.fillStyle = 'yellow';
context.fill();
context.lineWidth = 7;
context.strokeStyle = 'black';
context.stroke();

编辑:

可能是错误的,但在我看来,这个问题是由 Kinetic 在 Stage 类中注册 touchmove 事件(和其他事件)引起的。在它运行的处理程序中, preventDefault 似乎阻止移动浏览器执行其默认滚动行为。如果“我”已经注册了 touchmove 事件,这可能是可取的。如果 Kinetic 没有注册和处理我不感兴趣的事件,那就太好了。

 _touchmove: function(evt) {
     this._setUserPosition(evt);
     var dd = Kinetic.DD;
     evt.preventDefault();

我可以在这里演示这个问题:http://jsfiddle.net/blueshirts/P9RaT/28/

【问题讨论】:

    标签: jquery scroll kineticjs


    【解决方案1】:

    我认为这是 Kinetic JS 中的一个基本错误。如果我知道是这种情况,我就不会开始使用 kinetic JS 来着手一个雄心勃勃的项目,因为它甚至不能做基础。

    由于 Kinetic 团队没有任何回应,我将切换到 bug 较少的库,例如 fabric.js。

    【讨论】:

    • 在画布上添加一个“激活”/“停用”按钮。 deactivate 脚本将简单地执行类似检查舞台上的所有项目以查看它们是否正在“侦听”,如果为真,则将它们设置为“wasListening”或其他一些持有者变量,然后将侦听设置为 false。激活按钮检查舞台上的所有项目是否为“wasListening”,然后将它们设置为“listening(true)”。
    • 或者,让整个舞台“不听”,除非用户激活舞台上的特定控件。这样它将响应典型的滚动触摸事件。
    • 另外,你是说 Fabric js 可以处理你最初提到的情况吗?即:有一个网页,您可以在其中滚动交互式和侦听画布,使其完全填满屏幕,但仍然具有将网页滚动到该画布之外的功能?
    • 将形状对象设置为 listener:false 确实允许画布可滚动,但代价是具有静态形状。就我的目的而言,这还不够,因为我本质上是在创建图像映射并且需要对我的对象进行点击事件。所以具体的事件是滚动画布并点击形状。
    • 我不知道fabric是如何处理这个问题的,但是当一个形状不可拖动并且有一个用户可以滚动到ipad上的形状时,这是我想要的行为。我认为,如果您想要滚动画布上有许多带有点击事件的形状,这将变得不切实际。
    【解决方案2】:

    不确定我是否喜欢这个选项,尽管它比使用许多滚动库之一更好。我可以通过扩展默认 Stage 类并仅在我不在移动设备上时执行 evt.preventDefault() 来解决此问题。虽然到目前为止似乎符合我的用法,但不确定这可能会造成什么不良影响。如果有更简单的方法来修改默认行为,那就太好了。

    Kinetic.Global.extend(MyStage, Kinetic.Stage);
    function MyStage(mobile, config) {
        this.mobile = mobile;
        this._initStage(config);
    }
    MyStage.prototype._touchstart = function(evt) {
        this._setUserPosition(evt);
        if (this.mobile) {
            evt.preventDefault();
        }
        var obj = this.getIntersection(this.getUserPosition());
    
        if(obj && obj.shape) {
            var shape = obj.shape;
            this.tapStart = true;
            shape._handleEvent('touchstart', evt);
        }
    
        /*
                             * init stage drag and drop
                             */
        if(Kinetic.DD && this.attrs.draggable) {
            this._initDrag();
        }
    }
    MyStage.prototype._touchmove = function(evt) { // Override the default touchmove handler.
        this._setUserPosition(evt);
        var dd = Kinetic.DD;
        if (this.mobile) {
            evt.preventDefault();
        }
        var obj = this.getIntersection(this.getUserPosition());
        if(obj && obj.shape) {
            var shape = obj.shape;
            shape._handleEvent('touchmove', evt);
        }
    
        // start drag and drop
        if(dd) {
            dd._startDrag(evt);
        }
    }
    

    【讨论】:

      【解决方案3】:

      我可能不完全理解这个问题,但为什么不直接在舞台上添加 'draggable: true'

      // Create a stage instance that is larger than its parent div.
      var stage = new Kinetic.Stage({
          container: 'container',
          width: 800,
          height: 600,
          draggable: true
      });
      

      我正在使用同样的方法,其中我的画布是视口大小的几倍,并且使用“可拖动:真”我可以滚动画布图像。

      【讨论】:

      • 问题不在于滚动 canvas 上的内容,而是滚动具有画布的 webpage。在移动设备上,如果您有一个包含画布的网页,并且用户滚动或缩放以使您的画布填满屏幕,他们就无法再次“离开它”。这让我很头疼!
      • 是的,我也看到过同样的问题。我通过使用“关闭”按钮使画布部分成为弹出窗口,在我的应用程序中修复了它。就我而言,它有效。这是导致我出现问题的画布部分...(请注意,它在其自己的网页上被分开,但您会看到问题,此画布是启用触摸的,并且会填满 iPhone 5 的屏幕,然后您无法滚动它....就像你说的那样。除了将画布分成自己的弹出窗口之外,IO 找不到其他解决方案。github.com/JSdc/adobe-kuler-clone
      • 所以我能想到的唯一解决方法是“不要使用整个水平空间”来处理 Kinetic 对象。相反,让它用完(不是整个水平空间)(见图)(添加虚线以进行解释)cloud.githubusercontent.com/assets/6971009/2923289/… ---如果用户单击一个圆圈,则“不可选择”类将应用于整个面板。如果用户松开圆圈,则从面板中删除“不可选择”,因此用户可以通过按虚线的左侧或右侧来滚动……这非常直观。
      【解决方案4】:

      我在 iPad/iPhone 上使用 KineticJS 创建的地图滚动时遇到了同样的问题。

      这对我有用:stage.setListening(false);

      我在这里找到了这个解决方案:

      https://github.com/ericdrowell/KineticJS/pull/510

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多