javascript - RXJS 在 html5 Canvas 上画线

标签 javascript html canvas system.reactive rxjs

我正在尝试使用 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 事件创建可观察对象。

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

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

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

这是布兰登回答后我的代码:

              $(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');
                      });
              });

最佳答案

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

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

关于javascript - RXJS 在 html5 Canvas 上画线,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22225810/

相关文章:

HTML CSS 如何去掉滚动条让网站全屏?

javascript - 是否可以在 Canvas 的同一路径上使用两种不同的笔触样式?

javascript - 从数组中获取不包括先前选择的随机值

javascript - 如何在 JavaScript 中将多个变量列出到单个变量中?

JavaScript 接口(interface)可以工作,但需要调用该函数两次

javascript - UWP Web View : add tags to selected text

javascript - 让加载屏幕与 Polymer 配合使用

internet-explorer - 在 VML 中使用@font-face(通过 excanvas)

javascript - 打印或导出Cesium图加载部门

javascript - 确定javascript中单击对象的类型