线性插值编写可视化代码
线性插值
处于创意编码,游戏开发,数据可视化和生成创意的功能
[start,end]
在范围内插值,t通常在[0,1]
范围内
function lerp (start, end, t) {
return start * (1 - t) + end * t;
}
//虽然这样,但是我感觉现在这样,更容易理解
start+(end-start)*t
// 当 t 为 50%的时候,结果为50
lerp(0, 100, 0.5); // 50
// 当 t 为 0% 的时候,结果20
lerp(20, 80, 0); // 20
// 当t 为1 的时候,结果为5
lerp(30, 5, 1); // 5
lerp(-1, 1, 0.5); // 0
lerp(0.5, 1, 0.5); // 0.75
案例
lerp(20, 50, t)
逐渐增大圆的半径或lerp(20, 10, t)
逐渐减小其线的粗细
关键代码
// 半径20-50
const radius = lerp(20, 50, t);
// 线宽 20-10
const lineWidth = lerp(20, 10, t);
const canvasSketch = require('canvas-sketch');
function lerp (start, end, t) {
return start * (1 - t) + end * t;
}
const settings = {
dimensions: [ 512, 512 ],
animate: true,
duration: 5
};
const rect = (context, x, y, width, height, color) => {
context.fillStyle = color;
context.fillRect(x, y, width, height);
};
const circle = (context, x, y, radius, color, lineWidth) => {
context.strokeStyle = context.fillStyle = color;
context.beginPath();
context.arc(x, y, radius, 0, Math.PI * 2, false);
context.lineWidth = lineWidth;
if (lineWidth != null) context.stroke();
else context.fill();
};
const progress = (context, time, width, height, margin = 0) => {
context.fillStyle = 'white';
context.fillRect(
margin * 2,
height - margin * 2,
(width - margin * 4) * time,
4
);
};
const sketch = ({ width, height }) => {
const margin = 25;
return props => {
// 拿到我们需要的属性
const { context, width, height, playhead } = props;
// 设置距离margin的背景
rect(context, margin, margin, width - margin * 2, height - margin * 2, '#e5b5b5');
// 画出场景
draw(props);
// 在下面画一个时间轴
progress(context, playhead, width, height, margin);
};
function draw ({ context, width, height, playhead, deltaTime }) {
// Get our 0..1 range value
const t = playhead;
// 半径20-50
const radius = lerp(20, 50, t);
// 线宽 20-10
const lineWidth = lerp(20, 10, t);
// 画圆
circle(context, width / 2, height / 2, radius, 'white', lineWidth);
}
};
canvasSketch(sketch, settings);
逆线性插值
我们需要20过渡到40的比例是50%,值设置了30
假设您要对0到100像素之间的滚动位置做出反应。我们称它们为a
和b
。用下面的逆线性插值,你在传递a
,b
以及滚动位置v
function invlerp(a, b, v) {
return ( v - a ) / ( b - a )
}
但是我们会发现返回的值可能会大于1,超过两个极限
const lerp = (x, y, a) => x * (1 - a) + y * a
const invlerp = (a, b, v) => clamp(( v - a ) / ( b - a ))
const clamp = (v, min = 0, max = 1) => Math.min(max, Math.max(min, v))
我自己也是很蒙蔽,直接上案例
invlerp(20, 40, 20) // 0
invlerp(20, 40, 30) // 0.5
结果范围20-40
结果返回的是0-1
在小于等于20的时候都是0
大于等于40的时候都是1
demo
See the Pen 线性插值 by 973782523
(@973782523) on CodePen.