npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

lxhhj-webgl

v3.0.0

Published

kriging.js webgl accelerate version

Downloads

444

Readme

kriging.js 改造而来,使用webgl加速生成

alt text

watch example

通常在cpu中逐像素计算

import kriging from 'kriging.js';
const variogram = kriging.train(...);
for(let i=0;i<row;i++){
    for(let j=0;j<col;j++){
        const [x, y] = getPosition(j, i); //像素转世界坐标
        const value =  kriging.predict(x, y, variogram); //计算值
        pixel[ y * col + x] = getColor(value); //为像素着色
    }
}

使用webgl加速计算以下部分:

for(let i=0;i<row;i++){
    for(let j=0;j<col;j++){
        const value = kriging.predict(x, y, variogram); 
    }
}

API

//训练, 同 oeo4b/kriging.js
export function train(t: number[], x: number[], y: number[], model: KrigingModel, sigma2: number, alpha: number)


// 生成
// 色调映射
type ColorMappingItem = { 
    min: number, //最小值
    max: number, //最大值
    color: string //区间颜色
};
type P = {
    variogram: Variogram | VariogramObject; //训练参数结果
    llCorner: number[]; //要生成区域的左下角 [xmin, ymin](世界坐标)
    gridSize: number[]; //要生成的网格尺寸 [width, height] (像素)
    cellSize: number; //每个网格的大小(世界坐标)
}
type Cancelable<R> = Promise<R> & { cancel: () => void };
//输出所有像素的预测值
export function gernerate_WEBGL(opts: P & { outputFormat: 'value-buffer' }): Cancelable<Float32Array>; 
//输出所有像素的预测值, 以rgb打包方式存储在imagebitmap中
export function gernerate_WEBGL(opts: P & { outputFormat: 'packed-imagebitmap', packValueRange: number[] }): Cancelable<ImageBitmap>; 
//直接输出imagebitmap图像
export function gernerate_WEBGL(opts: P & { outputFormat: 'imagebitmap', colorMapping: ColorMappingItem[] | ColorMappingObject }): Cancelable<ImageBitmap>;

Example

outputFormat: 'imagebitmap'

import {train, gernerate_WEBGL} from 'kriging-webgl';
const variogram = train(...);
const gridSize = [300, 300];//生成300x300像素

//直接生成映射颜色后图像
const imagebitmap = await gernerate_WEBGL({
    outputFormat: 'imagebitmap',
    gridSize,
    ...,
    colorMapping: [
        { min: 0, max: 10, color: "rgba(166, 255, 176, 1)", },
        { min: 10, max: 25, color: "rgba(30, 186, 37, 1)", },
        { min: 25, max: 50, color: "rgba(95, 207, 255, 1)", },
        { min: 50, max: 100, color: "rgba(0, 0, 255, 1)", },
        { min: 100, max: 250, color: "rgba(249, 0, 241, 1)", },
        { min: 250, max: Infinity, color: "rgba(255, 0, 0, 1)", },
    ]
});

//渲染 或 作为 webgl的纹理
const canvas = document.createElement('canvas');
canvas.width = gridSize[0];
canvas.height = gridSize[1];
const ctx = canvas.getContext('2d');
ctx.drawImage(imagebitmap, 0, 0);

outputFormat: 'value-buffer'

import {train, gernerate_WEBGL } from 'kriging-webgl';
const variogram = train(...);
const gridSize = [300, 300];//生成300x300像素

//生成每个像素位置的预测值数组,需要手动映射颜色
const values = await gernerate_WEBGL({
    outputFormat: 'value-buffer',
    gridSize
});

// 1.cpu逐像素着色
const canvas = document.createElement('canvas');
canvas.width = gridSize[0];
canvas.height = gridSize[1];
const ctx = canvas.getContext('2d');
const imageData = ctx.createImageData();
for(let i=0; i < gridSize[1]; i++){
    for(let j=0; j < gridSize[0]; j++){
        const valueIndex = i * gridSize[0] + j;
        const value = values[valueIndex];
        const [r, g, b, a] = getColor(value);
        const pixel = valueIndex * 4;
        imageData.data[pixel] = r;
        imageData.data[pixel + 1] = g;
        imageData.data[pixel + 2] = b;
        imageData.data[pixel + 3] = a;
    }
}
ctx.putImageData(imageData, 0, 0);


// 2.webgl着色
const gl = canvas.getContext('webgl2');
//将数据做成浮点纹理
const texture = gl.createTexture();
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); //数据纹理, 不能直接插值
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); 
gl.texImage2D(gl.TEXTURE_2D, 0, gl.R32F, gridInfo[0], gridInfo[1], 0, gl.RED, gl.FLOAT, buffer);
//在shader中着色
` uniform sampler2D dataTexture;
  in vec2 v_uv;
  void main(){
     vec2 uv = vec2(v_uv.x, 1.0 - v_uv.y); // flipY is false, 所以手动翻转
    
     float value = texture(dataTexture, uv); //获取原始值
     gl_FragColor = getColor(value); //根据值获取输出颜色
  }
`

outputFormat: 'packed-imagebitmap'

