使用 Canvas 在 JS 中动画排序算法

2024-02-25

为了好玩,我尝试创建不同排序算法的可视化,但我遇到了 Canvas 动画的问题。

我假设我只能在排序器方法中调用绘制函数,但这会导致浏览器锁定,直到数组完全排序,然后绘制一些中间帧。

我将如何在排序方法中进行动画处理?下面是我到目前为止的代码,我不会运行此代码片段,因为它会将选项卡挂起几秒钟。

N = 250; // Array Size
XYs = 5; // Element Visual Size
Xp = 1; // Start Pos X
Yp = 1; // Start Pos Y
var canvas;
var l = Array.apply(null, {
  length: N
}).map(Number.call, Number);

Array.prototype.shuffle = function() {
  var i = this.length,
    j, temp;
  if (i == 0) return this;
  while (--i) {
    j = Math.floor(Math.random() * (i + 1));
    temp = this[i];
    this[i] = this[j];
    this[j] = temp;
  }
  return this;
}

function map_range(x, in_min, in_max, out_min, out_max) {
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

function rainbow(x) {
  var m = map_range(x, 0, N, 0, 359);
  return 'hsl(' + m + ',100%,50%)';
}

function init() {
  canvas = document.getElementById('canvas');
  l.shuffle();
  draw();
  bubbleSort(l);
}

function draw() {
  if (canvas.getContext) {
    var ctx = canvas.getContext('2d');
    for (var i = 0; i < l.length; i++) {
      ctx.fillStyle = rainbow(l[i]);
      ctx.fillRect((Xp * i) * XYs, Yp * XYs, XYs, XYs);
    }
  }
}

function bubbleSort(a) {
  var swapped;
  do {
    swapped = false;
    for (var i = 0; i < a.length - 1; i++) {
      if (a[i] > a[i + 1]) {
        var temp = a[i];
        a[i] = a[i + 1];
        a[i + 1] = temp;
        swapped = true;
        draw();
        setTimeout(function() {}, 10);
      }
    }
  } while (swapped);
}
<html>

<body onload="init();">
  <canvas id="canvas" width="1500" height="1500"></canvas>
</body>

</html>

一种解决方案是ES6 发电机function* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function%2A连同它的yield陈述。

这允许您暂停一个函数并稍后在暂停的地方重新启动它:

N = 100; // Array Size
XYs = 5; // Element Visual Size
Xp = 1; // Start Pos X
Yp = 1; // Start Pos Y
var canvas;
var l = Array.apply(null, {
  length: N
}).map(Number.call, Number);

Array.prototype.shuffle = function() {
  var i = this.length,
    j, temp;
  if (i == 0) return this;
  while (--i) {
    j = Math.floor(Math.random() * (i + 1));
    temp = this[i];
    this[i] = this[j];
    this[j] = temp;
  }
  return this;
}

function map_range(x, in_min, in_max, out_min, out_max) {
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

function rainbow(x) {
  var m = map_range(x, 0, N, 0, 359);
  return 'hsl(' + m + ',100%,50%)';
}

function init() {
  canvas = document.getElementById('canvas');
  l.shuffle();
  var sort = bubbleSort(l);
  // an anim function triggered every 60th of a second
  function anim(){
    requestAnimationFrame(anim);
    draw();
    sort.next(); // call next iteration of the bubbleSort function
  }
  anim();
}

function draw() {
  if (canvas.getContext) {
    var ctx = canvas.getContext('2d');
    for (var i = 0; i < l.length; i++) {
      ctx.fillStyle = rainbow(l[i]);
      ctx.fillRect((Xp * i) * XYs, Yp * XYs, XYs, XYs);
    }
  }
}

function* bubbleSort(a) { // * is magic
  var swapped;
  do {
    swapped = false;
    for (var i = 0; i < a.length - 1; i++) {
      if (a[i] > a[i + 1]) {
        var temp = a[i];
        a[i] = a[i + 1];
        a[i + 1] = temp;
        swapped = true;
        yield swapped; // pause here
      }
    }
  } while (swapped);
}
init();
<canvas id="canvas" width="500" height="20">

您现在还可以使用async/await https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function为了实现相同目标的更具可读性的代码:

const N = 100; // Array Size
const XYs = 5; // Element Visual Size
const Xp = 1; // Start Pos X
const Yp = 1; // Start Pos Y
let canvas;
const l = Array.from({ length: N }, (_,i) => i);

Array.prototype.shuffle = function() {
  let i = this.length;
  if (i == 0) return this;
  while (--i) {
    const j = Math.floor(Math.random() * (i + 1));
    const temp = this[i];
    this[i] = this[j];
    this[j] = temp;
  }
  return this;
}

function map_range(x, in_min, in_max, out_min, out_max) {
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

function rainbow(x) {
  const m = map_range(x, 0, N, 0, 359);
  return 'hsl(' + m + ',100%,50%)';
}

function init() {
  canvas = document.getElementById('canvas');
  l.shuffle();
  bubbleSort(l);
}

function draw() {
  if (canvas.getContext) {
    const ctx = canvas.getContext('2d');
    for (let i = 0; i < l.length; i++) {
      ctx.fillStyle = rainbow(l[i]);
      ctx.fillRect((Xp * i) * XYs, Yp * XYs, XYs, XYs);
    }
  }
}
function drawNextFrame() {
  return new Promise((res) => requestAnimationFrame(res))
    .then(draw);
}
async function bubbleSort(a) { // async is magic
  let swapped;
  do {
    swapped = false;
    for (let i = 0; i < a.length - 1; i++) {
      if (a[i] > a[i + 1]) {
        const temp = a[i];
        a[i] = a[i + 1];
        a[i + 1] = temp;
        swapped = true;
        await drawNextFrame(); // pause here
      }
    }
  } while (swapped);
}
init();
<canvas id="canvas" width="500" height="20">
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 Canvas 在 JS 中动画排序算法 的相关文章

  • 赋予 d3 序数轴标签与尺度名称不同

    我有一个序数scale具有不同值的某些标签 我想显示该比例的轴 其中轴标签与比例标签不同 我有这个代码 var width 1000 var height 600 var margins left 100 40 right 25 botto
  • 在 Bootstrap 3 中将容器类嵌套在容器流体类中?

    除了填充问题之外 为什么不建议将 container 嵌套在 container fluid 中 如果将子容器填充归零 如下面我的代码所示 则效果与拥有一个容器相同 此外 如今 不同的全宽和固定宽度布局似乎很常见 我知道文档说了什么 LIN
  • Angular 7 Guard 重定向仅适用于双击

    问题是我已经实现了一个 Guard 旨在处理特定的目录 如果当前用户名的角色等于 2 它应该返回 true 如果没有 那么它不应该重定向 这是我的 app routing module ts 文件 问题出在 userlist 路径中 我们是
  • Javascript 根据字段值任意排序数组

    所以我有一个对象数组 如下所示 var myArray priority low priority critical priority high 我需要以这种方式排序 1 关键 2 高和3 低 如何才能做到这一点 我建议使用一个对象来存储排
  • Angular UI.Bootstrap 单选按钮在 ng-repeat 中表现得很奇怪[重复]

    这个问题在这里已经有答案了 我在 Angular 的 ui bootstrap 中动态生成无线电模型的选项时遇到问题 我想我可以简单地对数组进行 ng repeat 使用 btn radio 属性的内容 如下所示 in the contro
  • 通过电子邮件发送在 HTML5 画布上创建的图像

    我有一个画布 用户可以通过交互来更改设计 现在 用户完成更改后 可以提交他的设计及其电子邮件 ID 但为了提交设计 我使用以下方法将画布转换为图像http www nihilogic dk labs canvas2image http ww
  • Django 模板变量从 {% for %} 循环到 Javascript

    这是一个迭代记录的 Django 模板 每条记录都包含一个由 JS 函数填充的 div 为了让 JS 知道要做什么 它需要从每次 for 循环迭代中获取一个变量并使用它 我不知道具体如何实现这一目标或是否可能 我不知道 也许记录在单独的 J
  • 函数声明或函数表达式

    我刚刚在块作用域中定义函数时遇到了问题 考虑以下程序 try greet function greet alert Merry Christmas catch error alert error 我希望这个程序能够发出警报Merry Chr
  • WPF - 按多列排序时使用自定义比较器

    我有一个 ListView GridView 我想按 2 列排序 因此如果第 1 列中有 2 个以上的项目具有相同的值 它将按第 2 列排序 非常简单 但是在对 A Z 进行排序时 空字符串会出现在顶部 我想把它们移到底部 我制作了一个比较
  • 如何混淆或使 JavaScript 文件不可读?

    我的应用程序中有 JavaScript 脚本 其中包含 JavaScript 和 jQuery 函数 所有用户与我的应用程序的交互都是动态的 并且通过 jQuery 传递到应用程序 我意识到 当我在客户端运行我的应用程序时 客户端可以通过查
  • IE 中的文件上传按钮和奇怪的文本光标行为

    我构建了一个上传按钮 其格式类似于典型的 html 按钮 而不是浏览器标准文件上传表单 该方法是设置锚元素的样式并在顶部覆盖透明文件输入元素 这种方法在除 IE 之外的所有浏览器中都可以正常工作 在 IE 中 当用户单击上传按钮时 会出现一
  • 当元素具有多个类时如何在 switch 语句中检查 className

    在下面的示例中 我只想单击该选项以在警报中显示 我正在尝试使用 switch 语句来确定单击了哪个类 如果我的 div 不包含多个类 则我的示例将有效 我尝试使用classList contains在我的 switch 语句中无济于事 有没
  • Javascript/DOM:如何删除 DOM 对象的所有事件侦听器?

    只是问题 有没有办法完全删除对象的所有事件 例如一个div 编辑 我添加每div addEventListener click eventReturner false 一个事件 function eventReturner return f
  • router.navigate 使用查询参数 Angular 5

    我在使用查询参数路由到路由时遇到问题我有一个像这样的函数 goToLink link this router navigate link split 0 queryParams this sortParams link 和这个功能 sort
  • jVectorMap - 向下钻取地图 - 自定义背景

    我正在使用 jVectorMap 中的向下钻取地图 并且尝试将自定义背景颜色设置为地图的第二层 为了自定义主级别 我使用 main 参数 但我不知道如何将其扩展到地图的较低级别 提前致谢 马切伊 None
  • Javascript 替换为正则表达式无法正常工作

    我正在尝试使用正则表达式验证名称 正则表达式阻止用户连续输入 2 个空格或点 这是我的代码 function test input var regex A Za z 0 1 s 0 1 input value input value rep
  • JavaScript 比较中应使用哪个等于运算符(== 与 ===)?

    这个问题的答案是社区努力 help privileges edit community wiki 编辑现有答案以改进这篇文章 目前不接受新的答案或互动 我在用着JSLint http en wikipedia org wiki JSLint
  • ☺ 不在移动版本中呈现

    我如何获得特殊角色 笑脸在移动浏览器中正确呈现 li a href http goo gl GjxlI title target blank span style font size 20px span a li 它在大多数浏览器上显示为
  • 网页执行回发时如何停止在注册表单上?

    我正在做我的最后一年的项目 其中 我在一页上有登录和注册表单 WebForm 当用户点击锚点时Sign Up下拉菜单ddlType 隐藏 和文本框 txtCustName txtEmail and txtConfirmPassword 显示
  • Ie11 不应用媒体查询样式

    IE11 忽略我的媒体查询并始终使用移动 CSS 奇怪的是 如果我改变浏览器宽度 即使只是 1 2 像素 浏览器也会自行渲染并显示媒体查询 我尝试了 css lint 我的 css 中没有错误 我的CSS没有什么特别的 只是简单的 css

随机推荐