之前在用h5做物理课件的时候发现,对于非整数的线,h5在渲染上有问题。
flash在课件开发中的优势
游标卡尺,对于刻度的准确性,要求是很严格的,毕竟,游标卡尺就是靠上下两层刻度相差的1/10mm来实现精确测量的。
渲染上的问题,导致直接显示错误了。无法准确的测量。
有一个简单的办法,就是在canvas中用svg图片,创建一个image,image的src用svg图片,然后把image画到canvas上。这样显示效果能保持svg的显示效果。
专业的矢量渲染,会好很多,比如flash,比如svg。
我们想要在canvas中实现一个游标卡尺,缩放的时候,要求保持准确性,有没有什么办法呢?
之前的文章中已经提到过,用canvas自身的方法,似乎是行不通的。
我们可以尝试自己去写渲染算法。
参考:
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像素。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。