【问题标题】:RXJS draw line on html5 canvasRXJS 在 html5 画布上画线
【发布时间】:2014-03-06 13:20:46
【问题描述】:

我正在尝试使用 Reactive Extensions for Javascript (RX-JS) 来达到我在此处发布的相同效果。 我对如何做到这一点有点困惑。 这是页面:

      <!DOCTYPE html>
      <html>
      <head>
        <title>drag and drop</title>
      </head>
      <style type="text/css">

      canvas {
        border:1px solid steelblue;
        background-color: whitesmoke;
      }

      </style>
      <body>
        <canvas id="canvas" width=300 height=300></canvas>
        <script type="text/javascript" src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
        <script type="text/javascript">
        $(function() {
            var canvas = document.getElementById("canvas");
            var ctx = canvas.getContext("2d");

            var canvasOffset = $("#canvas").offset();
            var offsetX = canvasOffset.left;
            var offsetY = canvasOffset.top;

            var drawing = false;
            var mouseX = 0;
            var mouseY = 0;


            function handleMouseDown(e) {
                mouseX = parseInt(e.clientX - offsetX);
                mouseY = parseInt(e.clientY - offsetY);         
                drawing= true;                
        }

        function handleMouseUp(e) {             
            drawing = false;    
        }
        function handleMouseMove(e) {
            if(drawing){
              mouseeX = parseInt(e.clientX - offsetX);
              mouseeY = parseInt(e.clientY - offsetY);
              $("#movelog").html("Move: " + mouseX + " / " + mouseY);

                var ctx =  canvas.getContext("2d");
                // some cleanup code
                ctx.save();
                ctx.setTransform(1, 0, 0, 1, 0, 0);
                ctx.clearRect(0, 0, canvas.width, canvas.height);
                ctx.restore();          
                ctx.beginPath();
                ctx.moveTo(mouseX,mouseY);
                ctx.lineTo(mouseeX,mouseeY);
                ctx.stroke();
             }
        }

        $("#canvas").mousedown(function(e) {
            handleMouseDown(e);
        });
        $("#canvas").mousemove(function(e) {
            handleMouseMove(e);
        });
        $("#canvas").mouseup(function(e) {
            handleMouseUp(e);
        });

      });
      </script> 
      </body>
      </html>

我认为我应该为 mouseDown、mouseMove 和 mouseUp 事件创建 observables。

    var mouseDown = Rx.Observable.fromEvent(canvas, 'mousedown');
    var mouseMove = Rx.Observable.fromEvent(canvas, 'mousemove');
    var mouseUp = Rx.Observable.fromEvent(canvas, 'mouseup');

但我不知道如何组合它们。我认为应该开始观察 mousedown,然后收集所有移动,直到 mouseup 被提升,并同时重新绘制从起点到鼠标在 mousemove 期间鼠标所在的当前点的线。 你有什么想法?非常感谢。

°°°°°°°°°°°°°°°°°°°°°°°编辑°°°°°°°°°°°°°°°°°°°°°°°°° °°°°°°°°°°°°°

这是我在 Brandon 回答后的代码:

              $(function() {

                  var canvas = document.getElementById('canvas');
                  var ctx = canvas.getContext("2d");
                  var canvasOffset = $("#canvas").offset();
                  var offsetX = canvasOffset.left;
                  var offsetY = canvasOffset.top;

                  var mouseDown = Rx.Observable.fromEvent($("#canvas"), 'mousedown');
                  var mouseMove = Rx.Observable.fromEvent($("#canvas"), 'mousemove');
                  var mouseUp = Rx.Observable.fromEvent($("#canvas"), 'mouseup');

                  // keep a reference to the pisition when the mouse down was fired
                  // then flatten the stream with concatAll


                  var traceLineStream = mouseDown.map(function(md) {
                      var movesFromMouseDown = mouseMove.takeUntil(mouseUp);
                      var movesFromMouseDownAndMouseDown = movesFromMouseDown.map(function(mm) {
                          return {
                              mouseDownPoint: md,
                              mouseMovePoint: mm
                          }
                      });
                      return movesFromMouseDownAndMouseDown;
                  }).concatAll();


                  var subscription = traceLineStream.subscribe(
                      function(y) {

                          var mouseDown = y.mouseDownPoint;
                          var mouseMove = y.mouseMovePoint;

                          var mouseDownX = parseInt(mouseDown.clientX - offsetX);
                          var mouseDownY = parseInt(mouseDown.clientY - offsetY);               

                          var mouseMoveX = parseInt(mouseMove.clientX - offsetX);
                          var mouseMoveY = parseInt(mouseMove.clientY - offsetY);

                          ctx.save();
                          ctx.setTransform(1, 0, 0, 1, 0, 0);
                          ctx.clearRect(0, 0, canvas.width, canvas.height);
                          ctx.restore();
                          ctx.beginPath();
                          ctx.moveTo(mouseDownX, mouseDownY);
                          ctx.lineTo(mouseMoveX, mouseMoveY);
                          ctx.stroke();

                      },
                      function(e) {
                          console.log('onError: ' + e.message);
                      },
                      function() {
                          console.log('onCompleted');
                      });
              });

【问题讨论】:

    标签: javascript html canvas system.reactive rxjs


    【解决方案1】:

    首先,合并流,这样您就有了代表单个拖动的事件流。

    var drag = mouseDown.first().concat(mouseMove.takeUntil(mouseUp));
    

    接下来,将此事件流投影到previous,current 元组流中。

    var moves = drag
        .scan({}, function(acc, x) {
            return { previous: acc.current, current: x };
        })
        .skip(1);
    

    现在我们有一个只在第一次工作的流。当它结束时,我们要开始监听下一次拖动:

    var allMoves = moves.repeat();
    

    最后,订阅:

    allMoves.subscribe(function (move) {
        var mouseX = move.previous.clientX - offsetX,
            mouseY = move.previous.clientY - offsetY,
            mouseeX = move.current.clientX - offsetX,
            mouseeY = move.current.clientY - offsetY,
        ...
    });
    

    将它们放在一起,没有所有中间变量:

    mouseDown
        .first()
        .concat(mouseMove.takeUntil(mouseUp))
        .scan({}, function(acc, x) {
            return { previous: acc.current, current: x };
        })
        .skip(1)
        .repeat()
        .subscribe(function (move) {
            var mouseX = move.previous.clientX - offsetX,
                mouseY = move.previous.clientY - offsetY,
                mouseeX = move.current.clientX - offsetX,
                mouseeY = move.current.clientY - offsetY,
            ...
        });
    

    【讨论】:

    • 嗨,布兰登,感谢您的回答。这不完全是我想要的,但它是灵感的来源。我努力工作并得到了我想要实现的目标。
    猜你喜欢
    • 2015-03-24
    • 2011-05-24
    • 2012-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多