mirror of
https://github.com/pyalot/webgl-heatmap.git
synced 2025-12-08 20:13:00 +00:00
added an option to use a gradient texture and turn of intensity to alpha
This commit is contained in:
parent
8d04627cba
commit
424f4ae573
BIN
deep-sea-gradient.png
Normal file
BIN
deep-sea-gradient.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.3 KiB |
@ -5,7 +5,9 @@
|
||||
<script type="text/javascript">
|
||||
window.onload = function(){
|
||||
var canvas = document.getElementsByTagName('canvas')[0];
|
||||
var heatmap = createWebGLHeatmap({canvas: canvas});
|
||||
var heatmap = createWebGLHeatmap({canvas: canvas, intensityToAlpha:true});
|
||||
//var heatmap = createWebGLHeatmap({canvas: canvas, intensityToAlpha:true, gradientTexture:'deep-sea-gradient.png'});
|
||||
//var heatmap = createWebGLHeatmap({canvas: canvas, intensityToAlpha:false, gradientTexture:'skyline-gradient.png'});
|
||||
//var heatmap = createWebGLHeatmap({width: 500, height: 500}); // statically sized heatmap
|
||||
|
||||
// just feeding some mouse coords
|
||||
|
||||
@ -28,6 +28,14 @@ catch(error){
|
||||
}
|
||||
```
|
||||
|
||||
creation arguments
|
||||
|
||||
* canvas: the canvas you wish to draw on
|
||||
* width: explicit width
|
||||
* height: explicit height
|
||||
* intensityToAlpha: defaults to true
|
||||
* gradientTexture: texture used instead of color calculation, can be path or an image
|
||||
|
||||
Add a data point.
|
||||
|
||||
* x and y relative to the canvas in pixels
|
||||
|
||||
BIN
skyline-gradient.png
Normal file
BIN
skyline-gradient.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.4 KiB |
@ -134,6 +134,13 @@ class Texture
|
||||
@gl.texImage2D @target, 0, @channels, @width, @height, 0, @channels, @type, null
|
||||
return @
|
||||
|
||||
upload: (data) ->
|
||||
@width = data.width
|
||||
@height = data.height
|
||||
|
||||
@gl.texImage2D @target, 0, @channels, @channels, @type, data
|
||||
return @
|
||||
|
||||
linear: ->
|
||||
@gl.texParameteri @target, @gl.TEXTURE_MAG_FILTER, @gl.LINEAR
|
||||
@gl.texParameteri @target, @gl.TEXTURE_MIN_FILTER, @gl.LINEAR
|
||||
@ -368,7 +375,7 @@ class Heights
|
||||
@pointCount += 1
|
||||
|
||||
class WebGLHeatmap
|
||||
constructor: ({@canvas, @width, @height}={}) ->
|
||||
constructor: ({@canvas, @width, @height, intensityToAlpha, gradientTexture}={}) ->
|
||||
@canvas = document.createElement('canvas') unless @canvas
|
||||
try
|
||||
@gl = @canvas.getContext('experimental-webgl', depth:false, antialias:false)
|
||||
@ -385,22 +392,30 @@ class WebGLHeatmap
|
||||
@gl.enableVertexAttribArray 0
|
||||
@gl.blendFunc @gl.ONE, @gl.ONE
|
||||
|
||||
@shader = new Shader @gl,
|
||||
vertex: vertexShaderBlit
|
||||
fragment: fragmentShaderBlit + '''
|
||||
float linstep(float low, float high, float value){
|
||||
return clamp((value-low)/(high-low), 0.0, 1.0);
|
||||
}
|
||||
if gradientTexture
|
||||
textureGradient = @gradientTexture = new Texture(@gl, channels:'rgba').bind(0).setSize(2, 2).linear().clampToEdge()
|
||||
if typeof gradientTexture == 'string'
|
||||
image = new Image()
|
||||
image.onload = ->
|
||||
textureGradient.bind().upload(image)
|
||||
image.src = gradientTexture
|
||||
else
|
||||
if gradientTexture.width > 0 and gradientTexture.height > 0
|
||||
textureGradient.upload(gradientTexture)
|
||||
else
|
||||
gradientTexture.onload = ->
|
||||
textureGradient.upload(gradientTexture)
|
||||
|
||||
float fade(float low, float high, float value){
|
||||
float mid = (low+high)*0.5;
|
||||
float range = (high-low)*0.5;
|
||||
float x = 1.0 - clamp(abs(mid-value)/range, 0.0, 1.0);
|
||||
return smoothstep(0.0, 1.0, x);
|
||||
getColorFun = '''
|
||||
uniform sampler2D gradientTexture;
|
||||
vec3 getColor(float intensity){
|
||||
return texture2D(gradientTexture, vec2(intensity, 0.0)).rgb;
|
||||
}
|
||||
void main(){
|
||||
float intensity = smoothstep(0.0, 1.0, texture2D(source, texcoord).r);
|
||||
|
||||
'''
|
||||
else
|
||||
textureGradient = null
|
||||
getColorFun = '''
|
||||
vec3 getColor(float intensity){
|
||||
vec3 blue = vec3(0.0, 0.0, 1.0);
|
||||
vec3 cyan = vec3(0.0, 1.0, 1.0);
|
||||
vec3 green = vec3(0.0, 1.0, 0.0);
|
||||
@ -414,12 +429,40 @@ class WebGLHeatmap
|
||||
fade(0.5, 1.0, intensity)*yellow +
|
||||
smoothstep(0.75, 1.0, intensity)*red
|
||||
);
|
||||
|
||||
gl_FragColor = vec4(color*intensity, intensity);
|
||||
//gl_FragColor = vec4(1.0, 0.0, 1.0, 1.0);
|
||||
return color;
|
||||
}
|
||||
'''
|
||||
|
||||
intensityToAlpha ?= true
|
||||
|
||||
if intensityToAlpha
|
||||
output = 'vec4(color*intensity, intensity)'
|
||||
else
|
||||
output = 'vec4(color, 1.0)'
|
||||
|
||||
@shader = new Shader @gl,
|
||||
vertex: vertexShaderBlit
|
||||
fragment: fragmentShaderBlit + """
|
||||
float linstep(float low, float high, float value){
|
||||
return clamp((value-low)/(high-low), 0.0, 1.0);
|
||||
}
|
||||
|
||||
float fade(float low, float high, float value){
|
||||
float mid = (low+high)*0.5;
|
||||
float range = (high-low)*0.5;
|
||||
float x = 1.0 - clamp(abs(mid-value)/range, 0.0, 1.0);
|
||||
return smoothstep(0.0, 1.0, x);
|
||||
}
|
||||
|
||||
#{getColorFun}
|
||||
|
||||
void main(){
|
||||
float intensity = smoothstep(0.0, 1.0, texture2D(source, texcoord).r);
|
||||
vec3 color = getColor(intensity);
|
||||
gl_FragColor = #{output};
|
||||
}
|
||||
"""
|
||||
|
||||
@width ?= @canvas.offsetWidth or 2
|
||||
@height ?= @canvas.offsetHeight or 2
|
||||
@canvas.width = @width
|
||||
@ -458,7 +501,9 @@ class WebGLHeatmap
|
||||
@gl.bindBuffer @gl.ARRAY_BUFFER, @quad
|
||||
@gl.vertexAttribPointer(0, 4, @gl.FLOAT, false, 0, 0)
|
||||
@heights.nodeFront.bind(0)
|
||||
@shader.use().int('source', 0)
|
||||
if @gradientTexture
|
||||
@gradientTexture.bind(1)
|
||||
@shader.use().int('source', 0).int('gradientTexture', 1)
|
||||
@gl.drawArrays @gl.TRIANGLES, 0, 6
|
||||
|
||||
update: ->
|
||||
|
||||
@ -208,6 +208,13 @@
|
||||
return this;
|
||||
};
|
||||
|
||||
Texture.prototype.upload = function(data) {
|
||||
this.width = data.width;
|
||||
this.height = data.height;
|
||||
this.gl.texImage2D(this.target, 0, this.channels, this.channels, this.type, data);
|
||||
return this;
|
||||
};
|
||||
|
||||
Texture.prototype.linear = function() {
|
||||
this.gl.texParameteri(this.target, this.gl.TEXTURE_MAG_FILTER, this.gl.LINEAR);
|
||||
this.gl.texParameteri(this.target, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR);
|
||||
@ -432,8 +439,8 @@
|
||||
WebGLHeatmap = (function() {
|
||||
|
||||
function WebGLHeatmap(_arg) {
|
||||
var quad, _ref, _ref1, _ref2;
|
||||
_ref = _arg != null ? _arg : {}, this.canvas = _ref.canvas, this.width = _ref.width, this.height = _ref.height;
|
||||
var getColorFun, gradientTexture, image, intensityToAlpha, output, quad, textureGradient, _ref, _ref1, _ref2;
|
||||
_ref = _arg != null ? _arg : {}, this.canvas = _ref.canvas, this.width = _ref.width, this.height = _ref.height, intensityToAlpha = _ref.intensityToAlpha, gradientTexture = _ref.gradientTexture;
|
||||
if (!this.canvas) {
|
||||
this.canvas = document.createElement('canvas');
|
||||
}
|
||||
@ -459,9 +466,41 @@
|
||||
}
|
||||
this.gl.enableVertexAttribArray(0);
|
||||
this.gl.blendFunc(this.gl.ONE, this.gl.ONE);
|
||||
if (gradientTexture) {
|
||||
textureGradient = this.gradientTexture = new Texture(this.gl, {
|
||||
channels: 'rgba'
|
||||
}).bind(0).setSize(2, 2).linear().clampToEdge();
|
||||
if (typeof gradientTexture === 'string') {
|
||||
image = new Image();
|
||||
image.onload = function() {
|
||||
return textureGradient.bind().upload(image);
|
||||
};
|
||||
image.src = gradientTexture;
|
||||
} else {
|
||||
if (gradientTexture.width > 0 && gradientTexture.height > 0) {
|
||||
textureGradient.upload(gradientTexture);
|
||||
} else {
|
||||
gradientTexture.onload = function() {
|
||||
return textureGradient.upload(gradientTexture);
|
||||
};
|
||||
}
|
||||
}
|
||||
getColorFun = 'uniform sampler2D gradientTexture;\nvec3 getColor(float intensity){\n return texture2D(gradientTexture, vec2(intensity, 0.0)).rgb;\n}';
|
||||
} else {
|
||||
textureGradient = null;
|
||||
getColorFun = 'vec3 getColor(float intensity){\n vec3 blue = vec3(0.0, 0.0, 1.0);\n vec3 cyan = vec3(0.0, 1.0, 1.0);\n vec3 green = vec3(0.0, 1.0, 0.0);\n vec3 yellow = vec3(1.0, 1.0, 0.0);\n vec3 red = vec3(1.0, 0.0, 0.0);\n\n vec3 color = (\n fade(-0.25, 0.25, intensity)*blue +\n fade(0.0, 0.5, intensity)*cyan +\n fade(0.25, 0.75, intensity)*green +\n fade(0.5, 1.0, intensity)*yellow +\n smoothstep(0.75, 1.0, intensity)*red\n );\n return color;\n}';
|
||||
}
|
||||
if (intensityToAlpha == null) {
|
||||
intensityToAlpha = true;
|
||||
}
|
||||
if (intensityToAlpha) {
|
||||
output = 'vec4(color*intensity, intensity)';
|
||||
} else {
|
||||
output = 'vec4(color, 1.0)';
|
||||
}
|
||||
this.shader = new Shader(this.gl, {
|
||||
vertex: vertexShaderBlit,
|
||||
fragment: fragmentShaderBlit + 'float linstep(float low, float high, float value){\n return clamp((value-low)/(high-low), 0.0, 1.0);\n}\n\nfloat fade(float low, float high, float value){\n float mid = (low+high)*0.5;\n float range = (high-low)*0.5;\n float x = 1.0 - clamp(abs(mid-value)/range, 0.0, 1.0);\n return smoothstep(0.0, 1.0, x);\n}\nvoid main(){\n float intensity = smoothstep(0.0, 1.0, texture2D(source, texcoord).r);\n\n vec3 blue = vec3(0.0, 0.0, 1.0);\n vec3 cyan = vec3(0.0, 1.0, 1.0);\n vec3 green = vec3(0.0, 1.0, 0.0);\n vec3 yellow = vec3(1.0, 1.0, 0.0);\n vec3 red = vec3(1.0, 0.0, 0.0);\n\n vec3 color = (\n fade(-0.25, 0.25, intensity)*blue +\n fade(0.0, 0.5, intensity)*cyan +\n fade(0.25, 0.75, intensity)*green +\n fade(0.5, 1.0, intensity)*yellow +\n smoothstep(0.75, 1.0, intensity)*red\n );\n\n gl_FragColor = vec4(color*intensity, intensity);\n //gl_FragColor = vec4(1.0, 0.0, 1.0, 1.0);\n}'
|
||||
fragment: fragmentShaderBlit + ("float linstep(float low, float high, float value){\n return clamp((value-low)/(high-low), 0.0, 1.0);\n}\n\nfloat fade(float low, float high, float value){\n float mid = (low+high)*0.5;\n float range = (high-low)*0.5;\n float x = 1.0 - clamp(abs(mid-value)/range, 0.0, 1.0);\n return smoothstep(0.0, 1.0, x);\n}\n\n" + getColorFun + "\n\nvoid main(){\n float intensity = smoothstep(0.0, 1.0, texture2D(source, texcoord).r);\n vec3 color = getColor(intensity);\n gl_FragColor = " + output + ";\n}")
|
||||
});
|
||||
if ((_ref1 = this.width) == null) {
|
||||
this.width = this.canvas.offsetWidth || 2;
|
||||
@ -498,7 +537,10 @@
|
||||
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.quad);
|
||||
this.gl.vertexAttribPointer(0, 4, this.gl.FLOAT, false, 0, 0);
|
||||
this.heights.nodeFront.bind(0);
|
||||
this.shader.use().int('source', 0);
|
||||
if (this.gradientTexture) {
|
||||
this.gradientTexture.bind(1);
|
||||
}
|
||||
this.shader.use().int('source', 0).int('gradientTexture', 1);
|
||||
return this.gl.drawArrays(this.gl.TRIANGLES, 0, 6);
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user