线性插值编写可视化代码

线性插值

处于创意编码,游戏开发,数据可视化和生成创意的功能

[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像素之间的滚动位置做出反应。我们称它们为ab。用下面的逆线性插值,你在传递ab以及滚动位置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

posted @ 2020-11-16 18:32  猫神甜辣酱  阅读(264)  评论(0编辑  收藏  举报