import {train, gernerate_WEBGL, glsl_pack} from 'kriging-webgl';
const xs = [...];
const ys = [...];
const datas = [1,2,3,4, ....];
const variogram = train(xs, ys, datas,...);
const gridSize = [300, 300];//生成300x300像素

//生成每个像素位置的预测值, 以rgb打包方式存储在imagebitmap中, 需要在shader中解包
const packedImagebitmap = await gernerate_WEBGL({
    outputFormat: 'packed-imagebitmap',
    gridSize,
    ...,
    packValueRange: [
        Math.min.apply(null, datas),
        Math.max.apply(null, datas)
    ], //打包的值范围,从原始值域或自行指定
});


//webgl 解包 并且 着色
const gl = canvas.getContext('webgl2');
//上传到纹理
const texture = gl.createTexture();
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); //数据纹理, 不能直接插值
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); 
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, packedImageBitmap);
//fragment shader
` 
  uniform sampler2D packedImageBitmap;
  uniform vec2 unpackValueRange; //解码范围, 即原始打包的范围 [min, max]

  in vec2 v_uv;

  ${glsl_pack} //引入解包的代码

  void main(){
       vec2 uv = vec2(v_uv.x, 1.0 - v_uv.y); //注意y轴反向 gl.UNPACK_FLIP_Y_WEBGL 对 imagebitmap 无效

       vec3 packed_rgb = texture(packedImageBitmap, uv).rgb; //获取打包值

       float normalized_value = unpackRGBToNormalizeFloat(packed_rgb); //解包

       float value = mix(unpackValueRange.x, unpackValueRange.y, normalized_value); //映射回范围

       gl_FragColor = getColor(value); //输出颜色
  }
`

Optimize

对象复用 VariogramObject & ColorMappingObject

import {gernerate_WEBGL, createColorMappingObject, createVariogramObject} from 'kriging-webgl';


// 直接调用, 会在内部生成  VariogramObject / ColorMappingObject, 然后销毁
// 若需要多次生成或重新生成, 可以生成 VariogramObject / ColorMappingObject 重复使用, 提高性能
const result = await gernerate_WEBGL({
    variogram: variogram,
    colorMapping: colorMapping
});


// 给多个时刻不同数据使用相同的colorMapping
const colorMapping_object = createColorMappingObject([
    { min: 0, max: 10, color: "rgba(166, 255, 176, 1)", },
    { min: 10, max: 25, color: "rgba(30, 186, 37, 1)", },
    { min: 25, max: 50, color: "rgba(95, 207, 255, 1)", },
    { min: 50, max: 100, color: "rgba(0, 0, 255, 1)", },
    { min: 100, max: 250, color: "rgba(249, 0, 241, 1)", },
    { min: 250, max: Infinity, color: "rgba(255, 0, 0, 1)", },
]);

const variogram_1 = train(...);
const imagebitmap_1 = await gernerate_WEBGL({
    variogram: variogram_1,
    colorMapping: colorMapping_object
});
const variogram_2 = train(...);
const imagebitmap_2 = await gernerate_WEBGL({
    variogram: variogram_2,
    colorMapping: colorMapping_object
});

colorMapping_object.dispoe(); //不使用后, 需要手动释放


// 使用同一个数据, 生成不同的颜色映射的结果
const variogram = train(...);
const variogram_object = createVariogramObject(variogram);
const imagebitmap_1 = await gernerate_WEBGL({
    variogram: variogram_object,
    colorMapping: colorMapping_1
});
const imagebitmap_2 = await gernerate_WEBGL({
    variogram: variogram_object,
    colorMapping: colorMapping_2
});

variogram_object.dispoe(); //不使用后, 需要手动释放

精度问题

某些低端设备不支持highp float; 坐标(例如web墨卡托)误差很大, 导致结果误差大; 可将坐标归一化,合理利用浮点数存储精度

const xs = [113.13, 113.23, ....];
const ys = [23.33, 23.44, ...];

const [xmin, xmax, ymin, ymax] = resolveRange(xs, ys); 
const width = xmax - xmin;
const height = ymax - min;
const normalized_xs = xs.map(x => (x-xmin) / width);
const normalized_ys = ys.map(y => (y-ymin) / height);
const variogram = train(data, normalized_xs, normalized_ys, 'exponential', 0, 10);

const cellSize = width / 300;
const gridSize = [300, Math.round(height / cellSize)];
const imagebitmap = await gernerate_WEBGL({
    variogram,
    llCorner: [0, 0], //position normalized
    cellSize,
    gridSize,
});

use in worker

// main thread
const worker = new Worker('worker.js');
worker.onmessage = e => {
    doRender(e.data as ImageBitmap);
}
worker.postMessage({...});


// worker.js
import {train, gernerate_WEBGL} from 'kriging-webgl';
self.onmessage = e =>{
    const {data, xs, ys, ...} = e.data;
    const variogram = train(data, xs, ys,'exponential', 0, 10);
    gernerate_WEBGL({
        variogram,
        ....
    }).then(imagbitmap=>{
        self.postmessage({ imagbitmap }, [imagbitmap] /*transfer to main*/);
    })
}