// Context and canvas creation helper functions var check = require('./util/check') var extend = require('./util/extend') function createCanvas (element, onDone, pixelRatio) { var canvas = document.createElement('canvas') extend(canvas.style, { border: 0, margin: 0, padding: 0, top: 0, left: 0, width: '100%', height: '100%' }) element.appendChild(canvas) if (element === document.body) { canvas.style.position = 'absolute' extend(element.style, { margin: 0, padding: 0 }) } function resize () { var w = window.innerWidth var h = window.innerHeight if (element !== document.body) { var bounds = canvas.getBoundingClientRect() w = bounds.right - bounds.left h = bounds.bottom - bounds.top } canvas.width = pixelRatio * w canvas.height = pixelRatio * h } var resizeObserver if (element !== document.body && typeof ResizeObserver === 'function') { // ignore 'ResizeObserver' is not defined // eslint-disable-next-line resizeObserver = new ResizeObserver(function () { // setTimeout to avoid flicker setTimeout(resize) }) resizeObserver.observe(element) } else { window.addEventListener('resize', resize, false) } function onDestroy () { if (resizeObserver) { resizeObserver.disconnect() } else { window.removeEventListener('resize', resize) } element.removeChild(canvas) } resize() return { canvas: canvas, onDestroy: onDestroy } } function createContext (canvas, contextAttributes) { function get (name) { try { return canvas.getContext(name, contextAttributes) } catch (e) { return null } } return ( get('webgl') || get('experimental-webgl') || get('webgl-experimental') ) } function isHTMLElement (obj) { return ( typeof obj.nodeName === 'string' && typeof obj.appendChild === 'function' && typeof obj.getBoundingClientRect === 'function' ) } function isWebGLContext (obj) { return ( typeof obj.drawArrays === 'function' || typeof obj.drawElements === 'function' ) } function parseExtensions (input) { if (typeof input === 'string') { return input.split() } check(Array.isArray(input), 'invalid extension array') return input } function getElement (desc) { if (typeof desc === 'string') { check(typeof document !== 'undefined', 'not supported outside of DOM') return document.querySelector(desc) } return desc } module.exports = function parseArgs (args_) { var args = args_ || {} var element, container, canvas, gl var contextAttributes = {} var extensions = [] var optionalExtensions = [] var pixelRatio = (typeof window === 'undefined' ? 1 : window.devicePixelRatio) var profile = false var onDone = function (err) { if (err) { check.raise(err) } } var onDestroy = function () {} if (typeof args === 'string') { check( typeof document !== 'undefined', 'selector queries only supported in DOM enviroments') element = document.querySelector(args) check(element, 'invalid query string for element') } else if (typeof args === 'object') { if (isHTMLElement(args)) { element = args } else if (isWebGLContext(args)) { gl = args canvas = gl.canvas } else { check.constructor(args) if ('gl' in args) { gl = args.gl } else if ('canvas' in args) { canvas = getElement(args.canvas) } else if ('container' in args) { container = getElement(args.container) } if ('attributes' in args) { contextAttributes = args.attributes check.type(contextAttributes, 'object', 'invalid context attributes') } if ('extensions' in args) { extensions = parseExtensions(args.extensions) } if ('optionalExtensions' in args) { optionalExtensions = parseExtensions(args.optionalExtensions) } if ('onDone' in args) { check.type( args.onDone, 'function', 'invalid or missing onDone callback') onDone = args.onDone } if ('profile' in args) { profile = !!args.profile } if ('pixelRatio' in args) { pixelRatio = +args.pixelRatio check(pixelRatio > 0, 'invalid pixel ratio') } } } else { check.raise('invalid arguments to regl') } if (element) { if (element.nodeName.toLowerCase() === 'canvas') { canvas = element } else { container = element } } if (!gl) { if (!canvas) { check( typeof document !== 'undefined', 'must manually specify webgl context outside of DOM environments') var result = createCanvas(container || document.body, onDone, pixelRatio) if (!result) { return null } canvas = result.canvas onDestroy = result.onDestroy } // workaround for chromium bug, premultiplied alpha value is platform dependent if (contextAttributes.premultipliedAlpha === undefined) contextAttributes.premultipliedAlpha = true gl = createContext(canvas, contextAttributes) } if (!gl) { onDestroy() onDone('webgl not supported, try upgrading your browser or graphics drivers http://get.webgl.org') return null } return { gl: gl, canvas: canvas, container: container, extensions: extensions, optionalExtensions: optionalExtensions, pixelRatio: pixelRatio, profile: profile, onDone: onDone, onDestroy: onDestroy } }