在HTML画布上依次绘制连续的线条

时间:2015-04-27 19:36:46

标签: javascript canvas promise

我正在尝试为上述问题编写代码。我试着寻找解决方案。这就是我现在所拥有的。



var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');

var drawColorLine = function(start, end, color) {
  var deltaX, deltaY, i = 0,
    currLength = 0,
    isHor, isVert;

  deltaX = end[0] - start[0];
  deltaY = end[1] - start[1];
  context.strokeStyle = color;

  isHor = deltaX === 0 ? 0 : 1;
  isVert = deltaY === 0 ? 0 : 1;

  function draw() {
    context.beginPath();
    context.moveTo(start[0] + currLength * isHor, start[1] + currLength * isVert);

    currLength = currLength + 0.5 * i;
    context.lineTo(start[0] + currLength * isHor, start[1] + currLength * isVert);
    context.stroke();

    if (currLength <= Math.max(deltaX, deltaY)) {
      i = i + 1;
      requestAnimationFrame(draw);
    }
  }
  draw();
};

drawColorLine([40, 40], [100, 40], '#116699');
drawColorLine([40, 40], [40, 100], '#bb11dd');
&#13;
<canvas id='canvas' width='400' height='400'></canvas>
&#13;
&#13;
&#13;

问题是两者同时被绘制出来。一个人应该追随另一个人。使用promsises是否可以在第一个函数执行时延迟第二个函数,然后执行第二个函数?我试着读一下Promises,但我无法将我理解的内容翻译成代码。

提前致谢。

2 个答案:

答案 0 :(得分:5)

是的,您可以使用promises,尽管出于学习目的,您可能希望首先编写纯回调解决方案。

您需要查看我的rules of thumb承诺开发。我们在这里应用它们:

  1. 每个异步函数都必须返回一个promise。

    在您的案例中,这些将是drawColorLinedrawrequestAnimationFrame

  2. 由于requestAnimationFrame是一个原生的,原始异步的函数,遗憾的是它仍然需要回调,我们必须promisify它:

    function getAnimationFrame() {
        return new Promise(function(resolve) {
            requestAnimationFrame(resolve); // this promise never gets rejected
            // TODO: cancellation support :-)
        });
    }
    
  3. 异步操作后的所有内容都会进入.then()回调:

    function drawColorLine(start, end, color) {
        … // initialisation
    
        function draw() {
            … // do work
            // always return a promise:
            if (/* furter work */) {
                i++;
                return getAnimationFrame().then(draw); // magic happens here :-)
            } else {
                return Promise.resolve(…); // maybe have a path object as eventual result?
                                           // or anything else, including nothing (no arg)
            }
        }
        return draw(); // returns a promise - but don't forget the `return`
    }
    
  4. 瞧!

    drawColorLine([40, 40], [100, 40], '#116699').then(function() {
        return drawColorLine([40, 40], [40, 100], '#bb11dd');
    }).then(console.log.bind(console, "both lines drawn"));
    

答案 1 :(得分:2)

尝试使用.animate()jQuery.Deferred()

<?php 
    require_once '../../inc/config.php';
    $response = array();
    $response['errors'] = false;
    $id = $_REQUEST['id'];

    if(!empty($_FILES)){
        //set default data arrays
        $names = array(); //stores file names
        $files = array(); //stores the file data
        $mime_types = array(); //store the file type as a mime type

        //force each file name to the names array
        foreach($_FILES['file']['name'] as $name){
            array_push($names, $name);
        }
        //force the file data into its own array spot in the files array
        foreach($_FILES['file']['tmp_name'] as $temp){
            array_push($files, prepareImageDBString($temp));
        }
        //force the mimetypes into the mime_types array
        foreach($_FILES['file']['type'] as $type){
            array_push($mime_types, $type);
        }

        //process all three of the file arrays simultaneously so that no data is left out
        for($i = 0; $i < count($names); $i++){
            $file_name = $names[$i];
            $file_data = $files[$i];
            $mime_type = $mime_types[$i];

            //set the query for the data to go into the note_file table in the database 
            $q = "INSERT INTO brb.files (customer__id, file_name, file_data, mime_type)
            VALUES('$id', '$file_name', '$file_data', '$mime_type')";
            //run the query
            if($stmt = $CONN->prepare($q)){
            //process any errors that may occur

                if(!$stmt->execute()){
                    printf("Error Message: %s\n", $CONN->error);
                }
            }
        }

    }


    echo json_encode($response);

    function prepareImageDBString($filepath){
        $out = 'null';
        $handle = fopen($filepath, 'r');
        if($handle){
            $content = fread($handle, filesize($filepath));
            $content = bin2hex($content);
            fclose($handle);
            $out = $content;
        }

        return $out;
    }
?>
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');

var drawColorLine = function(start, end, color) {
  // create new `deferred` object
  var dfd = new $.Deferred(),
    deltaX, deltaY, i = 0,
    currLength = 0,
    isHor, isVert,
    // create animation object
    props = $({"prop":i}); 

  deltaX = end[0] - start[0];
  deltaY = end[1] - start[1];
  context.strokeStyle = color;

  isHor = deltaX === 0 ? 0 : 1;
  isVert = deltaY === 0 ? 0 : 1;

  function draw(n) {
    context.beginPath();
    context.moveTo(start[0] + currLength * isHor
                   , start[1] + currLength * isVert);

    currLength = currLength + 0.5 * n;
    context.lineTo(start[0] + currLength * isHor
                   , start[1] + currLength * isVert);
    context.stroke();

    if (currLength <= Math.max(deltaX, deltaY)) {
      // create object to animate,
      // do animation stuff      
      props.animate({"prop":1}, {
        // set duration of animation
        duration:10, 
        complete:function() {
          // increment `n`:`i`
          n = n + 1;
          // call `draw` with `n` as parameter
          draw(n)
        }
      })         
    } else {
      // if `currLength > Math.max(deltaX, deltaY)`,
      // resolve `deferred` object, 
      // set `canvas` element as `this` at `.then()`
      // pass `deltaX`, `deltaY`, `currLength`, `n`` 
      // arguments to `.then()`
      dfd.resolveWith(canvas, [deltaX, deltaY, currLength, n]);
    }

    }
  draw(i);
  // return jQuery promise object
  return dfd.promise()
};
// draw first line
drawColorLine([40, 40], [100, 40], '#116699')
.then(function() {
  console.log("first line complete", arguments, this);
  // draw sencond line
  return drawColorLine([40, 40], [40, 100], '#bb11dd');
}).then(function() {
  console.log("second line complete", arguments, this);
})