01
2025
09

canvas画游标卡尺刻度

之前在用h5做物理课件的时候发现,对于非整数的线,h5在渲染上有问题。

flash在课件开发中的优势

游标卡尺,对于刻度的准确性,要求是很严格的,毕竟,游标卡尺就是靠上下两层刻度相差的1/10mm来实现精确测量的。

渲染上的问题,导致直接显示错误了。无法准确的测量。

专业的矢量渲染,会好很多,比如flash,比如svg。

我们想要在canvas中实现一个游标卡尺,缩放的时候,要求保持准确性,有没有什么办法呢?

之前的文章中已经提到过,用canvas自身的方法,似乎是行不通的。

我们可以尝试自己去写渲染算法。

参考:

简要评说Adobe的FlashPlayer的渲染算法

计算几何系列 —— 扫描线算法

图形学中的抗锯齿方法简谈

Computer Graphics from Scratch

可视计算与交互概论

揭秘图像缩小:深度解析算法原理与优化技巧

我们这个问题,属于图像缩小,找图像缩小的算法。

我尝试了3种方法,第一种:最近邻插值:直接取最近的像素值作为新的像素值。
第二种:双线性插值:利用周围两个像素点的加权平均值作为新的像素值。

第三种:原图像的像素点加权平局赋值给目标像素。

效果如下:

在新标签页打开    

代码如下:

<html>
  <head>
    <script>
      var canvas,ctx,input,select;
      var data0 = [];
      var data1 = [];
      for(var i = 0; i < 1800; i++) {
        data0[i] = (i % 10 <= 2) ? 0 : 1;
        data1[i] = (i % 9 <= 2) ? 0 : 1;
      }
      window.onload = function(){
        canvas = document.getElementById("canvas");
        ctx = canvas.getContext("2d");
        input = document.getElementById("input");
        select = document.getElementById("select");
        setData(10, 100, data0);
        setData(10, 110, data1);

        onInput();
      }

      function onChange(e){
        //console.log("change");
      }

      function onInput(e) {
        // console.log("input",input.value);
        ctx.clearRect(0, 200, 1900, 20);

        var w = input.value;
        var m = select.selectedIndex;
        var data2 = suoxiao(data0, w, m);
        var data3 = suoxiao(data1, w, m);
        setData(10, 200, data2);
        setData(10, 210, data3);
      }

      function suoxiao(data, w, m) {
        var n = data.length;
        var s = n / w;
        var a = [];
        for(var i = 0; i < w; i++){
          a[i] = 0;
        }
        if(m == 1) {
          for(var i = 0; i < w; i++) {
            var j = i * s;
            var j0 = Math.floor(j);
            var j1 = Math.ceil(j);
            var v0 = data[j0];
            var v1 = data[j1];
            var f = j - j0;
            a[i] = (v1 * f) + v0 * (1-f);
          }
        } else if(m == 2){
          for(var i = 0; i < n; i++) {
            var j = i / s;
            var v = data[i] / s;
            var j0 = Math.floor(j);
            var j1 = Math.ceil(j);
            var f = j - j0;
            if(j0 >= 0 && j0 < w) a[j0] += v * (1-f);
            if(j1 >= 0 && j1 < w) a[j1] += v * f;
          }
        } else {
          for(var i = 0; i < w; i++) {
            var j = Math.round(i * s);
            a[i] = data[j];
          }
        }
        return a;
      }

      function setData(x, y, data0){
        var w = data0.length;
        var imgData = ctx.getImageData(x, y, w, 10);
        for(var i = 0; i < w; i++) {
          for(var j = 0; j < 10; j++){
            var n = (j * w + i) * 4;
            imgData.data[n] = data0[i] * 255;
            imgData.data[n + 1] = data0[i] * 255;
            imgData.data[n + 2] = data0[i] * 255;
            imgData.data[n + 3] = 255;
          }
        }
        ctx.putImageData(imgData, x, y);
      }
    </script>
  </head>
  <body>
    <select id="select">
      <option value="1">方法一</option>
      <option value="2">方法二</option>
      <option value="3">方法三</option>
    </select>
    <input id="input" type="range" min="1" max="3800" value="1800"  step="1" style="width: 1900px;" onchange="onChange()" oninput="onInput()"/>
    <canvas id="canvas" width="1900" height="1000" style="width: 1900px;height: 1000px;border: solid 1px red;"></canvas>
  </body>
</html>

方法一效果和原生的差不多。

方法二好一点。方法三效果更好。

对于放大的场景,方法三有问题,可以用方法二,或者方法一,或者直接用原生的。

游标卡尺的刻度计算是一维问题,计算量也不是很大。在显示的时候我们取了高度10像素,实际使用的时候,高度1像素就行,拉伸成10像素。



« 上一篇下一篇 »

相关文章:

canvas窗口自适应  (2021-6-24 9:0:7)

flash在课件开发中的优势  (2021-5-26 8:45:37)

场景的平移和缩放  (2020-6-8 9:1:2)

DataURL与File,Blob,canvas对象之间的互相转换的Javascript  (2016-11-25 14:58:41)

(十)hEngine—时钟  (2015-12-21 14:34:48)

(九)hEngine—画波形图  (2015-12-21 12:4:46)

(八)hEngine—打气球小游戏  (2015-12-18 11:0:22)

(七)hEngine—类继承关系  (2015-12-17 13:11:27)

(六)hEngine—事件  (2015-12-17 11:39:44)

(五)hEngine—几何运算类HPoint、HRectange  (2015-12-17 11:34:26)

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。