Skip to content
Snippets Groups Projects
Commit 9f936d9c authored by David Sehnal's avatar David Sehnal
Browse files

Merge gl-geo

parents d4ed6cc7 152b5219
No related branches found
No related tags found
No related merge requests found
Showing
with 1563 additions and 4 deletions
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import REGL = require('regl');
import { Renderable } from '../renderable'
import { getBuffers } from './util'
import Attribute from '../attribute';
import { MeshShaders } from '../shaders'
type Mesh = 'mesh'
type Uniforms = { [k: string]: REGL.Uniform | REGL.Texture }
export function fillSerial<T extends Helpers.NumberArray> (array: T) {
const n = array.length
for (let i = 0; i < n; ++i) array[ i ] = i
return array
}
namespace Mesh {
export type DataType = {
position: { type: Float32Array, itemSize: 3 }
normal: { type: Float32Array, itemSize: 3 }
transformColumn0: { type: Float32Array, itemSize: 4 }
transformColumn1: { type: Float32Array, itemSize: 4 }
transformColumn2: { type: Float32Array, itemSize: 4 }
transformColumn3: { type: Float32Array, itemSize: 4 }
}
export type Data = { [K in keyof DataType]: DataType[K]['type'] }
export type Attributes = { [K in keyof Data]: Attribute<Data[K]> }
export function create(regl: REGL.Regl, attributes: Attributes, uniforms: Uniforms, elements?: Helpers.UintArray): Renderable<Data> {
console.log('mesh', {
count: attributes.position.getCount(),
instances: attributes.transformColumn0.getCount(),
attributes,
uniforms
})
const instanceCount = attributes.transformColumn0.getCount()
const instanceId = fillSerial(new Float32Array(instanceCount))
console.log(instanceId)
const command = regl({
...MeshShaders,
uniforms: {
objectId: uniforms.objectId || 0,
instanceCount,
...uniforms
},
attributes: getBuffers({
instanceId: Attribute.create(regl, instanceId, { size: 1, divisor: 1 }),
...attributes
}),
elements: elements && regl.elements({
data: new Uint16Array(elements),
primitive: 'triangles',
// type: 'uint16',
// count: elements.length / 3,
// length: elements.length * 2
}),
count: elements ? elements.length : attributes.position.getCount(),
instances: instanceCount,
primitive: 'triangles'
})
return {
draw: () => command(),
}
}
}
export default Mesh
\ No newline at end of file
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import REGL = require('regl');
import { Renderable } from '../renderable'
import { getBuffers } from './util'
import Attribute from '../attribute';
import { PointShaders } from '../shaders'
type Point = 'point'
namespace Point {
export type DataType = {
position: { type: Float32Array, itemSize: 3 }
transformColumn0: { type: Float32Array, itemSize: 4 }
transformColumn1: { type: Float32Array, itemSize: 4 }
transformColumn2: { type: Float32Array, itemSize: 4 }
transformColumn3: { type: Float32Array, itemSize: 4 }
}
export type Data = { [K in keyof DataType]: DataType[K]['type'] }
export type Attributes = { [K in keyof Data]: Attribute<Data[K]> }
export function create(regl: REGL.Regl, attributes: Attributes): Renderable<Data> {
console.log('point', {
count: attributes.position.getCount(),
instances: attributes.transformColumn0.getCount(),
}, attributes)
const command = regl({
...PointShaders,
attributes: getBuffers(attributes),
count: attributes.position.getCount(),
instances: attributes.transformColumn0.getCount(),
primitive: 'points'
})
return {
draw: () => command(),
}
}
}
export default Point
// namespace Point {
// export type DataType = {
// position: { type: Float32Array, itemSize: 3 }
// }
// export type Data = { [K in keyof DataType]: DataType[K]['type'] }
// export type Attributes = { [K in keyof Data]: Attribute<Data[K]> }
// export function create(regl: REGL.Regl, dataOrCount: Data | number): Renderable<Data> {
// let count: number
// let data: Data
// if (typeof dataOrCount === 'number') {
// count = dataOrCount
// data = {
// position: new Float32Array(count * 3)
// }
// } else {
// count = dataOrCount.position.length / 3
// data = dataOrCount
// }
// const attributes = createAttributes(regl, data)
// const command = regl({
// vert: pointVert,
// frag: pointFrag,
// attributes: getBuffers(attributes),
// count,
// primitive: 'points'
// })
// return {
// draw: () => command(),
// setCount: (newCount: number) => {
// for (const k of Object.keys(data)) {
// attributes[k as keyof Data].setCount(newCount)
// }
// count = newCount
// },
// getCount: () => count,
// attributes
// }
// }
// }
\ No newline at end of file
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import REGL = require('regl');
import { Attributes, AttributesData, AttributesBuffers } from '../renderable'
import Attribute from '../attribute'
export function createTransformAttributes (regl: REGL.Regl, transform: Float32Array) {
const size = 4
const divisor = 1
const bpe = transform.BYTES_PER_ELEMENT
const stride = 16 * bpe
return {
transformColumn0: Attribute.create(regl, transform, { size, divisor, offset: 0, stride }),
transformColumn1: Attribute.create(regl, transform, { size, divisor, offset: 4 * bpe, stride }),
transformColumn2: Attribute.create(regl, transform, { size, divisor, offset: 8 * bpe, stride }),
transformColumn3: Attribute.create(regl, transform, { size, divisor, offset: 12 * bpe, stride })
}
}
export function getBuffers<T extends AttributesData>(attributes: Attributes<T>): AttributesBuffers<T> {
const buffers: AttributesBuffers<any> = {}
for (const k of Object.keys(attributes)) {
buffers[k] = attributes[k].buffer
}
return buffers as AttributesBuffers<T>
}
// by Tom Madams
// Simple:
// https://imdoingitwrong.wordpress.com/2011/01/31/light-attenuation/
//
// Improved
// https://imdoingitwrong.wordpress.com/2011/02/10/improved-light-attenuation/
float attenuation(float r, float f, float d) {
float denom = d / r + 1.0;
float attenuation = 1.0 / (denom*denom);
float t = (attenuation - f) / (1.0 - f);
return max(t, 0.0);
}
#pragma glslify: export(attenuation)
\ No newline at end of file
// (c) 2014 Mikola Lysenko. MIT License
// https://github.com/glslify/glsl-inverse
float inverse(float m) {
return 1.0 / m;
}
mat2 inverse(mat2 m) {
return mat2(m[1][1],-m[0][1],
-m[1][0], m[0][0]) / (m[0][0]*m[1][1] - m[0][1]*m[1][0]);
}
mat3 inverse(mat3 m) {
float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];
float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];
float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];
float b01 = a22 * a11 - a12 * a21;
float b11 = -a22 * a10 + a12 * a20;
float b21 = a21 * a10 - a11 * a20;
float det = a00 * b01 + a01 * b11 + a02 * b21;
return mat3(b01, (-a22 * a01 + a02 * a21), (a12 * a01 - a02 * a11),
b11, (a22 * a00 - a02 * a20), (-a12 * a00 + a02 * a10),
b21, (-a21 * a00 + a01 * a20), (a11 * a00 - a01 * a10)) / det;
}
mat4 inverse(mat4 m) {
float
a00 = m[0][0], a01 = m[0][1], a02 = m[0][2], a03 = m[0][3],
a10 = m[1][0], a11 = m[1][1], a12 = m[1][2], a13 = m[1][3],
a20 = m[2][0], a21 = m[2][1], a22 = m[2][2], a23 = m[2][3],
a30 = m[3][0], a31 = m[3][1], a32 = m[3][2], a33 = m[3][3],
b00 = a00 * a11 - a01 * a10,
b01 = a00 * a12 - a02 * a10,
b02 = a00 * a13 - a03 * a10,
b03 = a01 * a12 - a02 * a11,
b04 = a01 * a13 - a03 * a11,
b05 = a02 * a13 - a03 * a12,
b06 = a20 * a31 - a21 * a30,
b07 = a20 * a32 - a22 * a30,
b08 = a20 * a33 - a23 * a30,
b09 = a21 * a32 - a22 * a31,
b10 = a21 * a33 - a23 * a31,
b11 = a22 * a33 - a23 * a32,
det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
return mat4(
a11 * b11 - a12 * b10 + a13 * b09,
a02 * b10 - a01 * b11 - a03 * b09,
a31 * b05 - a32 * b04 + a33 * b03,
a22 * b04 - a21 * b05 - a23 * b03,
a12 * b08 - a10 * b11 - a13 * b07,
a00 * b11 - a02 * b08 + a03 * b07,
a32 * b02 - a30 * b05 - a33 * b01,
a20 * b05 - a22 * b02 + a23 * b01,
a10 * b10 - a11 * b08 + a13 * b06,
a01 * b08 - a00 * b10 - a03 * b06,
a30 * b04 - a31 * b02 + a33 * b00,
a21 * b02 - a20 * b04 - a23 * b00,
a11 * b07 - a10 * b09 - a12 * b06,
a00 * b09 - a01 * b07 + a02 * b06,
a31 * b01 - a30 * b03 - a32 * b00,
a20 * b03 - a21 * b01 + a22 * b00) / det;
}
#pragma glslify: export(inverse)
\ No newline at end of file
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
precision mediump float;
struct Light {
vec3 position;
vec3 color;
vec3 ambient;
float falloff;
float radius;
};
uniform Light light;
uniform mat4 view;
varying vec3 vNormal, vViewPosition, vColor;
float phongSpecular(vec3 lightDirection, vec3 viewDirection, vec3 surfaceNormal, float shininess) {
//Calculate Phong power
vec3 R = -reflect(lightDirection, surfaceNormal);
return pow(max(0.0, dot(viewDirection, R)), shininess);
}
#define PI 3.14159265
float orenNayarDiffuse(vec3 lightDirection, vec3 viewDirection, vec3 surfaceNormal, float roughness, float albedo) {
float LdotV = dot(lightDirection, viewDirection);
float NdotL = dot(lightDirection, surfaceNormal);
float NdotV = dot(surfaceNormal, viewDirection);
float s = LdotV - NdotL * NdotV;
float t = mix(1.0, max(NdotL, NdotV), step(0.0, s));
float sigma2 = roughness * roughness;
float A = 1.0 + sigma2 * (albedo / (sigma2 + 0.13) + 0.5 / (sigma2 + 0.33));
float B = 0.45 * sigma2 / (sigma2 + 0.09);
return albedo * max(0.0, NdotL) * (A + B * s / t) / PI;
}
#pragma glslify: attenuation = require(./attenuation.glsl)
const float specularScale = 0.65;
const float shininess = 10.0;
const float roughness = 5.0;
const float albedo = 0.95;
void main() {
// determine surface to light direction
vec4 lightPosition = view * vec4(light.position, 1.0);
vec3 lightVector = lightPosition.xyz - vViewPosition;
// calculate attenuation
float lightDistance = length(lightVector);
float falloff = 1.0; // attenuation(light.radius, light.falloff, lightDistance);
vec3 L = normalize(lightVector); // light direction
vec3 V = normalize(vViewPosition); // eye direction
vec3 N = normalize(vNormal); // surface normal
// compute our diffuse & specular terms
float specular = phongSpecular(L, V, N, shininess) * specularScale * falloff;
vec3 diffuse = light.color * orenNayarDiffuse(L, V, N, roughness, albedo) * falloff;
vec3 ambient = light.ambient;
// add the lighting
vec3 color = vColor * (diffuse + ambient) + specular;
gl_FragColor.rgb = N;
gl_FragColor.a = 1.0;
}
\ No newline at end of file
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
#define INSTANCE_COLOR
precision mediump float;
uniform mat4 projection, model, view;
uniform int objectId;
uniform int instanceCount;
#if defined( ATTRIBUTE_COLOR )
attribute vec3 color;
#elif defined( INSTANCE_COLOR ) || defined( ELEMENT_COLOR )
uniform vec2 colorTexSize;
uniform sampler2D colorTex;
#endif
attribute vec3 position;
attribute vec3 normal;
attribute vec4 transformColumn0, transformColumn1, transformColumn2, transformColumn3;
attribute float instanceId;
// attribute int elementId;
varying vec3 vColor;
varying vec3 vNormal;
varying vec3 vViewPosition;
#pragma glslify: inverse = require(./inverse.glsl)
#pragma glslify: read_vec3 = require(./read-vec3.glsl)
#pragma glslify: transpose = require(./transpose.glsl)
void main(){
#if defined( ATTRIBUTE_COLOR )
vColor = color;
#elif defined( INSTANCE_COLOR )
vColor = read_vec3(colorTex, instanceId, colorTexSize);
// #elif defined( ELEMENT_COLOR )
// vColor = read_vec3(colorTex, instanceId * instanceCount + elementId, colorTexSize);
#else
vColor = vec3(0.0, 1.0, 0.0);
#endif
mat4 transform = mat4(transformColumn0, transformColumn1, transformColumn2, transformColumn3);
mat4 modelView = view * model * transform;
vec4 mvPosition = modelView * vec4(position, 1.0);
vViewPosition = mvPosition.xyz;
gl_Position = projection * mvPosition;
// TODO do on CPU side
mat3 normalMatrix = transpose(inverse(mat3(modelView)));
vNormal = normalize(normalMatrix * normal);
}
\ No newline at end of file
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
void main(){
gl_FragColor = vec4(1, 0, 0, 1);
}
\ No newline at end of file
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
precision mediump float;
uniform mat4 projection, model, view;
attribute vec3 position; //, color;
attribute vec4 transformColumn0, transformColumn1, transformColumn2, transformColumn3;
// attribute int instanceId;
// instanced
// attribute mat4 transform;
// uniform mat4 transform;
// varying vec3 vColor;
void main(){
mat4 transform = mat4(transformColumn0, transformColumn1, transformColumn2, transformColumn3);
// vColor = color;
gl_PointSize = 20.0;
gl_Position = projection * view * model * transform * vec4(position, 1.0);
}
\ No newline at end of file
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
vec3 read_vec3 (sampler2D tex, float i, vec2 size) {
float x = mod(i, size.x);
float y = floor(i / size.x);
vec2 uv = (vec2(x, y) + 0.5) / size;
return texture2D(tex, uv).rgb;
}
#pragma glslify: export(read_vec3)
\ No newline at end of file
// (c) 2014 Mikola Lysenko. MIT License
// https://github.com/glslify/glsl-transpose
float transpose(float m) {
return m;
}
mat2 transpose(mat2 m) {
return mat2(m[0][0], m[1][0],
m[0][1], m[1][1]);
}
mat3 transpose(mat3 m) {
return mat3(m[0][0], m[1][0], m[2][0],
m[0][1], m[1][1], m[2][1],
m[0][2], m[1][2], m[2][2]);
}
mat4 transpose(mat4 m) {
return mat4(m[0][0], m[1][0], m[2][0], m[3][0],
m[0][1], m[1][1], m[2][1], m[3][1],
m[0][2], m[1][2], m[2][2], m[3][2],
m[0][3], m[1][3], m[2][3], m[3][3]);
}
#pragma glslify: export(transpose)
\ No newline at end of file
const PointShaders = {
vert: require('mol-gl/shader/point.vert'),
frag: require('mol-gl/shader/point.frag')
}
const MeshShaders = {
vert: require('mol-gl/shader/mesh.vert'),
frag: require('mol-gl/shader/mesh.frag')
}
export { PointShaders, MeshShaders }
\ No newline at end of file
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
export function calculateTextureInfo (n: number, itemSize: number) {
const sqN = Math.sqrt(n * itemSize)
let width = Math.ceil(sqN)
width = width + (itemSize - (width % itemSize)) % itemSize
const height = width > 0 ? Math.ceil(n * itemSize / width) : 0
return { width, height, length: width * height * itemSize }
}
\ No newline at end of file
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
export function normalize (value: number, min: number, max: number) {
return (value - min) / (max - min)
}
export function clamp (value: number, min: number, max: number) {
return Math.max(min, Math.min(max, value))
}
export function pclamp (value: number) {
return clamp(value, 0, 100)
}
export function saturate (value: number) {
return clamp(value, 0, 1)
}
export function damp (value: number, dampingFactor: number) {
const dampedValue = value * dampingFactor
return Math.abs(dampedValue) < 0.1 ? 0 : dampedValue
}
export function lerp (start: number, stop: number, alpha: number) {
return start + (stop - start) * alpha
}
export function spline (p0: number, p1: number, p2: number, p3: number, t: number, tension: number) {
const v0 = (p2 - p0) * tension
const v1 = (p3 - p1) * tension
const t2 = t * t
const t3 = t * t2
return (2 * p1 - 2 * p2 + v0 + v1) * t3 + (-3 * p1 + 3 * p2 - 2 * v0 - v1) * t2 + v0 * t + p1
}
export function smoothstep (min: number, max: number, x: number) {
x = saturate(normalize(x, min, max))
return x * x * (3 - 2 * x)
}
export function smootherstep (min: number, max: number, x: number) {
x = saturate(normalize(x, min, max))
return x * x * x * (x * (x * 6 - 15) + 10)
}
export function smootheststep (min: number, max: number, x: number) {
x = saturate(normalize(x, min, max))
return -20 * Math.pow(x, 7) + 70 * Math.pow(x, 6) - 84 * Math.pow(x, 5) + 35 * Math.pow(x, 4)
}
export function almostIdentity (value: number, start: number, stop: number) {
if (value > start) return value
const a = 2 * stop - start
const b = 2 * start - 3 * stop
const t = value / start
return (a * t + b) * t * t + stop
}
\ No newline at end of file
This diff is collapsed.
...@@ -22,3 +22,7 @@ export function arrayEqual<T>(arr1: T[], arr2: T[]) { ...@@ -22,3 +22,7 @@ export function arrayEqual<T>(arr1: T[], arr2: T[]) {
} }
return true return true
} }
export function defaults (value: any, defaultValue: any) {
return value !== undefined ? value : defaultValue
}
\ No newline at end of file
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
/*
* This code has been modified from https://github.com/mikolalysenko/mouse-change,
* copyright (c) 2015 Mikola Lysenko. MIT License
*/
import * as mouse from './mouse-event'
export type MouseModifiers = {
shift: boolean,
alt: boolean,
control: boolean,
meta: boolean
}
export type MouseChangeCallback = (buttonState: number, x: number, y: number, mods: MouseModifiers) => void
export default function mouseListen (element: Element, callback: MouseChangeCallback) {
let buttonState = 0
let x = 0
let y = 0
const mods: MouseModifiers = {
shift: false,
alt: false,
control: false,
meta: false
}
let attached = false
function updateMods (event: MouseEvent | KeyboardEvent) {
let changed = false
if ('altKey' in event) {
changed = changed || event.altKey !== mods.alt
mods.alt = !!event.altKey
}
if ('shiftKey' in event) {
changed = changed || event.shiftKey !== mods.shift
mods.shift = !!event.shiftKey
}
if ('ctrlKey' in event) {
changed = changed || event.ctrlKey !== mods.control
mods.control = !!event.ctrlKey
}
if ('metaKey' in event) {
changed = changed || event.metaKey !== mods.meta
mods.meta = !!event.metaKey
}
return changed
}
function handleEvent (nextButtons: number, event: MouseEvent) {
const nextX = mouse.x(event)
const nextY = mouse.y(event)
if ('buttons' in event) {
nextButtons = event.buttons | 0
}
if (nextButtons !== buttonState || nextX !== x || nextY !== y || updateMods(event) ) {
buttonState = nextButtons | 0
x = nextX || 0
y = nextY || 0
callback && callback(buttonState, x, y, mods)
}
}
function clearState (event: MouseEvent) {
handleEvent(0, event)
}
function handleBlur () {
if (buttonState || x || y || mods.shift || mods.alt || mods.meta || mods.control) {
x = y = 0
buttonState = 0
mods.shift = mods.alt = mods.control = mods.meta = false
callback && callback(0, 0, 0, mods)
}
}
function handleMods (event: MouseEvent | KeyboardEvent) {
if (updateMods(event)) {
callback && callback(buttonState, x, y, mods)
}
}
function handleMouseMove (event: MouseEvent) {
if (mouse.buttons(event) === 0) {
handleEvent(0, event)
} else {
handleEvent(buttonState, event)
}
}
function handleMouseDown (event: MouseEvent) {
handleEvent(buttonState | mouse.buttons(event), event)
}
function handleMouseUp (event: MouseEvent) {
handleEvent(buttonState & ~mouse.buttons(event), event)
}
function attachListeners () {
if (attached) return
attached = true
element.addEventListener('mousemove', handleMouseMove as EventListener)
element.addEventListener('mousedown', handleMouseDown as EventListener)
element.addEventListener('mouseup', handleMouseUp as EventListener)
element.addEventListener('mouseleave', clearState as EventListener)
element.addEventListener('mouseenter', clearState as EventListener)
element.addEventListener('mouseout', clearState as EventListener)
element.addEventListener('mouseover', clearState as EventListener)
element.addEventListener('blur', handleBlur)
element.addEventListener('keyup', handleMods as EventListener)
element.addEventListener('keydown', handleMods as EventListener)
element.addEventListener('keypress', handleMods as EventListener)
if (!(element instanceof Window)) {
window.addEventListener('blur', handleBlur)
window.addEventListener('keyup', handleMods)
window.addEventListener('keydown', handleMods)
window.addEventListener('keypress', handleMods)
}
}
function detachListeners () {
if (!attached) return
attached = false
element.removeEventListener('mousemove', handleMouseMove as EventListener)
element.removeEventListener('mousedown', handleMouseDown as EventListener)
element.removeEventListener('mouseup', handleMouseUp as EventListener)
element.removeEventListener('mouseleave', clearState as EventListener)
element.removeEventListener('mouseenter', clearState as EventListener)
element.removeEventListener('mouseout', clearState as EventListener)
element.removeEventListener('mouseover', clearState as EventListener)
element.removeEventListener('blur', handleBlur)
element.removeEventListener('keyup', handleMods as EventListener)
element.removeEventListener('keydown', handleMods as EventListener)
element.removeEventListener('keypress', handleMods as EventListener)
if (!(element instanceof Window)) {
window.removeEventListener('blur', handleBlur)
window.removeEventListener('keyup', handleMods)
window.removeEventListener('keydown', handleMods)
window.removeEventListener('keypress', handleMods)
}
}
// Attach listeners
attachListeners()
const result = {
element: element
}
Object.defineProperties(result, {
enabled: {
get: function () { return attached },
set: function (f) {
if (f) {
attachListeners()
} else {
detachListeners()
}
},
enumerable: true
},
buttons: {
get: function () { return buttonState },
enumerable: true
},
x: {
get: function () { return x },
enumerable: true
},
y: {
get: function () { return y },
enumerable: true
},
mods: {
get: function () { return mods },
enumerable: true
}
})
return result
}
\ No newline at end of file
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
/*
* This code has been modified from https://github.com/mikolalysenko/mouse-event,
* copyright (c) 2015 Mikola Lysenko. MIT License
*/
export function buttons(event: MouseEvent) {
if (typeof event === 'object') {
if ('buttons' in event) {
return event.buttons
} else if ('which' in event) {
const b = (event as any).which // 'any' to support older browsers
if (b === 2) {
return 4
} else if (b === 3) {
return 2
} else if (b > 0) {
return 1<<(b-1)
}
} else if ('button' in event) {
const b = (event as any).button // 'any' to support older browsers
if (b === 1) {
return 4
} else if (b === 2) {
return 2
} else if (b >= 0) {
return 1<<b
}
}
}
return 0
}
export function element(event: MouseEvent) {
return event.target as Element || event.srcElement || window
}
export function x(event: MouseEvent) {
if (typeof event === 'object') {
if ('offsetX' in event) {
return event.offsetX
}
const target = element(event)
const bounds = target.getBoundingClientRect()
return (event as any).clientX - bounds.left // 'any' to support older browsers
}
return 0
}
export function y(event: MouseEvent) {
if (typeof event === 'object') {
if ('offsetY' in event) {
return event.offsetY
}
const target = element(event)
const bounds = target.getBoundingClientRect()
return (event as any).clientY - bounds.top // 'any' to support older browsers
}
return 0
}
\ No newline at end of file
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
/*
* This code has been modified from https://github.com/mikolalysenko/mouse-wheel,
* copyright (c) 2015 Mikola Lysenko. MIT License
*/
import toPixels from './to-pixels'
export type MouseWheelCallback = (dx: number, dy: number, dz: number, event: MouseWheelEvent) => void
export default function mouseWheelListen(element: Element, callback: MouseWheelCallback, noScroll = false) {
const lineHeight = toPixels('ex', element)
const listener = function (event: MouseWheelEvent) {
if (noScroll) {
event.preventDefault()
}
const mode = event.deltaMode
let dx = event.deltaX || 0
let dy = event.deltaY || 0
let dz = event.deltaZ || 0
let scale = 1
switch (mode) {
case 1: scale = lineHeight; break
case 2: scale = window.innerHeight; break
}
dx *= scale
dy *= scale
dz *= scale
if (dx || dy || dz) {
return callback(dx, dy, dz, event)
}
}
element.addEventListener('wheel', listener)
return listener
}
\ No newline at end of file
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
/*
* This code has been modified from https://github.com/mattdesl/parse-unit,
* copyright (c) 2014 Matt DesLauriers. MIT License
*/
const reUnit = /[\d.\-\+]*\s*(.*)/
export default function parseUnit(str: string, out: [number, string] = [ 0, '' ]) {
str = String(str)
const num = parseFloat(str)
out[0] = num
const m = str.match(reUnit)
if (m) out[1] = m[1] || ''
return out
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment