diff --git a/.gitignore b/.gitignore index 3465ead02..49dc29d94 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules/ docs/ +.vscode/ diff --git a/dist/gmaps.js b/dist/gmaps.js index a3bf3a142..1a09e1467 100644 --- a/dist/gmaps.js +++ b/dist/gmaps.js @@ -60,2579 +60,667 @@ /******/ __webpack_require__.p = ""; /******/ /******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 10); +/******/ return __webpack_require__(__webpack_require__.s = 25); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ -/***/ (function(module, exports, __webpack_require__) { +/***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; +Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Property", function() { return Property; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Blend", function() { return Blend; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Now", function() { return Now; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Near", function() { return Near; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Color", function() { return Color; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Float", function() { return Float; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RampColor", function() { return RampColor; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FloatMul", function() { return FloatMul; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FloatDiv", function() { return FloatDiv; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FloatAdd", function() { return FloatAdd; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FloatSub", function() { return FloatSub; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FloatPow", function() { return FloatPow; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "setGL", function() { return setGL; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "schemas", function() { return schemas; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_cartocolor__ = __webpack_require__(13); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_cartocolor___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_cartocolor__); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__schema__ = __webpack_require__(17); -var VectorTileFeature = __webpack_require__(1); - -module.exports = VectorTileLayer; - -function VectorTileLayer(pbf, end) { - // Public - this.version = 1; - this.name = null; - this.extent = 4096; - this.length = 0; - - // Private - this._pbf = pbf; - this._keys = []; - this._values = []; - this._features = []; - - pbf.readFields(readLayer, this, end); - - this.length = this._features.length; -} - -function readLayer(tag, layer, pbf) { - if (tag === 15) layer.version = pbf.readVarint(); - else if (tag === 1) layer.name = pbf.readString(); - else if (tag === 5) layer.extent = pbf.readVarint(); - else if (tag === 2) layer._features.push(pbf.pos); - else if (tag === 3) layer._keys.push(pbf.readString()); - else if (tag === 4) layer._values.push(readValueMessage(pbf)); -} - -function readValueMessage(pbf) { - var value = null, - end = pbf.readVarint() + pbf.pos; - - while (pbf.pos < end) { - var tag = pbf.readVarint() >> 3; - value = tag === 1 ? pbf.readString() : - tag === 2 ? pbf.readFloat() : - tag === 3 ? pbf.readDouble() : - tag === 4 ? pbf.readVarint64() : - tag === 5 ? pbf.readVarint() : - tag === 6 ? pbf.readSVarint() : - tag === 7 ? pbf.readBoolean() : null; +function implicitCast(value) { + if (Number.isFinite(value)) { + return Float(value); } - return value; } - -// return feature `i` from this layer as a `VectorTileFeature` -VectorTileLayer.prototype.feature = function(i) { - if (i < 0 || i >= this._features.length) throw new Error('feature index out of bounds'); - - this._pbf.pos = this._features[i]; - - var end = this._pbf.readVarint() + this._pbf.pos; - return new VectorTileFeature(this._pbf, end, this.extent, this._keys, this._values); -}; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +var gl = null; +function setGL(_gl) { + gl = _gl; +} -var Point = __webpack_require__(5); +const schemas = {}; +Object.keys(__WEBPACK_IMPORTED_MODULE_0_cartocolor__).map(name => { + const s = __WEBPACK_IMPORTED_MODULE_0_cartocolor__[name]; + var defaultFound = false; + for (let i = 20; i >= 0; i--) { + if (s[i]) { + if (!defaultFound) { + schemas[name.toLowerCase()] = () => s[i]; + defaultFound = true; + } + schemas[`${name.toLowerCase()}_${i}`] = () => s[i]; + } + } +}); -module.exports = VectorTileFeature; -function VectorTileFeature(pbf, end, extent, keys, values) { - // Public - this.properties = {}; - this.extent = extent; - this.type = 0; +/* + Each styling function should: + - Create their own objects, i.e.: be used without "new" + - Check input validity on user input (constructor and exposed functions). + - Have certain functions that never fail: + - _applyToShaderSource should use uniformIDMaker and propertyTIDMaker to get unique uniform IDs and property IDs as needed + - _postShaderCompile should get uniform location after program compilation as needed + - _preDraw should set any program's uniforms as needed + - isAnimated should return true if the function output could change depending on the timestamp + - Have a type property declaring the GLSL output type: 'float', 'color' +*/ - // Private - this._pbf = pbf; - this._geometry = -1; - this._keys = keys; - this._values = values; +/* + TODO + - Integrated color palettes + - Type checking for color palettes + - Allow multiplication, division and pow() to color expressions and color literals + - Add SetOpacity(colorExpr, opacityFloatOverride) + - HSV + - Think about uniform-only types / parameters + - Think about "Date" and "string" types. + - Heatmaps (renderer should be improved too to accommodate this) +*/ - pbf.readFields(readFeature, this, end); +function Property(name, schema) { + return new _Property(name, schema); } - -function readFeature(tag, feature, pbf) { - if (tag == 1) feature.id = pbf.readVarint(); - else if (tag == 2) readTag(pbf, feature); - else if (tag == 3) feature.type = pbf.readVarint(); - else if (tag == 4) feature._geometry = pbf.pos; +function _Property(name, schema) { + if (typeof name !== 'string' || name == '') { + throw new Error(`Invalid property name '${name}'`); + } + if (!schema[name]) { + throw new Error(`Property name not found`); + } + this.name = name; + this.type = 'float'; + this.schema = schema; +} +_Property.prototype._applyToShaderSource = function (uniformIDMaker, propertyTIDMaker) { + return { + preface: '', + inline: `p${propertyTIDMaker(this.name)}` + }; +} +_Property.prototype._postShaderCompile = function (program) { +} +_Property.prototype._preDraw = function () { +} +_Property.prototype.isAnimated = function () { + return false; } -function readTag(pbf, feature) { - var end = pbf.readVarint() + pbf.pos; - - while (pbf.pos < end) { - var key = feature._keys[pbf.readVarint()], - value = feature._values[pbf.readVarint()]; - feature.properties[key] = value; +function Now(speed) { + return new _Now(speed); +} +function _Now(speed) { + if (speed == undefined) { + speed = 1; + } + if (!Number.isFinite(Number(speed))) { + throw new Error('Now() only accepts number literals'); } + this.speed = Number(speed); + this.type = 'float'; + this.float = Float(0); +} +_Now.prototype._applyToShaderSource = function (uniformIDMaker) { + return this.float._applyToShaderSource(uniformIDMaker); +} +_Now.prototype._postShaderCompile = function (program) { + return this.float._postShaderCompile(program); +} +_Now.prototype._preDraw = function () { + this.float.expr = (Date.now() * this.speed / 1000.) % 1; + this.float._preDraw(); +} +_Now.prototype.isAnimated = function () { + return true; } -VectorTileFeature.types = ['Unknown', 'Point', 'LineString', 'Polygon']; - -VectorTileFeature.prototype.loadGeometry = function() { - var pbf = this._pbf; - pbf.pos = this._geometry; - - var end = pbf.readVarint() + pbf.pos, - cmd = 1, - length = 0, - x = 0, - y = 0, - lines = [], - line; +const FloatMul = genFloatBinaryOperation((x, y) => x * y, (x, y) => `(${x} * ${y})`); +const FloatDiv = genFloatBinaryOperation((x, y) => x / y, (x, y) => `(${x} / ${y})`); +const FloatAdd = genFloatBinaryOperation((x, y) => x + y, (x, y) => `(${x} + ${y})`); +const FloatSub = genFloatBinaryOperation((x, y) => x - y, (x, y) => `(${x} - ${y})`); +const FloatPow = genFloatBinaryOperation((x, y) => Math.pow(x, y), (x, y) => `pow(${x}, ${y})`); - while (pbf.pos < end) { - if (!length) { - var cmdLen = pbf.readVarint(); - cmd = cmdLen & 0x7; - length = cmdLen >> 3; +function genFloatBinaryOperation(jsFn, glsl) { + function BinaryOp(a, b) { + if (Number.isFinite(a) && Number.isFinite(b)) { + return Float(jsFn(a, b)); } - - length--; - - if (cmd === 1 || cmd === 2) { - x += pbf.readSVarint(); - y += pbf.readSVarint(); - - if (cmd === 1) { // moveTo - if (line) lines.push(line); - line = []; - } - - line.push(new Point(x, y)); - - } else if (cmd === 7) { - - // Workaround for https://github.com/mapbox/mapnik-vector-tile/issues/90 - if (line) { - line.push(line[0].clone()); // closePolygon - } - + if (Number.isFinite(a)) { + a = Float(a); + } + if (Number.isFinite(b)) { + b = Float(b); + } + if (a.type == 'float' && b.type == 'float') { + this.type = 'float'; } else { - throw new Error('unknown command ' + cmd); + console.warn(a, b); + throw new Error(`Binary operation cannot be performed between '${a}' and '${b}'`); } + return new _BinaryOp(a, b); } - - if (line) lines.push(line); - - return lines; -}; - -VectorTileFeature.prototype.bbox = function() { - var pbf = this._pbf; - pbf.pos = this._geometry; - - var end = pbf.readVarint() + pbf.pos, - cmd = 1, - length = 0, - x = 0, - y = 0, - x1 = Infinity, - x2 = -Infinity, - y1 = Infinity, - y2 = -Infinity; - - while (pbf.pos < end) { - if (!length) { - var cmdLen = pbf.readVarint(); - cmd = cmdLen & 0x7; - length = cmdLen >> 3; - } - - length--; - - if (cmd === 1 || cmd === 2) { - x += pbf.readSVarint(); - y += pbf.readSVarint(); - if (x < x1) x1 = x; - if (x > x2) x2 = x; - if (y < y1) y1 = y; - if (y > y2) y2 = y; - - } else if (cmd !== 7) { - throw new Error('unknown command ' + cmd); - } + function _BinaryOp(a, b) { + this.type = 'float'; + this.a = a; + this.b = b; + a.parent = this; + b.parent = this; } - - return [x1, y1, x2, y2]; -}; - -VectorTileFeature.prototype.toGeoJSON = function(x, y, z) { - var size = this.extent * Math.pow(2, z), - x0 = this.extent * x, - y0 = this.extent * y, - coords = this.loadGeometry(), - type = VectorTileFeature.types[this.type], - i, j; - - function project(line) { - for (var j = 0; j < line.length; j++) { - var p = line[j], y2 = 180 - (p.y + y0) * 360 / size; - line[j] = [ - (p.x + x0) * 360 / size - 180, - 360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90 - ]; - } + _BinaryOp.prototype._applyToShaderSource = function (uniformIDMaker, propertyTIDMaker) { + const a = this.a._applyToShaderSource(uniformIDMaker, propertyTIDMaker); + const b = this.b._applyToShaderSource(uniformIDMaker, propertyTIDMaker); + return { + preface: a.preface + b.preface, + inline: glsl(a.inline, b.inline) + }; } - - switch (this.type) { - case 1: - var points = []; - for (i = 0; i < coords.length; i++) { - points[i] = coords[i][0]; - } - coords = points; - project(coords); - break; - - case 2: - for (i = 0; i < coords.length; i++) { - project(coords[i]); - } - break; - - case 3: - coords = classifyRings(coords); - for (i = 0; i < coords.length; i++) { - for (j = 0; j < coords[i].length; j++) { - project(coords[i][j]); - } - } - break; + _BinaryOp.prototype._postShaderCompile = function (program) { + this.a._postShaderCompile(program); + this.b._postShaderCompile(program); } - - if (coords.length === 1) { - coords = coords[0]; - } else { - type = 'Multi' + type; + _BinaryOp.prototype._preDraw = function (l) { + this.a._preDraw(l); + this.b._preDraw(l); } - - var result = { - type: "Feature", - geometry: { - type: type, - coordinates: coords - }, - properties: this.properties - }; - - if ('id' in this) { - result.id = this.id; + _BinaryOp.prototype.isAnimated = function () { + return this.a.isAnimated() || this.b.isAnimated(); } - - return result; -}; - -// classifies an array of rings into polygons with outer rings and holes - -function classifyRings(rings) { - var len = rings.length; - - if (len <= 1) return [rings]; - - var polygons = [], - polygon, - ccw; - - for (var i = 0; i < len; i++) { - var area = signedArea(rings[i]); - if (area === 0) continue; - - if (ccw === undefined) ccw = area < 0; - - if (ccw === area < 0) { - if (polygon) polygons.push(polygon); - polygon = [rings[i]]; - + _BinaryOp.prototype.replaceChild = function (toReplace, replacer) { + if (this.a = toReplace) { + this.a = replacer; } else { - polygon.push(rings[i]); + this.b = replacer; } + replacer.parent = this; + replacer.notify = toReplace.notify; } - if (polygon) polygons.push(polygon); - - return polygons; -} - -function signedArea(ring) { - var sum = 0; - for (var i = 0, len = ring.length, j = len - 1, p1, p2; i < len; j = i++) { - p1 = ring[i]; - p2 = ring[j]; - sum += (p2.x - p1.x) * (p1.y + p2.y); + _BinaryOp.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { + genericBlend(this, finalValue, duration, blendFunc); } - return sum; + return BinaryOp; } - -/***/ }), -/* 2 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Renderer; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__shaders__ = __webpack_require__(12); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__style__ = __webpack_require__(20); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__scheme__ = __webpack_require__(25); -/* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "c", function() { return __WEBPACK_IMPORTED_MODULE_1__style__; }); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return __WEBPACK_IMPORTED_MODULE_2__scheme__["a"]; }); - - - - -// TODO remove -var gl; - -// The maximum number of features per tile is RTT_WIDTH^2, large RTT_WIDTH values can be unsupported by the hardware, -// they imply a small waste of resources too -const RTT_WIDTH = 1024; - -Renderer.prototype._initShaders = function () { - this.finalRendererProgram = __WEBPACK_IMPORTED_MODULE_0__shaders__["a" /* renderer */].createPointShader(gl); +function Animation(duration) { + return new _Animation(duration); } - -Renderer.prototype.refresh = refresh; -function refresh(timestamp) { - // Don't re-render more than once per animation frame - if (this.lastFrame == timestamp) { - return; +function _Animation(duration) { + if (!Number.isFinite(duration)) { + throw new Error("Animation only supports number literals"); } - this.lastFrame = timestamp; - var canvas = this.canvas; - var width = gl.canvas.clientWidth; - var height = gl.canvas.clientHeight; - if (gl.canvas.width != width || - gl.canvas.height != height) { - gl.canvas.width = width; - gl.canvas.height = height; + this.type = 'float'; + this.aTime = Date.now(); + this.bTime = this.aTime + Number(duration); +} +_Animation.prototype._applyToShaderSource = function (uniformIDMaker, propertyTIDMaker) { + this._uniformID = uniformIDMaker(); + return { + preface: `uniform float anim${this._uniformID};\n`, + inline: `anim${this._uniformID}` + }; +} +_Animation.prototype._postShaderCompile = function (program) { + this._uniformLocation = gl.getUniformLocation(program, `anim${this._uniformID}`); +} +_Animation.prototype._preDraw = function (l) { + const time = Date.now(); + this.mix = (time - this.aTime) / (this.bTime - this.aTime); + if (this.mix > 1.) { + gl.uniform1f(this._uniformLocation, 1); + } else { + gl.uniform1f(this._uniformLocation, this.mix); } - var aspect = canvas.clientWidth / canvas.clientHeight; - gl.clearColor(0., 0., 0., 0.);//TODO this should be a renderer property - gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); - - gl.enable(gl.CULL_FACE); - - //TODO refactor condition - gl.disable(gl.BLEND); - gl.disable(gl.DEPTH_TEST); +} +_Animation.prototype.isAnimated = function () { + return !this.mix || this.mix <= 1.; +} - if (!this.auxFB) { - this.auxFB = gl.createFramebuffer(); +function Near(property, center, threshold, falloff) { + const args = [property, center, threshold, falloff].map(implicitCast); + if (args.some(x => x === undefined || x === null)) { + throw new Error(`Invalid arguments to Near(): ${args}`); } - gl.bindFramebuffer(gl.FRAMEBUFFER, this.auxFB); - //console.log("Restyle", timestamp) - // Render To Texture - // COLOR - this.tiles.forEach(tile => { - gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tile.texColor, 0); - gl.viewport(0, 0, RTT_WIDTH, tile.height); - gl.clear(gl.COLOR_BUFFER_BIT); - - gl.useProgram(tile.style.colorShader.program); - var obj = { - freeTexUnit: 4 - } - tile.style._color._preDraw(obj); + return new _Near(...args); +} - Object.keys(tile.style.propertyColorTID).forEach((name, i) => { - gl.activeTexture(gl.TEXTURE0 + i); - gl.bindTexture(gl.TEXTURE_2D, tile.propertyTex[tile.propertyID[name]]); - gl.uniform1i(tile.style.colorShader.textureLocations[i], i); - }); - - gl.enableVertexAttribArray(this.colorShaderVertex); - gl.bindBuffer(gl.ARRAY_BUFFER, this.squareBuffer); - gl.vertexAttribPointer(tile.style.colorShader.vertexAttribute, 2, gl.FLOAT, false, 0, 0); - - gl.drawArrays(gl.TRIANGLES, 0, 3); - }); - - //WIDTH - this.tiles.forEach(tile => { - gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tile.texWidth, 0); - gl.useProgram(tile.style.widthShader.program); - gl.viewport(0, 0, RTT_WIDTH, tile.height); - gl.clear(gl.COLOR_BUFFER_BIT); - var obj = { - freeTexUnit: 4 - } - tile.style._width._preDraw(obj); - Object.keys(tile.style.propertyWidthTID).forEach((name, i) => { - gl.activeTexture(gl.TEXTURE0 + i); - gl.bindTexture(gl.TEXTURE_2D, tile.propertyTex[tile.propertyID[name]]); - gl.uniform1i(tile.style.widthShader.textureLocations[i], i); - }); - - gl.enableVertexAttribArray(tile.style.widthShader.vertexAttribute); - gl.bindBuffer(gl.ARRAY_BUFFER, this.squareBuffer); - gl.vertexAttribPointer(tile.style.widthShader.vertexAttribute, 2, gl.FLOAT, false, 0, 0); - - gl.drawArrays(gl.TRIANGLES, 0, 3); - - tile.style.updated = false; - tile.initialized = true; - }); - - - gl.enable(gl.DEPTH_TEST); - - gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); - gl.enable(gl.BLEND); - - gl.bindFramebuffer(gl.FRAMEBUFFER, null); - gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); - - gl.useProgram(this.finalRendererProgram.program); - var s = 1. / this._zoom; - - - this.tiles.forEach(tile => { - /*console.log((s / aspect) * tile.scale, - s * tile.scale, - (s / aspect) * this._center.x - tile.center.x, - s * this._center.y - tile.center.y - );*/ - gl.uniform2f(this.finalRendererProgram.vertexScaleUniformLocation, - (s / aspect) * tile.scale, - s * tile.scale); - gl.uniform2f(this.finalRendererProgram.vertexOffsetUniformLocation, - (s / aspect) * (this._center.x - tile.center.x), - s * (this._center.y - tile.center.y)); - - gl.enableVertexAttribArray(this.finalRendererProgram.vertexPositionAttribute); - gl.bindBuffer(gl.ARRAY_BUFFER, tile.vertexBuffer); - gl.vertexAttribPointer(this.finalRendererProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); +function _Near(input, center, threshold, falloff) { + if (input.type != 'float' || center.type != 'float' || threshold.type != 'float' || falloff.type != 'float') { + throw new Error('Near(): invalid parameter type'); + } + this.type = 'float'; + this.input = input; + this.center = center; + this.threshold = threshold; + this.falloff = falloff; +} +_Near.prototype._applyToShaderSource = function (uniformIDMaker, propertyTIDMaker) { + this._UID = uniformIDMaker(); + const tid = propertyTIDMaker(this.property); + const input = this.input._applyToShaderSource(uniformIDMaker, propertyTIDMaker); + const center = this.center._applyToShaderSource(uniformIDMaker, propertyTIDMaker); + const threshold = this.threshold._applyToShaderSource(uniformIDMaker, propertyTIDMaker); + const falloff = this.falloff._applyToShaderSource(uniformIDMaker, propertyTIDMaker); + return { + preface: + input.preface + center.preface + threshold.preface + falloff.preface, + inline: `1.-clamp((abs(${input.inline}-${center.inline})-${threshold.inline})/${falloff.inline}, + 0., 1.)` + }; +} +_Near.prototype._postShaderCompile = function (program) { + this.center._postShaderCompile(program); + this.threshold._postShaderCompile(program); + this.falloff._postShaderCompile(program); + this.input._postShaderCompile(program); +} +_Near.prototype._preDraw = function () { + this.center._preDraw(); + this.threshold._preDraw(); + this.falloff._preDraw(); + this.input._preDraw(); +} +_Near.prototype.isAnimated = function () { + return this.center.isAnimated(); +} - gl.enableVertexAttribArray(this.finalRendererProgram.featureIdAttr); - gl.bindBuffer(gl.ARRAY_BUFFER, tile.featureIDBuffer); - gl.vertexAttribPointer(this.finalRendererProgram.featureIdAttr, 2, gl.FLOAT, false, 0, 0); - gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, tile.texColor); - gl.uniform1i(this.finalRendererProgram.colorTexture, 0); +function Blend(a, b, mix) { + const args = [a, b, mix].map(implicitCast); + if (args.some(x => x === undefined || x === null)) { + throw new Error(`Invalid arguments to Blend(): ${args}`); + } + return new _Blend(...args); +} +function _Blend(a, b, mix) { + if (a.type == 'float' && b.type == 'float') { + this.type = 'float'; + } else if (a.type == 'color' && b.type == 'color') { + this.type = 'color'; + } else { + console.warn(a, b); + throw new Error(`Blending cannot be performed between types '${a.type}' and '${b.type}'`); + } + if (__WEBPACK_IMPORTED_MODULE_1__schema__["b" /* checkschemaMatch */](a.schema, b.schema)) { + throw new Error('Blend parameters schemas mismatch'); + } + this.schema = a.schema; + this.a = a; + this.b = b; + this.mix = mix; + a.parent = this; + b.parent = this; + mix.parent = this; +} +_Blend.prototype._applyToShaderSource = function (uniformIDMaker, propertyTIDMaker) { + const a = this.a._applyToShaderSource(uniformIDMaker, propertyTIDMaker); + const b = this.b._applyToShaderSource(uniformIDMaker, propertyTIDMaker); + const mix = this.mix._applyToShaderSource(uniformIDMaker, propertyTIDMaker); + return { + preface: `${a.preface}${b.preface}${mix.preface}`, + inline: `mix(${a.inline}, ${b.inline}, ${mix.inline})` + }; +} +_Blend.prototype._postShaderCompile = function (program) { + this.a._postShaderCompile(program); + this.b._postShaderCompile(program); + this.mix._postShaderCompile(program); +} +_Blend.prototype._preDraw = function (l) { + this.a._preDraw(l); + this.b._preDraw(l); + this.mix._preDraw(l); + if (this.mix instanceof _Animation && !this.mix.isAnimated()) { + this.parent.replaceChild(this, this.b); + } +} +_Blend.prototype.isAnimated = function () { + return this.a.isAnimated() || this.b.isAnimated() || this.mix.isAnimated(); +} +_Blend.prototype.replaceChild = function (toReplace, replacer) { + if (this.a = toReplace) { + this.a = replacer; + } else { + this.b = replacer; + } + replacer.parent = this; + replacer.notify = toReplace.notify; +} - gl.activeTexture(gl.TEXTURE1); - gl.bindTexture(gl.TEXTURE_2D, tile.texWidth); - gl.uniform1i(this.finalRendererProgram.widthTexture, 1); +function genericBlend(initial, final, duration, blendFunc) { + const parent = initial.parent; + const blend = Blend(initial, final, Animation(duration)); + parent.replaceChild(initial, blend); + blend.notify(); +} +UniformColor.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { + genericBlend(this, finalValue, duration, blendFunc); +} +_RampColor.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { + genericBlend(this, finalValue, duration, blendFunc); +} - gl.drawArrays(gl.POINTS, 0, tile.numVertex); +_Near.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { + genericBlend(this, finalValue, duration, blendFunc); +} +UniformFloat.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { + genericBlend(this, finalValue, duration, blendFunc); +} +_Blend.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { + genericBlend(this, finalValue, duration, blendFunc); +} +_Property.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { + genericBlend(this, finalValue, duration, blendFunc); +} - }); - this.tiles.forEach(t => { - if (t.style._color.isAnimated() || t.style._width.isAnimated()) { - window.requestAnimationFrame(refresh.bind(this)); +function Color(color) { + if (Array.isArray(color)) { + color = color.filter(x => true); + if (color.length != 4 || !color.every(Number.isFinite)) { + throw new Error(`Invalid arguments to Color(): ${args}`); } + return new UniformColor(color); + } + throw new Error(`Invalid arguments to Color(): ${args}`); +} +function UniformColor(color) { + this.type = 'color'; + this.color = color; +} +UniformColor.prototype._applyToShaderSource = function (uniformIDMaker) { + this._uniformID = uniformIDMaker(); + return { + preface: `uniform vec4 color${this._uniformID};\n`, + inline: `color${this._uniformID}` + }; +} +UniformColor.prototype._postShaderCompile = function (program) { + this._uniformLocation = gl.getUniformLocation(program, `color${this._uniformID}`); +} +function evalColor(color, time) { + if (Array.isArray(color)) { + return color; + } + var a = evalColor(color.a, time); + var b = evalColor(color.b, time); + var m = (time - color.aTime) / (color.bTime - color.aTime); + return a.map((va, index) => { + return (1 - m) * va + m * b[index];//TODO non linear functions }); } - -Renderer.prototype.removeTile = function (tile) { - this.tiles = this.tiles.filter(t => t !== tile); - tile.propertyTex.map(tex => gl.deleteTexture(tex)); - gl.deleteTexture(tile.texColor); - gl.deleteTexture(tile.texWidth); - gl.deleteBuffer(tile.vertexBuffer); - gl.deleteBuffer(tile.featureIDBuffer); +function simplifyColorExpr(color, time) { + if (Array.isArray(color)) { + return color; + } + var m = (time - color.aTime) / (color.bTime - color.aTime); + if (m >= 1) { + return color.b; + } + return color; +} +UniformColor.prototype._preDraw = function () { + const t = Date.now(); + this.color = simplifyColorExpr(this.color, t); + const color = evalColor(this.color, t); + gl.uniform4f(this._uniformLocation, color[0], color[1], color[2], color[3]); +} +UniformColor.prototype.isAnimated = function () { + return false; } -Renderer.prototype.addTile = function (tile) { - this.tiles.push(tile); - tile.propertyTex = []; - - var points = tile.geom; - const level = 0; - const width = RTT_WIDTH; - tile.numVertex = points.length / 2; - const height = Math.ceil(tile.numVertex / width); - const border = 0; - const srcFormat = gl.RED; - const srcType = gl.FLOAT; - tile.height = height; - tile.propertyID = {}; //Name => PID - tile.propertyCount = 0; - - - for (var k in tile.properties) { - if (tile.properties.hasOwnProperty(k) && tile.properties[k].length > 0) { - const isCategory = !Number.isFinite(tile.properties[k][0]); - const property = tile.properties[k]; - var propertyID = tile.propertyID[k]; - if (propertyID === undefined) { - propertyID = tile.propertyCount; - tile.propertyCount++; - tile.propertyID[k] = propertyID; - } - tile.propertyTex[propertyID] = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, tile.propertyTex[propertyID]); - const pixel = new Float32Array(width * height); - for (var i = 0; i < property.length; i++) { - pixel[i] = property[i]; - } - gl.texImage2D(gl.TEXTURE_2D, level, gl.ALPHA, - width, height, 0, gl.ALPHA, srcType, - pixel); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); - } +function Float(x) { + if (!Number.isFinite(x)) { + throw new Error(`Invalid arguments to Float(): ${args}`); } + return new UniformFloat(x); +} - tile.setStyle = function (style) { - __WEBPACK_IMPORTED_MODULE_2__scheme__["b" /* checkSchemeMatch */](style.scheme, tile.scheme); - this.style = style; +function UniformFloat(size) { + this.type = 'float'; + this.expr = size; +} +UniformFloat.prototype._applyToShaderSource = function (uniformIDMaker) { + this._uniformID = uniformIDMaker(); + return { + preface: `uniform float float${this._uniformID};\n`, + inline: `float${this._uniformID}` + }; +} +UniformFloat.prototype._postShaderCompile = function (program) { + this._uniformLocation = gl.getUniformLocation(program, `float${this._uniformID}`); +} +function evalFloatExpr(expr, time) { + if (Number.isFinite(expr)) { + return expr; } - tile.style = null; - - tile.vertexBuffer = gl.createBuffer(); - tile.featureIDBuffer = gl.createBuffer(); - - - tile.texColor = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, tile.texColor); - gl.texImage2D(gl.TEXTURE_2D, level, gl.RGBA, - width, height, border, gl.RGBA, gl.UNSIGNED_BYTE, - new Uint8Array(4 * width * height).fill(255)); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); - - tile.texWidth = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, tile.texWidth); - gl.texImage2D(gl.TEXTURE_2D, level, gl.RGBA, - width, height, border, gl.RGBA, gl.UNSIGNED_BYTE, - new Uint8Array(4 * width * height).fill(100)); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); - - - - var ids = new Float32Array(points.length); - for (var i = 0; i < points.length; i += 2) { - ids[i + 0] = ((i / 2) % width) / width; - ids[i + 1] = Math.floor((i / 2) / width) / height; + if (typeof expr === "function") { + return x(time); } - - gl.bindBuffer(gl.ARRAY_BUFFER, tile.vertexBuffer); - gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW); - - gl.bindBuffer(gl.ARRAY_BUFFER, tile.featureIDBuffer); - gl.bufferData(gl.ARRAY_BUFFER, ids, gl.STATIC_DRAW); - - gl.bindBuffer(gl.ARRAY_BUFFER, null); - - window.requestAnimationFrame(refresh.bind(this)); - - return tile; + return expr.eval(); } - -/** - * THIS IS A RENDERER. - * @constructor - * @param {HTMLElement} canvas - */ -function Renderer(canvas) { - this.canvas = canvas; - this.tiles = []; - if (!gl) { - gl = canvas.getContext('webgl'); - __WEBPACK_IMPORTED_MODULE_1__style__["setGL"](gl); - var ext = gl.getExtension("OES_texture_float"); - if (!ext) { - console.error("this machine or browser does not support OES_texture_float"); - } - if (!gl) { - console.warn('Unable to initialize WebGL2. Your browser may not support it.'); - return null - } - this._initShaders(); - this._center = { x: 0, y: 0 }; - this._zoom = 1; +function simplifyFloatExpr(expr, time) { + if (Number.isFinite(expr)) { + return expr; } - this.squareBuffer = gl.createBuffer(); - gl.bindBuffer(gl.ARRAY_BUFFER, this.squareBuffer); - var vertices = [ - 10.0, -10.0, - 0.0, 10.0, - -10.0, -10.0, - ]; - gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); + return expr.simplify(); +} +UniformFloat.prototype._preDraw = function (time) { + this.expr = simplifyFloatExpr(this.expr, time); + const v = evalFloatExpr(this.expr, time); + gl.uniform1f(this._uniformLocation, v); +} +UniformFloat.prototype.isAnimated = function () { + return !Number.isFinite(this.expr); } -/** - * Wadus qwuasdfdasfasd fsadfads - * @api Get Renderer center in Renderer coordinates - * @param {fff} - * @name Renderer#getCenter - */ -Renderer.prototype.getCenter = function () { - return { x: this._center.x, y: this._center.y }; -}; +function hexToRgb(hex) { + var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); + return result ? { + r: parseInt(result[1], 16), + g: parseInt(result[2], 16), + b: parseInt(result[3], 16) + } : null; +} -Renderer.prototype.setCenter = function (x, y) { - this._center.x = x; - this._center.y = y; - window.requestAnimationFrame(refresh.bind(this)); -}; -Renderer.prototype.getZoom = function () { - return this._zoom; -} -Renderer.prototype.setZoom = function (zoom) { - this._zoom = zoom; - window.requestAnimationFrame(refresh.bind(this)); +function RampColor(input, minKey, maxKey, values) { + //TODO contiunuos vs discrete should be decided based on input type => cartegory vs float + const args = [input, minKey, maxKey, values].map(implicitCast); + if (args.some(x => x === undefined || x === null)) { + throw new Error(`Invalid arguments to RampColor(): ${args}`); + } + return new _RampColor(...args); } +//Palette => used by Ramp, Ramp gets texture2D from palette by asking for number of buckets (0/interpolated palette, 2,3,4,5,6...) +function _RampColor(input, minKey, maxKey, values) { + this.type = 'color'; + this.input = input; + this.minKey = minKey.expr; + this.maxKey = maxKey.expr; + this.values = values; + this.texture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, this.texture); + const level = 0; + const internalFormat = gl.RGBA; + const width = 256; + const height = 1; + const border = 0; + const srcFormat = gl.RGBA; + const srcType = gl.UNSIGNED_BYTE; + const pixel = new Uint8Array(4 * width); + for (var i = 0; i < width; i++) { + const vlowRaw = values[Math.floor(i / width * (values.length - 1))]; + const vhighRaw = values[Math.ceil(i / width * (values.length - 1))]; + const vlow = [hexToRgb(vlowRaw).r, hexToRgb(vlowRaw).g, hexToRgb(vlowRaw).b, 255]; + const vhigh = [hexToRgb(vhighRaw).r, hexToRgb(vhighRaw).g, hexToRgb(vhighRaw).b, 255]; + const m = i / width * (values.length - 1) - Math.floor(i / width * (values.length - 1)); + const v = vlow.map((low, index) => low * (1. - m) + vhigh[index] * m); + pixel[4 * i + 0] = v[0]; + pixel[4 * i + 1] = v[1]; + pixel[4 * i + 2] = v[2]; + pixel[4 * i + 3] = v[3]; + } -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { + gl.texImage2D(gl.TEXTURE_2D, level, internalFormat, + width, height, border, srcFormat, srcType, + pixel); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); +} -module.exports.VectorTile = __webpack_require__(4); -module.exports.VectorTileFeature = __webpack_require__(1); -module.exports.VectorTileLayer = __webpack_require__(0); +_RampColor.prototype._free = function () { + gl.deleteTexture(this.texture); +} +_RampColor.prototype._applyToShaderSource = function (uniformIDMaker, propertyTIDMaker) { + this._UID = uniformIDMaker(); + const input = this.input._applyToShaderSource(uniformIDMaker, propertyTIDMaker); + return { + preface: input.preface + ` + uniform sampler2D texRamp${this._UID}; + uniform float keyMin${this._UID}; + uniform float keyWidth${this._UID}; + `, + inline: `texture2D(texRamp${this._UID}, vec2((${input.inline}-keyMin${this._UID})/keyWidth${this._UID}, 0.5)).rgba` + }; +} +_RampColor.prototype._postShaderCompile = function (program) { + this.input._postShaderCompile(program); + this._texLoc = gl.getUniformLocation(program, `texRamp${this._UID}`); + this._keyMinLoc = gl.getUniformLocation(program, `keyMin${this._UID}`); + this._keyWidthLoc = gl.getUniformLocation(program, `keyWidth${this._UID}`); +} +_RampColor.prototype._preDraw = function (l) { + this.input._preDraw(l); + gl.activeTexture(gl.TEXTURE0 + l.freeTexUnit);//TODO remove hardcode + gl.bindTexture(gl.TEXTURE_2D, this.texture); + gl.uniform1i(this._texLoc, l.freeTexUnit); + gl.uniform1f(this._keyMinLoc, evalFloatExpr(this.minKey)); + gl.uniform1f(this._keyWidthLoc, evalFloatExpr(this.maxKey) - evalFloatExpr(this.minKey)); + l.freeTexUnit++; +} +_RampColor.prototype.isAnimated = function () { + return false; +} /***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { +/* 1 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return renderer; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return styler; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__renderer__ = __webpack_require__(7); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__styler__ = __webpack_require__(9); -var VectorTileLayer = __webpack_require__(0); -module.exports = VectorTile; +const NUM_TEXTURE_LOCATIONS = 4; -function VectorTile(pbf, end) { - this.layers = pbf.readFields(readTile, {}, end); +function compileShader(gl, sourceCode, type) { + const shader = gl.createShader(type); + gl.shaderSource(shader, sourceCode); + gl.compileShader(shader); + if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { + const log = gl.getShaderInfoLog(shader); + gl.deleteShader(shader); + throw new Error('An error occurred compiling the shaders: ' + log + '\nSource:\n' + sourceCode); + } + return shader; } -function readTile(tag, layers, pbf) { - if (tag === 3) { - var layer = new VectorTileLayer(pbf, pbf.readVarint() + pbf.pos); - if (layer.length) layers[layer.name] = layer; +function compileProgram(gl, glslVS, glslFS) { + const VS = compileShader(gl, glslVS, gl.VERTEX_SHADER); + const FS = compileShader(gl, glslFS, gl.FRAGMENT_SHADER); + this.program = gl.createProgram(); + gl.attachShader(this.program, VS); + gl.attachShader(this.program, FS); + gl.linkProgram(this.program); + gl.deleteShader(VS); + gl.deleteShader(FS); + if (!gl.getProgramParameter(this.program, gl.LINK_STATUS)) { + throw new Error('Unable to link the shader program: ' + gl.getProgramInfoLog(this.program)); } } - - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -module.exports = Point; - -/** - * A standalone point geometry with useful accessor, comparison, and - * modification methods. - * - * @class Point - * @param {Number} x the x-coordinate. this could be longitude or screen - * pixels, or any other sort of unit. - * @param {Number} y the y-coordinate. this could be latitude or screen - * pixels, or any other sort of unit. - * @example - * var point = new Point(-77, 38); - */ -function Point(x, y) { - this.x = x; - this.y = y; +function Point(gl) { + compileProgram.call(this, gl, __WEBPACK_IMPORTED_MODULE_0__renderer__["a" /* point */].VS, __WEBPACK_IMPORTED_MODULE_0__renderer__["a" /* point */].FS); + this.vertexPositionAttribute = gl.getAttribLocation(this.program, 'vertexPosition'); + this.featureIdAttr = gl.getAttribLocation(this.program, 'featureID'); + this.vertexScaleUniformLocation = gl.getUniformLocation(this.program, 'vertexScale'); + this.vertexOffsetUniformLocation = gl.getUniformLocation(this.program, 'vertexOffset'); + this.colorTexture = gl.getUniformLocation(this.program, 'colorTex'); + this.widthTexture = gl.getUniformLocation(this.program, 'widthTex'); +} +function GenericStyler(gl, glsl, preface, inline) { + const VS = glsl.VS; + let FS = glsl.FS; + FS = FS.replace('$PREFACE', preface); + FS = FS.replace('$INLINE', inline); + //console.log(FS) + compileProgram.call(this, gl, VS, FS); + this.vertexAttribute = gl.getAttribLocation(this.program, 'vertex'); + this.textureLocations = []; + for (let i = 0; i < NUM_TEXTURE_LOCATIONS; i++) { + this.textureLocations[i] = gl.getUniformLocation(this.program, `property${i}`); + } +} +function Color(gl, preface, inline) { + GenericStyler.call(this, gl, __WEBPACK_IMPORTED_MODULE_1__styler__["a" /* color */], preface, inline); +} +function Width(gl, preface, inline) { + GenericStyler.call(this, gl, __WEBPACK_IMPORTED_MODULE_1__styler__["b" /* width */], preface, inline); } -Point.prototype = { - - /** - * Clone this point, returning a new point that can be modified - * without affecting the old one. - * @return {Point} the clone - */ - clone: function() { return new Point(this.x, this.y); }, - - /** - * Add this point's x & y coordinates to another point, - * yielding a new point. - * @param {Point} p the other point - * @return {Point} output point - */ - add: function(p) { return this.clone()._add(p); }, - - /** - * Subtract this point's x & y coordinates to from point, - * yielding a new point. - * @param {Point} p the other point - * @return {Point} output point - */ - sub: function(p) { return this.clone()._sub(p); }, - - /** - * Multiply this point's x & y coordinates by point, - * yielding a new point. - * @param {Point} p the other point - * @return {Point} output point - */ - multByPoint: function(p) { return this.clone()._multByPoint(p); }, - - /** - * Divide this point's x & y coordinates by point, - * yielding a new point. - * @param {Point} p the other point - * @return {Point} output point - */ - divByPoint: function(p) { return this.clone()._divByPoint(p); }, - - /** - * Multiply this point's x & y coordinates by a factor, - * yielding a new point. - * @param {Point} k factor - * @return {Point} output point - */ - mult: function(k) { return this.clone()._mult(k); }, - - /** - * Divide this point's x & y coordinates by a factor, - * yielding a new point. - * @param {Point} k factor - * @return {Point} output point - */ - div: function(k) { return this.clone()._div(k); }, - - /** - * Rotate this point around the 0, 0 origin by an angle a, - * given in radians - * @param {Number} a angle to rotate around, in radians - * @return {Point} output point - */ - rotate: function(a) { return this.clone()._rotate(a); }, - - /** - * Rotate this point around p point by an angle a, - * given in radians - * @param {Number} a angle to rotate around, in radians - * @param {Point} p Point to rotate around - * @return {Point} output point - */ - rotateAround: function(a,p) { return this.clone()._rotateAround(a,p); }, - - /** - * Multiply this point by a 4x1 transformation matrix - * @param {Array} m transformation matrix - * @return {Point} output point - */ - matMult: function(m) { return this.clone()._matMult(m); }, - - /** - * Calculate this point but as a unit vector from 0, 0, meaning - * that the distance from the resulting point to the 0, 0 - * coordinate will be equal to 1 and the angle from the resulting - * point to the 0, 0 coordinate will be the same as before. - * @return {Point} unit vector point - */ - unit: function() { return this.clone()._unit(); }, - - /** - * Compute a perpendicular point, where the new y coordinate - * is the old x coordinate and the new x coordinate is the old y - * coordinate multiplied by -1 - * @return {Point} perpendicular point - */ - perp: function() { return this.clone()._perp(); }, - - /** - * Return a version of this point with the x & y coordinates - * rounded to integers. - * @return {Point} rounded point - */ - round: function() { return this.clone()._round(); }, - - /** - * Return the magitude of this point: this is the Euclidean - * distance from the 0, 0 coordinate to this point's x and y - * coordinates. - * @return {Number} magnitude - */ - mag: function() { - return Math.sqrt(this.x * this.x + this.y * this.y); - }, +const renderer = { + createPointShader: function (gl) { + return new Point(gl); + } +}; - /** - * Judge whether this point is equal to another point, returning - * true or false. - * @param {Point} other the other point - * @return {boolean} whether the points are equal - */ - equals: function(other) { - return this.x === other.x && - this.y === other.y; +const styler = { + createColorShader: function (gl, preface, inline) { + return new Color(gl, preface, inline); }, + createWidthShader: function (gl, preface, inline) { + return new Width(gl, preface, inline); + } +}; - /** - * Calculate the distance from this point to another point - * @param {Point} p the other point - * @return {Number} distance - */ - dist: function(p) { - return Math.sqrt(this.distSqr(p)); - }, - /** - * Calculate the distance from this point to another point, - * without the square root step. Useful if you're comparing - * relative distances. - * @param {Point} p the other point - * @return {Number} distance - */ - distSqr: function(p) { - var dx = p.x - this.x, - dy = p.y - this.y; - return dx * dx + dy * dy; - }, - /** - * Get the angle from the 0, 0 coordinate to this point, in radians - * coordinates. - * @return {Number} angle - */ - angle: function() { - return Math.atan2(this.y, this.x); - }, - /** - * Get the angle from this point to another point, in radians - * @param {Point} b the other point - * @return {Number} angle - */ - angleTo: function(b) { - return Math.atan2(this.y - b.y, this.x - b.x); - }, - - /** - * Get the angle between this point and another point, in radians - * @param {Point} b the other point - * @return {Number} angle - */ - angleWith: function(b) { - return this.angleWithSep(b.x, b.y); - }, - - /* - * Find the angle of the two vectors, solving the formula for - * the cross product a x b = |a||b|sin(θ) for θ. - * @param {Number} x the x-coordinate - * @param {Number} y the y-coordinate - * @return {Number} the angle in radians - */ - angleWithSep: function(x, y) { - return Math.atan2( - this.x * y - this.y * x, - this.x * x + this.y * y); - }, - - _matMult: function(m) { - var x = m[0] * this.x + m[1] * this.y, - y = m[2] * this.x + m[3] * this.y; - this.x = x; - this.y = y; - return this; - }, - - _add: function(p) { - this.x += p.x; - this.y += p.y; - return this; - }, - - _sub: function(p) { - this.x -= p.x; - this.y -= p.y; - return this; - }, - - _mult: function(k) { - this.x *= k; - this.y *= k; - return this; - }, - - _div: function(k) { - this.x /= k; - this.y /= k; - return this; - }, - - _multByPoint: function(p) { - this.x *= p.x; - this.y *= p.y; - return this; - }, - - _divByPoint: function(p) { - this.x /= p.x; - this.y /= p.y; - return this; - }, - - _unit: function() { - this._div(this.mag()); - return this; - }, - - _perp: function() { - var y = this.y; - this.y = this.x; - this.x = -y; - return this; - }, - - _rotate: function(angle) { - var cos = Math.cos(angle), - sin = Math.sin(angle), - x = cos * this.x - sin * this.y, - y = sin * this.x + cos * this.y; - this.x = x; - this.y = y; - return this; - }, - - _rotateAround: function(angle, p) { - var cos = Math.cos(angle), - sin = Math.sin(angle), - x = p.x + cos * (this.x - p.x) - sin * (this.y - p.y), - y = p.y + sin * (this.x - p.x) + cos * (this.y - p.y); - this.x = x; - this.y = y; - return this; - }, - - _round: function() { - this.x = Math.round(this.x); - this.y = Math.round(this.y); - return this; - } -}; - -/** - * Construct a point from an array if necessary, otherwise if the input - * is already a Point, or an unknown type, return it unchanged - * @param {Array|Point|*} a any kind of input value - * @return {Point} constructed point, or passed-through value. - * @example - * // this - * var point = Point.convert([0, 1]); - * // is equivalent to - * var point = new Point(0, 1); - */ -Point.convert = function (a) { - if (a instanceof Point) { - return a; - } - if (Array.isArray(a)) { - return new Point(a[0], a[1]); - } - return a; -}; - - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -module.exports = Pbf; - -var ieee754 = __webpack_require__(7); - -function Pbf(buf) { - this.buf = ArrayBuffer.isView && ArrayBuffer.isView(buf) ? buf : new Uint8Array(buf || 0); - this.pos = 0; - this.type = 0; - this.length = this.buf.length; -} - -Pbf.Varint = 0; // varint: int32, int64, uint32, uint64, sint32, sint64, bool, enum -Pbf.Fixed64 = 1; // 64-bit: double, fixed64, sfixed64 -Pbf.Bytes = 2; // length-delimited: string, bytes, embedded messages, packed repeated fields -Pbf.Fixed32 = 5; // 32-bit: float, fixed32, sfixed32 - -var SHIFT_LEFT_32 = (1 << 16) * (1 << 16), - SHIFT_RIGHT_32 = 1 / SHIFT_LEFT_32; - -Pbf.prototype = { - - destroy: function() { - this.buf = null; - }, - - // === READING ================================================================= - - readFields: function(readField, result, end) { - end = end || this.length; - - while (this.pos < end) { - var val = this.readVarint(), - tag = val >> 3, - startPos = this.pos; - - this.type = val & 0x7; - readField(tag, result, this); - - if (this.pos === startPos) this.skip(val); - } - return result; - }, - - readMessage: function(readField, result) { - return this.readFields(readField, result, this.readVarint() + this.pos); - }, - - readFixed32: function() { - var val = readUInt32(this.buf, this.pos); - this.pos += 4; - return val; - }, - - readSFixed32: function() { - var val = readInt32(this.buf, this.pos); - this.pos += 4; - return val; - }, - - // 64-bit int handling is based on github.com/dpw/node-buffer-more-ints (MIT-licensed) - - readFixed64: function() { - var val = readUInt32(this.buf, this.pos) + readUInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32; - this.pos += 8; - return val; - }, - - readSFixed64: function() { - var val = readUInt32(this.buf, this.pos) + readInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32; - this.pos += 8; - return val; - }, - - readFloat: function() { - var val = ieee754.read(this.buf, this.pos, true, 23, 4); - this.pos += 4; - return val; - }, - - readDouble: function() { - var val = ieee754.read(this.buf, this.pos, true, 52, 8); - this.pos += 8; - return val; - }, - - readVarint: function(isSigned) { - var buf = this.buf, - val, b; - - b = buf[this.pos++]; val = b & 0x7f; if (b < 0x80) return val; - b = buf[this.pos++]; val |= (b & 0x7f) << 7; if (b < 0x80) return val; - b = buf[this.pos++]; val |= (b & 0x7f) << 14; if (b < 0x80) return val; - b = buf[this.pos++]; val |= (b & 0x7f) << 21; if (b < 0x80) return val; - b = buf[this.pos]; val |= (b & 0x0f) << 28; - - return readVarintRemainder(val, isSigned, this); - }, - - readVarint64: function() { // for compatibility with v2.0.1 - return this.readVarint(true); - }, - - readSVarint: function() { - var num = this.readVarint(); - return num % 2 === 1 ? (num + 1) / -2 : num / 2; // zigzag encoding - }, - - readBoolean: function() { - return Boolean(this.readVarint()); - }, - - readString: function() { - var end = this.readVarint() + this.pos, - str = readUtf8(this.buf, this.pos, end); - this.pos = end; - return str; - }, - - readBytes: function() { - var end = this.readVarint() + this.pos, - buffer = this.buf.subarray(this.pos, end); - this.pos = end; - return buffer; - }, - - // verbose for performance reasons; doesn't affect gzipped size - - readPackedVarint: function(arr, isSigned) { - var end = readPackedEnd(this); - arr = arr || []; - while (this.pos < end) arr.push(this.readVarint(isSigned)); - return arr; - }, - readPackedSVarint: function(arr) { - var end = readPackedEnd(this); - arr = arr || []; - while (this.pos < end) arr.push(this.readSVarint()); - return arr; - }, - readPackedBoolean: function(arr) { - var end = readPackedEnd(this); - arr = arr || []; - while (this.pos < end) arr.push(this.readBoolean()); - return arr; - }, - readPackedFloat: function(arr) { - var end = readPackedEnd(this); - arr = arr || []; - while (this.pos < end) arr.push(this.readFloat()); - return arr; - }, - readPackedDouble: function(arr) { - var end = readPackedEnd(this); - arr = arr || []; - while (this.pos < end) arr.push(this.readDouble()); - return arr; - }, - readPackedFixed32: function(arr) { - var end = readPackedEnd(this); - arr = arr || []; - while (this.pos < end) arr.push(this.readFixed32()); - return arr; - }, - readPackedSFixed32: function(arr) { - var end = readPackedEnd(this); - arr = arr || []; - while (this.pos < end) arr.push(this.readSFixed32()); - return arr; - }, - readPackedFixed64: function(arr) { - var end = readPackedEnd(this); - arr = arr || []; - while (this.pos < end) arr.push(this.readFixed64()); - return arr; - }, - readPackedSFixed64: function(arr) { - var end = readPackedEnd(this); - arr = arr || []; - while (this.pos < end) arr.push(this.readSFixed64()); - return arr; - }, - - skip: function(val) { - var type = val & 0x7; - if (type === Pbf.Varint) while (this.buf[this.pos++] > 0x7f) {} - else if (type === Pbf.Bytes) this.pos = this.readVarint() + this.pos; - else if (type === Pbf.Fixed32) this.pos += 4; - else if (type === Pbf.Fixed64) this.pos += 8; - else throw new Error('Unimplemented type: ' + type); - }, - - // === WRITING ================================================================= - - writeTag: function(tag, type) { - this.writeVarint((tag << 3) | type); - }, - - realloc: function(min) { - var length = this.length || 16; - - while (length < this.pos + min) length *= 2; - - if (length !== this.length) { - var buf = new Uint8Array(length); - buf.set(this.buf); - this.buf = buf; - this.length = length; - } - }, - - finish: function() { - this.length = this.pos; - this.pos = 0; - return this.buf.subarray(0, this.length); - }, - - writeFixed32: function(val) { - this.realloc(4); - writeInt32(this.buf, val, this.pos); - this.pos += 4; - }, - - writeSFixed32: function(val) { - this.realloc(4); - writeInt32(this.buf, val, this.pos); - this.pos += 4; - }, - - writeFixed64: function(val) { - this.realloc(8); - writeInt32(this.buf, val & -1, this.pos); - writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4); - this.pos += 8; - }, - - writeSFixed64: function(val) { - this.realloc(8); - writeInt32(this.buf, val & -1, this.pos); - writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4); - this.pos += 8; - }, - - writeVarint: function(val) { - val = +val || 0; - - if (val > 0xfffffff || val < 0) { - writeBigVarint(val, this); - return; - } - - this.realloc(4); - - this.buf[this.pos++] = val & 0x7f | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return; - this.buf[this.pos++] = ((val >>>= 7) & 0x7f) | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return; - this.buf[this.pos++] = ((val >>>= 7) & 0x7f) | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return; - this.buf[this.pos++] = (val >>> 7) & 0x7f; - }, - - writeSVarint: function(val) { - this.writeVarint(val < 0 ? -val * 2 - 1 : val * 2); - }, - - writeBoolean: function(val) { - this.writeVarint(Boolean(val)); - }, - - writeString: function(str) { - str = String(str); - this.realloc(str.length * 4); - - this.pos++; // reserve 1 byte for short string length - - var startPos = this.pos; - // write the string directly to the buffer and see how much was written - this.pos = writeUtf8(this.buf, str, this.pos); - var len = this.pos - startPos; - - if (len >= 0x80) makeRoomForExtraLength(startPos, len, this); - - // finally, write the message length in the reserved place and restore the position - this.pos = startPos - 1; - this.writeVarint(len); - this.pos += len; - }, - - writeFloat: function(val) { - this.realloc(4); - ieee754.write(this.buf, val, this.pos, true, 23, 4); - this.pos += 4; - }, - - writeDouble: function(val) { - this.realloc(8); - ieee754.write(this.buf, val, this.pos, true, 52, 8); - this.pos += 8; - }, - - writeBytes: function(buffer) { - var len = buffer.length; - this.writeVarint(len); - this.realloc(len); - for (var i = 0; i < len; i++) this.buf[this.pos++] = buffer[i]; - }, - - writeRawMessage: function(fn, obj) { - this.pos++; // reserve 1 byte for short message length - - // write the message directly to the buffer and see how much was written - var startPos = this.pos; - fn(obj, this); - var len = this.pos - startPos; - - if (len >= 0x80) makeRoomForExtraLength(startPos, len, this); - - // finally, write the message length in the reserved place and restore the position - this.pos = startPos - 1; - this.writeVarint(len); - this.pos += len; - }, - - writeMessage: function(tag, fn, obj) { - this.writeTag(tag, Pbf.Bytes); - this.writeRawMessage(fn, obj); - }, - - writePackedVarint: function(tag, arr) { this.writeMessage(tag, writePackedVarint, arr); }, - writePackedSVarint: function(tag, arr) { this.writeMessage(tag, writePackedSVarint, arr); }, - writePackedBoolean: function(tag, arr) { this.writeMessage(tag, writePackedBoolean, arr); }, - writePackedFloat: function(tag, arr) { this.writeMessage(tag, writePackedFloat, arr); }, - writePackedDouble: function(tag, arr) { this.writeMessage(tag, writePackedDouble, arr); }, - writePackedFixed32: function(tag, arr) { this.writeMessage(tag, writePackedFixed32, arr); }, - writePackedSFixed32: function(tag, arr) { this.writeMessage(tag, writePackedSFixed32, arr); }, - writePackedFixed64: function(tag, arr) { this.writeMessage(tag, writePackedFixed64, arr); }, - writePackedSFixed64: function(tag, arr) { this.writeMessage(tag, writePackedSFixed64, arr); }, - - writeBytesField: function(tag, buffer) { - this.writeTag(tag, Pbf.Bytes); - this.writeBytes(buffer); - }, - writeFixed32Field: function(tag, val) { - this.writeTag(tag, Pbf.Fixed32); - this.writeFixed32(val); - }, - writeSFixed32Field: function(tag, val) { - this.writeTag(tag, Pbf.Fixed32); - this.writeSFixed32(val); - }, - writeFixed64Field: function(tag, val) { - this.writeTag(tag, Pbf.Fixed64); - this.writeFixed64(val); - }, - writeSFixed64Field: function(tag, val) { - this.writeTag(tag, Pbf.Fixed64); - this.writeSFixed64(val); - }, - writeVarintField: function(tag, val) { - this.writeTag(tag, Pbf.Varint); - this.writeVarint(val); - }, - writeSVarintField: function(tag, val) { - this.writeTag(tag, Pbf.Varint); - this.writeSVarint(val); - }, - writeStringField: function(tag, str) { - this.writeTag(tag, Pbf.Bytes); - this.writeString(str); - }, - writeFloatField: function(tag, val) { - this.writeTag(tag, Pbf.Fixed32); - this.writeFloat(val); - }, - writeDoubleField: function(tag, val) { - this.writeTag(tag, Pbf.Fixed64); - this.writeDouble(val); - }, - writeBooleanField: function(tag, val) { - this.writeVarintField(tag, Boolean(val)); - } -}; - -function readVarintRemainder(l, s, p) { - var buf = p.buf, - h, b; - - b = buf[p.pos++]; h = (b & 0x70) >> 4; if (b < 0x80) return toNum(l, h, s); - b = buf[p.pos++]; h |= (b & 0x7f) << 3; if (b < 0x80) return toNum(l, h, s); - b = buf[p.pos++]; h |= (b & 0x7f) << 10; if (b < 0x80) return toNum(l, h, s); - b = buf[p.pos++]; h |= (b & 0x7f) << 17; if (b < 0x80) return toNum(l, h, s); - b = buf[p.pos++]; h |= (b & 0x7f) << 24; if (b < 0x80) return toNum(l, h, s); - b = buf[p.pos++]; h |= (b & 0x01) << 31; if (b < 0x80) return toNum(l, h, s); - - throw new Error('Expected varint not more than 10 bytes'); -} - -function readPackedEnd(pbf) { - return pbf.type === Pbf.Bytes ? - pbf.readVarint() + pbf.pos : pbf.pos + 1; -} - -function toNum(low, high, isSigned) { - if (isSigned) { - return high * 0x100000000 + (low >>> 0); - } - - return ((high >>> 0) * 0x100000000) + (low >>> 0); -} - -function writeBigVarint(val, pbf) { - var low, high; - - if (val >= 0) { - low = (val % 0x100000000) | 0; - high = (val / 0x100000000) | 0; - } else { - low = ~(-val % 0x100000000); - high = ~(-val / 0x100000000); - - if (low ^ 0xffffffff) { - low = (low + 1) | 0; - } else { - low = 0; - high = (high + 1) | 0; - } - } - - if (val >= 0x10000000000000000 || val < -0x10000000000000000) { - throw new Error('Given varint doesn\'t fit into 10 bytes'); - } - - pbf.realloc(10); - - writeBigVarintLow(low, high, pbf); - writeBigVarintHigh(high, pbf); -} - -function writeBigVarintLow(low, high, pbf) { - pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7; - pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7; - pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7; - pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7; - pbf.buf[pbf.pos] = low & 0x7f; -} - -function writeBigVarintHigh(high, pbf) { - var lsb = (high & 0x07) << 4; - - pbf.buf[pbf.pos++] |= lsb | ((high >>>= 3) ? 0x80 : 0); if (!high) return; - pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return; - pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return; - pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return; - pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return; - pbf.buf[pbf.pos++] = high & 0x7f; -} - -function makeRoomForExtraLength(startPos, len, pbf) { - var extraLen = - len <= 0x3fff ? 1 : - len <= 0x1fffff ? 2 : - len <= 0xfffffff ? 3 : Math.ceil(Math.log(len) / (Math.LN2 * 7)); - - // if 1 byte isn't enough for encoding message length, shift the data to the right - pbf.realloc(extraLen); - for (var i = pbf.pos - 1; i >= startPos; i--) pbf.buf[i + extraLen] = pbf.buf[i]; -} - -function writePackedVarint(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeVarint(arr[i]); } -function writePackedSVarint(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSVarint(arr[i]); } -function writePackedFloat(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFloat(arr[i]); } -function writePackedDouble(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeDouble(arr[i]); } -function writePackedBoolean(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeBoolean(arr[i]); } -function writePackedFixed32(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFixed32(arr[i]); } -function writePackedSFixed32(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSFixed32(arr[i]); } -function writePackedFixed64(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFixed64(arr[i]); } -function writePackedSFixed64(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSFixed64(arr[i]); } - -// Buffer code below from https://github.com/feross/buffer, MIT-licensed - -function readUInt32(buf, pos) { - return ((buf[pos]) | - (buf[pos + 1] << 8) | - (buf[pos + 2] << 16)) + - (buf[pos + 3] * 0x1000000); -} - -function writeInt32(buf, val, pos) { - buf[pos] = val; - buf[pos + 1] = (val >>> 8); - buf[pos + 2] = (val >>> 16); - buf[pos + 3] = (val >>> 24); -} - -function readInt32(buf, pos) { - return ((buf[pos]) | - (buf[pos + 1] << 8) | - (buf[pos + 2] << 16)) + - (buf[pos + 3] << 24); -} - -function readUtf8(buf, pos, end) { - var str = ''; - var i = pos; - - while (i < end) { - var b0 = buf[i]; - var c = null; // codepoint - var bytesPerSequence = - b0 > 0xEF ? 4 : - b0 > 0xDF ? 3 : - b0 > 0xBF ? 2 : 1; - - if (i + bytesPerSequence > end) break; - - var b1, b2, b3; - - if (bytesPerSequence === 1) { - if (b0 < 0x80) { - c = b0; - } - } else if (bytesPerSequence === 2) { - b1 = buf[i + 1]; - if ((b1 & 0xC0) === 0x80) { - c = (b0 & 0x1F) << 0x6 | (b1 & 0x3F); - if (c <= 0x7F) { - c = null; - } - } - } else if (bytesPerSequence === 3) { - b1 = buf[i + 1]; - b2 = buf[i + 2]; - if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80) { - c = (b0 & 0xF) << 0xC | (b1 & 0x3F) << 0x6 | (b2 & 0x3F); - if (c <= 0x7FF || (c >= 0xD800 && c <= 0xDFFF)) { - c = null; - } - } - } else if (bytesPerSequence === 4) { - b1 = buf[i + 1]; - b2 = buf[i + 2]; - b3 = buf[i + 3]; - if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80 && (b3 & 0xC0) === 0x80) { - c = (b0 & 0xF) << 0x12 | (b1 & 0x3F) << 0xC | (b2 & 0x3F) << 0x6 | (b3 & 0x3F); - if (c <= 0xFFFF || c >= 0x110000) { - c = null; - } - } - } - - if (c === null) { - c = 0xFFFD; - bytesPerSequence = 1; - - } else if (c > 0xFFFF) { - c -= 0x10000; - str += String.fromCharCode(c >>> 10 & 0x3FF | 0xD800); - c = 0xDC00 | c & 0x3FF; - } - - str += String.fromCharCode(c); - i += bytesPerSequence; - } - - return str; -} - -function writeUtf8(buf, str, pos) { - for (var i = 0, c, lead; i < str.length; i++) { - c = str.charCodeAt(i); // code point - - if (c > 0xD7FF && c < 0xE000) { - if (lead) { - if (c < 0xDC00) { - buf[pos++] = 0xEF; - buf[pos++] = 0xBF; - buf[pos++] = 0xBD; - lead = c; - continue; - } else { - c = lead - 0xD800 << 10 | c - 0xDC00 | 0x10000; - lead = null; - } - } else { - if (c > 0xDBFF || (i + 1 === str.length)) { - buf[pos++] = 0xEF; - buf[pos++] = 0xBF; - buf[pos++] = 0xBD; - } else { - lead = c; - } - continue; - } - } else if (lead) { - buf[pos++] = 0xEF; - buf[pos++] = 0xBF; - buf[pos++] = 0xBD; - lead = null; - } - - if (c < 0x80) { - buf[pos++] = c; - } else { - if (c < 0x800) { - buf[pos++] = c >> 0x6 | 0xC0; - } else { - if (c < 0x10000) { - buf[pos++] = c >> 0xC | 0xE0; - } else { - buf[pos++] = c >> 0x12 | 0xF0; - buf[pos++] = c >> 0xC & 0x3F | 0x80; - } - buf[pos++] = c >> 0x6 & 0x3F | 0x80; - } - buf[pos++] = c & 0x3F | 0x80; - } - } - return pos; -} - - -/***/ }), -/* 7 */ -/***/ (function(module, exports) { - -exports.read = function (buffer, offset, isLE, mLen, nBytes) { - var e, m - var eLen = nBytes * 8 - mLen - 1 - var eMax = (1 << eLen) - 1 - var eBias = eMax >> 1 - var nBits = -7 - var i = isLE ? (nBytes - 1) : 0 - var d = isLE ? -1 : 1 - var s = buffer[offset + i] - - i += d - - e = s & ((1 << (-nBits)) - 1) - s >>= (-nBits) - nBits += eLen - for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {} - - m = e & ((1 << (-nBits)) - 1) - e >>= (-nBits) - nBits += mLen - for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {} - - if (e === 0) { - e = 1 - eBias - } else if (e === eMax) { - return m ? NaN : ((s ? -1 : 1) * Infinity) - } else { - m = m + Math.pow(2, mLen) - e = e - eBias - } - return (s ? -1 : 1) * m * Math.pow(2, e - mLen) -} - -exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { - var e, m, c - var eLen = nBytes * 8 - mLen - 1 - var eMax = (1 << eLen) - 1 - var eBias = eMax >> 1 - var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0) - var i = isLE ? 0 : (nBytes - 1) - var d = isLE ? 1 : -1 - var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0 - - value = Math.abs(value) - - if (isNaN(value) || value === Infinity) { - m = isNaN(value) ? 1 : 0 - e = eMax - } else { - e = Math.floor(Math.log(value) / Math.LN2) - if (value * (c = Math.pow(2, -e)) < 1) { - e-- - c *= 2 - } - if (e + eBias >= 1) { - value += rt / c - } else { - value += rt * Math.pow(2, 1 - eBias) - } - if (value * c >= 2) { - e++ - c /= 2 - } - - if (e + eBias >= eMax) { - m = 0 - e = eMax - } else if (e + eBias >= 1) { - m = (value * c - 1) * Math.pow(2, mLen) - e = e + eBias - } else { - m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen) - e = 0 - } - } - - for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} - - e = (e << mLen) | m - eLen += mLen - for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} - - buffer[offset + i - d] |= s * 128 -} - - -/***/ }), -/* 8 */, -/* 9 */, -/* 10 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__src_index__ = __webpack_require__(2); - - -var VectorTile = __webpack_require__(3).VectorTile; -var Protobuf = __webpack_require__(6); - -var renderer; -var layer; -var oldtile; -var ajax; - -function styleWidth(e) { - const v = document.getElementById("widthStyleEntry").value; - const Near = __WEBPACK_IMPORTED_MODULE_0__src_index__["c" /* Style */].Near; - const Float = __WEBPACK_IMPORTED_MODULE_0__src_index__["c" /* Style */].Float; - const Color = __WEBPACK_IMPORTED_MODULE_0__src_index__["c" /* Style */].Color; - const RampColor = __WEBPACK_IMPORTED_MODULE_0__src_index__["c" /* Style */].RampColor; - const width = eval(v); - if (width) { - layer.style.getWidth().blendTo(width, 1000); - } -} -function styleColor(e) { - const v = document.getElementById("colorStyleEntry").value; - const Near = __WEBPACK_IMPORTED_MODULE_0__src_index__["c" /* Style */].Near; - const Float = __WEBPACK_IMPORTED_MODULE_0__src_index__["c" /* Style */].Float; - const Color = __WEBPACK_IMPORTED_MODULE_0__src_index__["c" /* Style */].Color; - const RampColor = __WEBPACK_IMPORTED_MODULE_0__src_index__["c" /* Style */].RampColor; - const color = eval(v); - if (color) { - layer.style.getColor().blendTo(color, 1000); - } -} - -function getData() { - if (ajax) { - ajax.abort(); - } - - var oReq = new XMLHttpRequest(); - oReq.open("GET", "https://dmanzanares.carto.com/api/v1/map/dmanzanares@789cad67@92456f0655aac0322b2572f4e05088e7:1509358508954/mapnik/0/0/0.mvt", true); - oReq.responseType = "arraybuffer"; - oReq.onload = function (oEvent) { - var arrayBuffer = oReq.response; - if (arrayBuffer) { - var tile = new VectorTile(new Protobuf(arrayBuffer)); - const mvtLayer = tile.layers[Object.keys(tile.layers)[0]]; - - var fieldMap = { - temp: 0, - daten: 1 - }; - //mvtLayer.length=1000; - var properties = [[new Float32Array(mvtLayer.length)], [new Float32Array(mvtLayer.length)]]; - var points = new Float32Array(mvtLayer.length * 2); - for (var i = 0; i < mvtLayer.length; i++) { - const f = mvtLayer.feature(i); - const geom = f.loadGeometry(); - points[2 * i + 0] = 2 * (geom[0][0].x) / 4096.0 - 1.; - points[2 * i + 1] = 2 * (1. - (geom[0][0].y) / 4096.0) - 1.; - - properties[0][i] = Number(f.properties.temp); - properties[1][i] = Number(f.properties.daten); - } - var tile = { - center: { x: 0, y: 0 }, - scale: 1 / 1., - count: mvtLayer.length, - geom: points, - properties: {} - }; - Object.keys(fieldMap).map((name, pid) => { - tile.properties[name] = properties[pid]; - }) - oldtile = layer.addTile(tile); - styleWidth(); - styleColor(); - } - }; - - oReq.send(null); -} -function start(element) { - renderer = new __WEBPACK_IMPORTED_MODULE_0__src_index__["a" /* Renderer */](element); - layer = renderer.addLayer(); - - getData(); - $('#widthStyleEntry').on('input', styleWidth); - $('#colorStyleEntry').on('input', styleColor); - //$('#sqlEntry').on('input', getData); - - //window.onresize = function () { renderer.refresh(); }; -} -const DEG2RAD = Math.PI / 180; -const EARTH_RADIUS = 6378137; -const WM_EXT = EARTH_RADIUS * Math.PI * 2; -const TILE_SIZE = 256; -// Webmercator projection -function Wmxy(latLng) { - let lat = latLng.lat() * DEG2RAD; - let lng = latLng.lng() * DEG2RAD; - let x = lng * EARTH_RADIUS; - let y = Math.log(Math.tan(lat / 2 + Math.PI / 4)) * EARTH_RADIUS; - return { x: x, y: y }; -} - -function initMap() { - // Create a map object and specify the DOM element for display. - var map = new google.maps.Map(document.getElementById('map'), { - center: { lat: -34.397, lng: 150.644 }, - zoom: 8 - }); - - var cont = map.getDiv(); - var canvas = document.createElement('canvas') - canvas.id = 'good'; - cont.appendChild(canvas) - canvas.style.width = '100%'; - canvas.style.height = '100%'; - console.log(cont, cont.style.width, cont.getClientRects()[0].width, canvas.style.width); - function getZoom() { - var b = map.getBounds(); - var c = map.getCenter(); - var nw = b.getNorthEast(); - var sw = b.getSouthWest(); - var z = (Wmxy(nw).y - Wmxy(sw).y) / 40075019.834677525; - renderer.setCenter(c.lng() / 180., Wmxy(c).y / 40075019.834677525 * 2.); - return z; - } - function move(a, b, c) { - var b = map.getBounds(); - var nw = b.getNorthEast(); - var c = map.getCenter(); - - renderer.setCenter(c.lng / 180., Wmxy(c).y / 40075019.834677525 * 2.); - renderer.setZoom(getZoom()); - // console.log(renderer.getCenter(), renderer.getZoom(), c) - } - start(canvas); - // move(); - window.map = map; - -var attatched = false; - /* map.addListener('drag', function () { - // debugger; - if (!attatched) { - var target = cont.querySelector('div.gm-style div div'); - - // create an observer instance - var observer = new MutationObserver(function (mutations) { - //move(); - }); - - // configuration of the observer: - var config = { attributes: true, childList: true, characterData: true }; - - // pass in the target node, as well as the observer options - observer.observe(target, config); - } - }); - - map.addListener('dragend', move); - map.addListener('dragstart', move); - map.addListener('drag', move);*/ - /*cont.addEventListener('mousemove', move); - cont.addEventListener('mousestart', move); - cont.addEventListener('mouseleave', move); - cont.addEventListener('mouseover', move); - cont.addEventListener('mousemove', move);*/ -} -window.initMap = initMap; -/* -map.on('load', _ => { - var cont = map.getCanvasContainer(); - var canvas = document.createElement('canvas') - canvas.id = 'good'; - cont.appendChild(canvas) - canvas.style.width = map.getCanvas().style.width; - canvas.style.height = map.getCanvas().style.height; - - function move(a, b, c) { - var b = map.getBounds(); - var nw = b.getNorthWest(); - var c = map.getCenter(); - - renderer.setCenter(c.lng / 180., Wmxy(c).y / 40075019.834677525 * 2.); - renderer.setZoom(getZoom()); - } - start(canvas); - move(); - map.on('movestart', move); - map.on('move', move); - map.on('moveend', move); - map.on('dragstart', move); - map.on('drag', move); - map.on('dragstart', move); - map.on('dragend', move); - map.on('zoomstart', move); - map.on('zoom', move); - map.on('zoomend', move); - -}); -*/ - -/***/ }), -/* 11 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Property", function() { return Property; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Blend", function() { return Blend; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Now", function() { return Now; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Near", function() { return Near; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Color", function() { return Color; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Float", function() { return Float; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RampColor", function() { return RampColor; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FloatMul", function() { return FloatMul; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FloatDiv", function() { return FloatDiv; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FloatAdd", function() { return FloatAdd; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FloatSub", function() { return FloatSub; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FloatPow", function() { return FloatPow; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "setGL", function() { return setGL; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "schemes", function() { return schemes; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_cartocolor__ = __webpack_require__(21); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_cartocolor___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_cartocolor__); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__scheme__ = __webpack_require__(25); - - - -function implicitCast(value) { - if (Number.isFinite(value)) { - return Float(value); - } - return value; -} -var gl = null; -function setGL(_gl) { - gl = _gl; -} - - -const schemes = {}; -Object.keys(__WEBPACK_IMPORTED_MODULE_0_cartocolor__).map(name => { - const s = __WEBPACK_IMPORTED_MODULE_0_cartocolor__[name]; - var defaultFound = false; - for (let i = 20; i >= 0; i--) { - if (s[i]) { - if (!defaultFound) { - schemes[name.toLowerCase()] = () => s[i]; - defaultFound = true; - } - schemes[`${name.toLowerCase()}_${i}`] = () => s[i]; - } - } -}); - - -/* - Each styling function should: - - Create their own objects, i.e.: be used without "new" - - Check input validity on user input (constructor and exposed functions). - - Have certain functions that never fail: - - _applyToShaderSource should use uniformIDMaker and propertyTIDMaker to get unique uniform IDs and property IDs as needed - - _postShaderCompile should get uniform location after program compilation as needed - - _preDraw should set any program's uniforms as needed - - isAnimated should return true if the function output could change depending on the timestamp - - Have a type property declaring the GLSL output type: 'float', 'color' -*/ - -/* - TODO - - Integrated color palettes - - Type checking for color palettes - - Allow multiplication, division and pow() to color expressions and color literals - - Add SetOpacity(colorExpr, opacityFloatOverride) - - HSV - - Think about uniform-only types / parameters - - Think about "Date" and "string" types. - - Heatmaps (renderer should be improved too to accommodate this) -*/ - -function Property(name, scheme) { - return new _Property(name, scheme); -} -function _Property(name, scheme) { - if (typeof name !== 'string' || name == '') { - throw new Error(`Invalid property name '${name}'`); - } - if (!scheme[name]) { - throw new Error(`Property name not found`); - } - this.name = name; - this.type = 'float'; - this.scheme = scheme; -} -_Property.prototype._applyToShaderSource = function (uniformIDMaker, propertyTIDMaker) { - return { - preface: '', - inline: `p${propertyTIDMaker(this.name)}` - }; -} -_Property.prototype._postShaderCompile = function (program) { -} -_Property.prototype._preDraw = function () { -} -_Property.prototype.isAnimated = function () { - return false; -} - -function Now(speed) { - return new _Now(speed); -} -function _Now(speed) { - if (speed == undefined) { - speed = 1; - } - if (!Number.isFinite(Number(speed))) { - throw new Error('Now() only accepts number literals'); - } - this.speed = Number(speed); - this.type = 'float'; - this.float = Float(0); -} -_Now.prototype._applyToShaderSource = function (uniformIDMaker) { - return this.float._applyToShaderSource(uniformIDMaker); -} -_Now.prototype._postShaderCompile = function (program) { - return this.float._postShaderCompile(program); -} -_Now.prototype._preDraw = function () { - this.float.expr = (Date.now() * this.speed / 1000.) % 1; - this.float._preDraw(); -} -_Now.prototype.isAnimated = function () { - return true; -} - -const FloatMul = genFloatBinaryOperation((x, y) => x * y, (x, y) => `(${x} * ${y})`); -const FloatDiv = genFloatBinaryOperation((x, y) => x / y, (x, y) => `(${x} / ${y})`); -const FloatAdd = genFloatBinaryOperation((x, y) => x + y, (x, y) => `(${x} + ${y})`); -const FloatSub = genFloatBinaryOperation((x, y) => x - y, (x, y) => `(${x} - ${y})`); -const FloatPow = genFloatBinaryOperation((x, y) => Math.pow(x, y), (x, y) => `pow(${x}, ${y})`); - -function genFloatBinaryOperation(jsFn, glsl) { - function BinaryOp(a, b) { - if (Number.isFinite(a) && Number.isFinite(b)) { - return Float(jsFn(a, b)); - } - if (Number.isFinite(a)) { - a = Float(a); - } - if (Number.isFinite(b)) { - b = Float(b); - } - if (a.type == 'float' && b.type == 'float') { - this.type = 'float'; - } else { - console.warn(a, b); - throw new Error(`Binary operation cannot be performed between '${a}' and '${b}'`); - } - return new _BinaryOp(a, b); - } - function _BinaryOp(a, b) { - this.type = 'float'; - this.a = a; - this.b = b; - a.parent = this; - b.parent = this; - } - _BinaryOp.prototype._applyToShaderSource = function (uniformIDMaker, propertyTIDMaker) { - const a = this.a._applyToShaderSource(uniformIDMaker, propertyTIDMaker); - const b = this.b._applyToShaderSource(uniformIDMaker, propertyTIDMaker); - return { - preface: a.preface + b.preface, - inline: glsl(a.inline, b.inline) - }; - } - _BinaryOp.prototype._postShaderCompile = function (program) { - this.a._postShaderCompile(program); - this.b._postShaderCompile(program); - } - _BinaryOp.prototype._preDraw = function (l) { - this.a._preDraw(l); - this.b._preDraw(l); - } - _BinaryOp.prototype.isAnimated = function () { - return this.a.isAnimated() || this.b.isAnimated(); - } - _BinaryOp.prototype.replaceChild = function (toReplace, replacer) { - if (this.a = toReplace) { - this.a = replacer; - } else { - this.b = replacer; - } - replacer.parent = this; - replacer.notify = toReplace.notify; - } - _BinaryOp.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { - genericBlend(this, finalValue, duration, blendFunc); - } - return BinaryOp; -} - -function Animation(duration) { - return new _Animation(duration); -} -function _Animation(duration) { - if (!Number.isFinite(duration)) { - throw new Error("Animation only supports number literals"); - } - this.type = 'float'; - this.aTime = Date.now(); - this.bTime = this.aTime + Number(duration); -} -_Animation.prototype._applyToShaderSource = function (uniformIDMaker, propertyTIDMaker) { - this._uniformID = uniformIDMaker(); - return { - preface: `uniform float anim${this._uniformID};\n`, - inline: `anim${this._uniformID}` - }; -} -_Animation.prototype._postShaderCompile = function (program) { - this._uniformLocation = gl.getUniformLocation(program, `anim${this._uniformID}`); -} -_Animation.prototype._preDraw = function (l) { - const time = Date.now(); - this.mix = (time - this.aTime) / (this.bTime - this.aTime); - if (this.mix > 1.) { - gl.uniform1f(this._uniformLocation, 1); - } else { - gl.uniform1f(this._uniformLocation, this.mix); - } -} -_Animation.prototype.isAnimated = function () { - return !this.mix || this.mix <= 1.; -} - -function Near(property, center, threshold, falloff) { - const args = [property, center, threshold, falloff].map(implicitCast); - if (args.some(x => x === undefined || x === null)) { - throw new Error(`Invalid arguments to Near(): ${args}`); - } - return new _Near(...args); -} - -function _Near(input, center, threshold, falloff) { - if (input.type != 'float' || center.type != 'float' || threshold.type != 'float' || falloff.type != 'float') { - throw new Error('Near(): invalid parameter type'); - } - this.type = 'float'; - this.input = input; - this.center = center; - this.threshold = threshold; - this.falloff = falloff; -} -_Near.prototype._applyToShaderSource = function (uniformIDMaker, propertyTIDMaker) { - this._UID = uniformIDMaker(); - const tid = propertyTIDMaker(this.property); - const input = this.input._applyToShaderSource(uniformIDMaker, propertyTIDMaker); - const center = this.center._applyToShaderSource(uniformIDMaker, propertyTIDMaker); - const threshold = this.threshold._applyToShaderSource(uniformIDMaker, propertyTIDMaker); - const falloff = this.falloff._applyToShaderSource(uniformIDMaker, propertyTIDMaker); - return { - preface: - input.preface + center.preface + threshold.preface + falloff.preface, - inline: `1.-clamp((abs(${input.inline}-${center.inline})-${threshold.inline})/${falloff.inline}, - 0., 1.)` - }; -} -_Near.prototype._postShaderCompile = function (program) { - this.center._postShaderCompile(program); - this.threshold._postShaderCompile(program); - this.falloff._postShaderCompile(program); - this.input._postShaderCompile(program); -} -_Near.prototype._preDraw = function () { - this.center._preDraw(); - this.threshold._preDraw(); - this.falloff._preDraw(); - this.input._preDraw(); -} -_Near.prototype.isAnimated = function () { - return this.center.isAnimated(); -} - - - -function Blend(a, b, mix) { - const args = [a, b, mix].map(implicitCast); - if (args.some(x => x === undefined || x === null)) { - throw new Error(`Invalid arguments to Blend(): ${args}`); - } - return new _Blend(...args); -} -function _Blend(a, b, mix) { - if (a.type == 'float' && b.type == 'float') { - this.type = 'float'; - } else if (a.type == 'color' && b.type == 'color') { - this.type = 'color'; - } else { - console.warn(a, b); - throw new Error(`Blending cannot be performed between types '${a.type}' and '${b.type}'`); - } - if (__WEBPACK_IMPORTED_MODULE_1__scheme__["b" /* checkSchemeMatch */](a.scheme, b.scheme)) { - throw new Error('Blend parameters schemes mismatch'); - } - this.scheme = a.scheme; - this.a = a; - this.b = b; - this.mix = mix; - a.parent = this; - b.parent = this; - mix.parent = this; -} -_Blend.prototype._applyToShaderSource = function (uniformIDMaker, propertyTIDMaker) { - const a = this.a._applyToShaderSource(uniformIDMaker, propertyTIDMaker); - const b = this.b._applyToShaderSource(uniformIDMaker, propertyTIDMaker); - const mix = this.mix._applyToShaderSource(uniformIDMaker, propertyTIDMaker); - return { - preface: `${a.preface}${b.preface}${mix.preface}`, - inline: `mix(${a.inline}, ${b.inline}, ${mix.inline})` - }; -} -_Blend.prototype._postShaderCompile = function (program) { - this.a._postShaderCompile(program); - this.b._postShaderCompile(program); - this.mix._postShaderCompile(program); -} -_Blend.prototype._preDraw = function (l) { - this.a._preDraw(l); - this.b._preDraw(l); - this.mix._preDraw(l); - if (this.mix instanceof _Animation && !this.mix.isAnimated()) { - this.parent.replaceChild(this, this.b); - } -} -_Blend.prototype.isAnimated = function () { - return this.a.isAnimated() || this.b.isAnimated() || this.mix.isAnimated(); -} -_Blend.prototype.replaceChild = function (toReplace, replacer) { - if (this.a = toReplace) { - this.a = replacer; - } else { - this.b = replacer; - } - replacer.parent = this; - replacer.notify = toReplace.notify; -} - -function genericBlend(initial, final, duration, blendFunc) { - const parent = initial.parent; - const blend = Blend(initial, final, Animation(duration)); - parent.replaceChild(initial, blend); - blend.notify(); -} -UniformColor.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { - genericBlend(this, finalValue, duration, blendFunc); -} -_RampColor.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { - genericBlend(this, finalValue, duration, blendFunc); -} - -_Near.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { - genericBlend(this, finalValue, duration, blendFunc); -} -UniformFloat.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { - genericBlend(this, finalValue, duration, blendFunc); -} -_Blend.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { - genericBlend(this, finalValue, duration, blendFunc); -} -_Property.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { - genericBlend(this, finalValue, duration, blendFunc); -} - - -function Color(color) { - if (Array.isArray(color)) { - color = color.filter(x => true); - if (color.length != 4 || !color.every(Number.isFinite)) { - throw new Error(`Invalid arguments to Color(): ${args}`); - } - return new UniformColor(color); - } - throw new Error(`Invalid arguments to Color(): ${args}`); -} -function UniformColor(color) { - this.type = 'color'; - this.color = color; -} -UniformColor.prototype._applyToShaderSource = function (uniformIDMaker) { - this._uniformID = uniformIDMaker(); - return { - preface: `uniform vec4 color${this._uniformID};\n`, - inline: `color${this._uniformID}` - }; -} -UniformColor.prototype._postShaderCompile = function (program) { - this._uniformLocation = gl.getUniformLocation(program, `color${this._uniformID}`); -} -function evalColor(color, time) { - if (Array.isArray(color)) { - return color; - } - var a = evalColor(color.a, time); - var b = evalColor(color.b, time); - var m = (time - color.aTime) / (color.bTime - color.aTime); - return a.map((va, index) => { - return (1 - m) * va + m * b[index];//TODO non linear functions - }); -} -function simplifyColorExpr(color, time) { - if (Array.isArray(color)) { - return color; - } - var m = (time - color.aTime) / (color.bTime - color.aTime); - if (m >= 1) { - return color.b; - } - return color; -} -UniformColor.prototype._preDraw = function () { - const t = Date.now(); - this.color = simplifyColorExpr(this.color, t); - const color = evalColor(this.color, t); - gl.uniform4f(this._uniformLocation, color[0], color[1], color[2], color[3]); -} -UniformColor.prototype.isAnimated = function () { - return false; -} - -function Float(x) { - if (!Number.isFinite(x)) { - throw new Error(`Invalid arguments to Float(): ${args}`); - } - return new UniformFloat(x); -} - -function UniformFloat(size) { - this.type = 'float'; - this.expr = size; -} -UniformFloat.prototype._applyToShaderSource = function (uniformIDMaker) { - this._uniformID = uniformIDMaker(); - return { - preface: `uniform float float${this._uniformID};\n`, - inline: `float${this._uniformID}` - }; -} -UniformFloat.prototype._postShaderCompile = function (program) { - this._uniformLocation = gl.getUniformLocation(program, `float${this._uniformID}`); -} -function evalFloatExpr(expr, time) { - if (Number.isFinite(expr)) { - return expr; - } - if (typeof expr === "function") { - return x(time); - } - return expr.eval(); -} -function simplifyFloatExpr(expr, time) { - if (Number.isFinite(expr)) { - return expr; - } - return expr.simplify(); -} -UniformFloat.prototype._preDraw = function (time) { - this.expr = simplifyFloatExpr(this.expr, time); - const v = evalFloatExpr(this.expr, time); - gl.uniform1f(this._uniformLocation, v); -} -UniformFloat.prototype.isAnimated = function () { - return !Number.isFinite(this.expr); -} - -function hexToRgb(hex) { - var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); - return result ? { - r: parseInt(result[1], 16), - g: parseInt(result[2], 16), - b: parseInt(result[3], 16) - } : null; -} - - -function RampColor(input, minKey, maxKey, values) { - //TODO contiunuos vs discrete should be decided based on input type => cartegory vs float - const args = [input, minKey, maxKey, values].map(implicitCast); - if (args.some(x => x === undefined || x === null)) { - throw new Error(`Invalid arguments to RampColor(): ${args}`); - } - return new _RampColor(...args); -} - -//Palette => used by Ramp, Ramp gets texture2D from palette by asking for number of buckets (0/interpolated palette, 2,3,4,5,6...) -function _RampColor(input, minKey, maxKey, values) { - this.type = 'color'; - this.input = input; - this.minKey = minKey.expr; - this.maxKey = maxKey.expr; - this.values = values; - - this.texture = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, this.texture); - const level = 0; - const internalFormat = gl.RGBA; - const width = 256; - const height = 1; - const border = 0; - const srcFormat = gl.RGBA; - const srcType = gl.UNSIGNED_BYTE; - const pixel = new Uint8Array(4 * width); - for (var i = 0; i < width; i++) { - const vlowRaw = values[Math.floor(i / width * (values.length - 1))]; - const vhighRaw = values[Math.ceil(i / width * (values.length - 1))]; - const vlow = [hexToRgb(vlowRaw).r, hexToRgb(vlowRaw).g, hexToRgb(vlowRaw).b, 255]; - const vhigh = [hexToRgb(vhighRaw).r, hexToRgb(vhighRaw).g, hexToRgb(vhighRaw).b, 255]; - const m = i / width * (values.length - 1) - Math.floor(i / width * (values.length - 1)); - const v = vlow.map((low, index) => low * (1. - m) + vhigh[index] * m); - pixel[4 * i + 0] = v[0]; - pixel[4 * i + 1] = v[1]; - pixel[4 * i + 2] = v[2]; - pixel[4 * i + 3] = v[3]; - } - - - gl.texImage2D(gl.TEXTURE_2D, level, internalFormat, - width, height, border, srcFormat, srcType, - pixel); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); -} - -_RampColor.prototype._free = function () { - gl.deleteTexture(this.texture); -} -_RampColor.prototype._applyToShaderSource = function (uniformIDMaker, propertyTIDMaker) { - this._UID = uniformIDMaker(); - const input = this.input._applyToShaderSource(uniformIDMaker, propertyTIDMaker); - return { - preface: input.preface + ` - uniform sampler2D texRamp${this._UID}; - uniform float keyMin${this._UID}; - uniform float keyWidth${this._UID}; - `, - inline: `texture2D(texRamp${this._UID}, vec2((${input.inline}-keyMin${this._UID})/keyWidth${this._UID}, 0.5)).rgba` - }; -} -_RampColor.prototype._postShaderCompile = function (program) { - this.input._postShaderCompile(program); - this._texLoc = gl.getUniformLocation(program, `texRamp${this._UID}`); - this._keyMinLoc = gl.getUniformLocation(program, `keyMin${this._UID}`); - this._keyWidthLoc = gl.getUniformLocation(program, `keyWidth${this._UID}`); -} -_RampColor.prototype._preDraw = function (l) { - this.input._preDraw(l); - gl.activeTexture(gl.TEXTURE0 + l.freeTexUnit);//TODO remove hardcode - gl.bindTexture(gl.TEXTURE_2D, this.texture); - gl.uniform1i(this._texLoc, l.freeTexUnit); - gl.uniform1f(this._keyMinLoc, evalFloatExpr(this.minKey)); - gl.uniform1f(this._keyWidthLoc, evalFloatExpr(this.maxKey) - evalFloatExpr(this.minKey)); - l.freeTexUnit++; -} -_RampColor.prototype.isAnimated = function () { - return false; -} - - -/***/ }), -/* 12 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return renderer; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return styler; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__renderer__ = __webpack_require__(15); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__styler__ = __webpack_require__(17); - - - -const NUM_TEXTURE_LOCATIONS = 4; - -function compileShader(gl, sourceCode, type) { - const shader = gl.createShader(type); - gl.shaderSource(shader, sourceCode); - gl.compileShader(shader); - if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { - const log = gl.getShaderInfoLog(shader); - gl.deleteShader(shader); - throw new Error('An error occurred compiling the shaders: ' + log + '\nSource:\n' + sourceCode); - } - return shader; -} - -function compileProgram(gl, glslVS, glslFS) { - const VS = compileShader(gl, glslVS, gl.VERTEX_SHADER); - const FS = compileShader(gl, glslFS, gl.FRAGMENT_SHADER); - this.program = gl.createProgram(); - gl.attachShader(this.program, VS); - gl.attachShader(this.program, FS); - gl.linkProgram(this.program); - gl.deleteShader(VS); - gl.deleteShader(FS); - if (!gl.getProgramParameter(this.program, gl.LINK_STATUS)) { - throw new Error('Unable to link the shader program: ' + gl.getProgramInfoLog(this.program)); - } -} - -function Point(gl) { - compileProgram.call(this, gl, __WEBPACK_IMPORTED_MODULE_0__renderer__["a" /* point */].VS, __WEBPACK_IMPORTED_MODULE_0__renderer__["a" /* point */].FS); - this.vertexPositionAttribute = gl.getAttribLocation(this.program, 'vertexPosition'); - this.featureIdAttr = gl.getAttribLocation(this.program, 'featureID'); - this.vertexScaleUniformLocation = gl.getUniformLocation(this.program, 'vertexScale'); - this.vertexOffsetUniformLocation = gl.getUniformLocation(this.program, 'vertexOffset'); - this.colorTexture = gl.getUniformLocation(this.program, 'colorTex'); - this.widthTexture = gl.getUniformLocation(this.program, 'widthTex'); -} -function GenericStyler(gl, glsl, preface, inline) { - const VS = glsl.VS; - let FS = glsl.FS; - FS = FS.replace('$PREFACE', preface); - FS = FS.replace('$INLINE', inline); - console.log(FS) - compileProgram.call(this, gl, VS, FS); - this.vertexAttribute = gl.getAttribLocation(this.program, 'vertex'); - this.textureLocations = []; - for (let i = 0; i < NUM_TEXTURE_LOCATIONS; i++) { - this.textureLocations[i] = gl.getUniformLocation(this.program, `property${i}`); - } -} -function Color(gl, preface, inline) { - GenericStyler.call(this, gl, __WEBPACK_IMPORTED_MODULE_1__styler__["a" /* color */], preface, inline); -} -function Width(gl, preface, inline) { - GenericStyler.call(this, gl, __WEBPACK_IMPORTED_MODULE_1__styler__["b" /* width */], preface, inline); -} - -const renderer = { - createPointShader: function (gl) { - return new Point(gl); - } -}; - -const styler = { - createColorShader: function (gl, preface, inline) { - return new Color(gl, preface, inline); - }, - createWidthShader: function (gl, preface, inline) { - return new Width(gl, preface, inline); - } -}; - - - - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { +/***/ }), +/* 2 */ +/***/ (function(module, exports, __webpack_require__) { // JavaScript Expression Parser (JSEP) 0.3.2 // JSEP may be freely distributed under the MIT License @@ -3315,100 +1403,806 @@ const styler = { }(this)); -/***/ }), -/* 14 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +/***/ }), +/* 3 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (immutable) */ __webpack_exports__["a"] = parseStyleExpression; +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_jsep__ = __webpack_require__(2); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_jsep___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_jsep__); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__functions__ = __webpack_require__(0); + + + + +//TODO document style expressions +//TODO create complete style API, a way to define a color and a width style at the same time, we just have style expressions now +/* + Returns a valid style expression or throws an exception upon invalid inputs. +*/ +var lowerCaseFunctions = {}; +Object.keys(__WEBPACK_IMPORTED_MODULE_1__functions__).map(name => { + lowerCaseFunctions[name.toLocaleLowerCase()] = __WEBPACK_IMPORTED_MODULE_1__functions__[name]; +}); + +/** + * @api + * @param {*} str + * @param {*} schema + */ +function parseStyleExpression(str, schema) { + // jsep addBinaryOp pollutes its module scope, we need to remove the custom operators afterwards + __WEBPACK_IMPORTED_MODULE_0_jsep___default.a.addBinaryOp("^", 10); + const r = parseNode(__WEBPACK_IMPORTED_MODULE_0_jsep___default()(str), schema); + __WEBPACK_IMPORTED_MODULE_0_jsep___default.a.removeBinaryOp("^"); + return r; +} + +function parseNode(node, schema) { + if (node.type == 'CallExpression') { + const args = node.arguments.map(arg => parseNode(arg, schema)); + const name = node.callee.name.toLowerCase(); + if (lowerCaseFunctions[name]) { + return lowerCaseFunctions[name](...args, schema); + } + throw new Error(`Invalid function name '${node.callee.name}'`); + } else if (node.type == 'Literal') { + return node.value; + } else if (node.type == 'ArrayExpression') { + return node.elements.map(e => parseNode(e, schema)); + } else if (node.type == 'BinaryExpression') { + const left = parseNode(node.left, schema); + const right = parseNode(node.right, schema); + switch (node.operator) { + case "*": + return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatMul"](left, right, schema); + case "/": + return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatDiv"](left, right, schema); + case "+": + return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatAdd"](left, right, schema); + case "-": + return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatSub"](left, right, schema); + case "^": + return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatPow"](left, right, schema); + default: + throw new Error(`Invalid binary operator '${node.operator}'`); + } + } else if (node.type == 'UnaryExpression') { + switch (node.operator) { + case '-': + return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatMul"](-1, parseNode(node.argument, schema)); + case '+': + return parseNode(node.argument, schema); + default: + throw new Error(`Invalid unary operator '${node.operator}'`); + } + } else if (node.type == 'Identifier') { + if (node.name[0] == '$') { + return __WEBPACK_IMPORTED_MODULE_1__functions__["Property"](node.name.substring(1), schema); + } else if (__WEBPACK_IMPORTED_MODULE_1__functions__["schemas"][node.name.toLowerCase()]) { + return __WEBPACK_IMPORTED_MODULE_1__functions__["schemas"][node.name.toLowerCase()](); + } + } + throw new Error(`Invalid expression '${JSON.stringify(node)}'`); +} + + + + +/***/ }), +/* 4 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var VectorTileFeature = __webpack_require__(5); + +module.exports = VectorTileLayer; + +function VectorTileLayer(pbf, end) { + // Public + this.version = 1; + this.name = null; + this.extent = 4096; + this.length = 0; + + // Private + this._pbf = pbf; + this._keys = []; + this._values = []; + this._features = []; + + pbf.readFields(readLayer, this, end); + + this.length = this._features.length; +} + +function readLayer(tag, layer, pbf) { + if (tag === 15) layer.version = pbf.readVarint(); + else if (tag === 1) layer.name = pbf.readString(); + else if (tag === 5) layer.extent = pbf.readVarint(); + else if (tag === 2) layer._features.push(pbf.pos); + else if (tag === 3) layer._keys.push(pbf.readString()); + else if (tag === 4) layer._values.push(readValueMessage(pbf)); +} + +function readValueMessage(pbf) { + var value = null, + end = pbf.readVarint() + pbf.pos; + + while (pbf.pos < end) { + var tag = pbf.readVarint() >> 3; + + value = tag === 1 ? pbf.readString() : + tag === 2 ? pbf.readFloat() : + tag === 3 ? pbf.readDouble() : + tag === 4 ? pbf.readVarint64() : + tag === 5 ? pbf.readVarint() : + tag === 6 ? pbf.readSVarint() : + tag === 7 ? pbf.readBoolean() : null; + } + + return value; +} + +// return feature `i` from this layer as a `VectorTileFeature` +VectorTileLayer.prototype.feature = function(i) { + if (i < 0 || i >= this._features.length) throw new Error('feature index out of bounds'); + + this._pbf.pos = this._features[i]; + + var end = this._pbf.readVarint() + this._pbf.pos; + return new VectorTileFeature(this._pbf, end, this.extent, this._keys, this._values); +}; + + +/***/ }), +/* 5 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var Point = __webpack_require__(20); + +module.exports = VectorTileFeature; + +function VectorTileFeature(pbf, end, extent, keys, values) { + // Public + this.properties = {}; + this.extent = extent; + this.type = 0; + + // Private + this._pbf = pbf; + this._geometry = -1; + this._keys = keys; + this._values = values; + + pbf.readFields(readFeature, this, end); +} + +function readFeature(tag, feature, pbf) { + if (tag == 1) feature.id = pbf.readVarint(); + else if (tag == 2) readTag(pbf, feature); + else if (tag == 3) feature.type = pbf.readVarint(); + else if (tag == 4) feature._geometry = pbf.pos; +} + +function readTag(pbf, feature) { + var end = pbf.readVarint() + pbf.pos; + + while (pbf.pos < end) { + var key = feature._keys[pbf.readVarint()], + value = feature._values[pbf.readVarint()]; + feature.properties[key] = value; + } +} + +VectorTileFeature.types = ['Unknown', 'Point', 'LineString', 'Polygon']; + +VectorTileFeature.prototype.loadGeometry = function() { + var pbf = this._pbf; + pbf.pos = this._geometry; + + var end = pbf.readVarint() + pbf.pos, + cmd = 1, + length = 0, + x = 0, + y = 0, + lines = [], + line; + + while (pbf.pos < end) { + if (!length) { + var cmdLen = pbf.readVarint(); + cmd = cmdLen & 0x7; + length = cmdLen >> 3; + } + + length--; + + if (cmd === 1 || cmd === 2) { + x += pbf.readSVarint(); + y += pbf.readSVarint(); + + if (cmd === 1) { // moveTo + if (line) lines.push(line); + line = []; + } + + line.push(new Point(x, y)); + + } else if (cmd === 7) { + + // Workaround for https://github.com/mapbox/mapnik-vector-tile/issues/90 + if (line) { + line.push(line[0].clone()); // closePolygon + } + + } else { + throw new Error('unknown command ' + cmd); + } + } + + if (line) lines.push(line); + + return lines; +}; + +VectorTileFeature.prototype.bbox = function() { + var pbf = this._pbf; + pbf.pos = this._geometry; + + var end = pbf.readVarint() + pbf.pos, + cmd = 1, + length = 0, + x = 0, + y = 0, + x1 = Infinity, + x2 = -Infinity, + y1 = Infinity, + y2 = -Infinity; + + while (pbf.pos < end) { + if (!length) { + var cmdLen = pbf.readVarint(); + cmd = cmdLen & 0x7; + length = cmdLen >> 3; + } + + length--; + + if (cmd === 1 || cmd === 2) { + x += pbf.readSVarint(); + y += pbf.readSVarint(); + if (x < x1) x1 = x; + if (x > x2) x2 = x; + if (y < y1) y1 = y; + if (y > y2) y2 = y; + + } else if (cmd !== 7) { + throw new Error('unknown command ' + cmd); + } + } + + return [x1, y1, x2, y2]; +}; + +VectorTileFeature.prototype.toGeoJSON = function(x, y, z) { + var size = this.extent * Math.pow(2, z), + x0 = this.extent * x, + y0 = this.extent * y, + coords = this.loadGeometry(), + type = VectorTileFeature.types[this.type], + i, j; + + function project(line) { + for (var j = 0; j < line.length; j++) { + var p = line[j], y2 = 180 - (p.y + y0) * 360 / size; + line[j] = [ + (p.x + x0) * 360 / size - 180, + 360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90 + ]; + } + } + + switch (this.type) { + case 1: + var points = []; + for (i = 0; i < coords.length; i++) { + points[i] = coords[i][0]; + } + coords = points; + project(coords); + break; + + case 2: + for (i = 0; i < coords.length; i++) { + project(coords[i]); + } + break; + + case 3: + coords = classifyRings(coords); + for (i = 0; i < coords.length; i++) { + for (j = 0; j < coords[i].length; j++) { + project(coords[i][j]); + } + } + break; + } + + if (coords.length === 1) { + coords = coords[0]; + } else { + type = 'Multi' + type; + } + + var result = { + type: "Feature", + geometry: { + type: type, + coordinates: coords + }, + properties: this.properties + }; + + if ('id' in this) { + result.id = this.id; + } + + return result; +}; + +// classifies an array of rings into polygons with outer rings and holes + +function classifyRings(rings) { + var len = rings.length; + + if (len <= 1) return [rings]; + + var polygons = [], + polygon, + ccw; + + for (var i = 0; i < len; i++) { + var area = signedArea(rings[i]); + if (area === 0) continue; + + if (ccw === undefined) ccw = area < 0; + + if (ccw === area < 0) { + if (polygon) polygons.push(polygon); + polygon = [rings[i]]; + + } else { + polygon.push(rings[i]); + } + } + if (polygon) polygons.push(polygon); + + return polygons; +} + +function signedArea(ring) { + var sum = 0; + for (var i = 0, len = ring.length, j = len - 1, p1, p2; i < len; j = i++) { + p1 = ring[i]; + p2 = ring[j]; + sum += (p2.x - p1.x) * (p1.y + p2.y); + } + return sum; +} + + +/***/ }), +/* 6 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Renderer; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__shaders__ = __webpack_require__(1); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__style__ = __webpack_require__(12); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__schema__ = __webpack_require__(17); +/* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "c", function() { return __WEBPACK_IMPORTED_MODULE_1__style__; }); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return __WEBPACK_IMPORTED_MODULE_2__schema__["a"]; }); + + + + + + + +/** + * @api + * @typedef {object} RPoint - Point in renderer coordinates space + * @property {number} x + * @property {number} y + */ + + /** + * @api + * @typedef {object} Dataframe - Point in renderer coordinates space + * @property {RPoint} center + * @property {number} scale + * @property {geom} geometry + * @property {Properties} properties + */ + + +// TODO remove +var gl; + +/** + * @description The Render To Texture Width limits the maximum number of features per tile: *maxFeatureCount = RTT_WIDTH^2* + * + * Large RTT_WIDTH values are unsupported by hardware. Limits vary on each machine. + * Support starts to drop from 2048, with a drastic reduction in support for more than 4096 pixels. + * + * Large values imply a small overhead too. + */ +const RTT_WIDTH = 1024; + + +/** + * @description Renderer constructor. Use it to create a new renderer bound to the provided canvas. + * Initialization will be done synchronously. + * The function will fail in case that a WebGL context cannot be created this can happen because of the following reasons: + * * The provided canvas element is invalid + * * The browser or the machine doesn't support WebGL or the required WebGL extension and minimum parameter values + * @api + * @memberOf renderer + * @constructor + * @param {HTMLElement} canvas - the WebGL context will be created on this element + */ +function Renderer(canvas) { + this.canvas = canvas; + this.tiles = []; + if (!gl) { //TODO remove hack: remove global context + gl = canvas.getContext('webgl'); + if (!gl) { + throw new Error("WebGL extension OES_texture_float is unsupported"); + } + var ext = gl.getExtension("OES_texture_float"); + if (!ext) { + throw new Error("WebGL extension OES_texture_float is unsupported"); + } + const supportedRTT = gl.getParameter(gl.MAX_RENDERBUFFER_SIZE); + if (supportedRTT < RTT_WIDTH) { + throw new Error(`WebGL parameter 'gl.MAX_RENDERBUFFER_SIZE' is below the requirement: ${supportedRTT} < ${RTT_WIDTH}`); + } + __WEBPACK_IMPORTED_MODULE_1__style__["setGL"](gl); + this._initShaders(); + this._center = { x: 0, y: 0 }; + this._zoom = 1; + } + this.squareBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, this.squareBuffer); + var vertices = [ + 10.0, -10.0, + 0.0, 10.0, + -10.0, -10.0, + ]; + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); +} + +/** + * Get Renderer visualization center + * @api + * @return {RPoint} + */ +Renderer.prototype.getCenter = function () { + return { x: this._center.x, y: this._center.y }; +}; +/** + * Set Renderer visualization center + * @api + * @param {number} x + * @param {number} y + */ +Renderer.prototype.setCenter = function (x, y) { + this._center.x = x; + this._center.y = y; + window.requestAnimationFrame(refresh.bind(this)); +}; +/** + * Get Renderer visualization zoom + * @api + * @return {number} + */ +Renderer.prototype.getZoom = function () { + return this._zoom; +}; +/** + * Set Renderer visualization zoom + * @api + * @param {number} zoom + */ +Renderer.prototype.setZoom = function (zoom) { + this._zoom = zoom; + window.requestAnimationFrame(refresh.bind(this)); +}; + +/** + * Removes a dataframe for the renderer. Freeing its resources. + * @api + * @param {*} tile + */ +Renderer.prototype.removeDataframe = function (dataframe) { + this.tiles = this.tiles.filter(t => t !== dataframe); + dataframe.propertyTex.map(tex => gl.deleteTexture(tex)); + gl.deleteTexture(dataframe.texColor); + gl.deleteTexture(dataframe.texWidth); + gl.deleteBuffer(dataframe.vertexBuffer); + gl.deleteBuffer(dataframe.featureIDBuffer); +}; + +/** + * @api + * @description Adds a new dataframe to the renderer. + * + * Performance-intensive. The required allocation and copy of resources will happen synchronously. + * To achieve good performance, avoid multiple calls within the same event, particularly with large dataframes. + * @param {Dataframe} dataframe + */ +Renderer.prototype.addDataframe = function (tile) { + this.tiles.push(tile); + tile.propertyTex = []; + + var points = tile.geom; + const level = 0; + const width = RTT_WIDTH; + tile.numVertex = points.length / 2; + const height = Math.ceil(tile.numVertex / width); + const border = 0; + const srcFormat = gl.RED; + const srcType = gl.FLOAT; + tile.height = height; + tile.propertyID = {}; //Name => PID + tile.propertyCount = 0; + + + for (var k in tile.properties) { + if (tile.properties.hasOwnProperty(k) && tile.properties[k].length > 0) { + const isCategory = !Number.isFinite(tile.properties[k][0]); + const property = tile.properties[k]; + var propertyID = tile.propertyID[k]; + if (propertyID === undefined) { + propertyID = tile.propertyCount; + tile.propertyCount++; + tile.propertyID[k] = propertyID; + } + tile.propertyTex[propertyID] = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tile.propertyTex[propertyID]); + const pixel = new Float32Array(width * height); + for (var i = 0; i < property.length; i++) { + pixel[i] = property[i]; + } + gl.texImage2D(gl.TEXTURE_2D, level, gl.ALPHA, + width, height, 0, gl.ALPHA, srcType, + pixel); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + } + } + + tile.setStyle = function (style) { + __WEBPACK_IMPORTED_MODULE_2__schema__["b" /* checkschemaMatch */](style.schema, tile.schema); + this.style = style; + } + tile.style = null; + + tile.vertexBuffer = gl.createBuffer(); + tile.featureIDBuffer = gl.createBuffer(); + + + tile.texColor = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tile.texColor); + gl.texImage2D(gl.TEXTURE_2D, level, gl.RGBA, + width, height, border, gl.RGBA, gl.UNSIGNED_BYTE, + new Uint8Array(4 * width * height).fill(255)); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + + tile.texWidth = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tile.texWidth); + gl.texImage2D(gl.TEXTURE_2D, level, gl.RGBA, + width, height, border, gl.RGBA, gl.UNSIGNED_BYTE, + new Uint8Array(4 * width * height).fill(100)); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + + -"use strict"; -/* harmony export (immutable) */ __webpack_exports__["a"] = parseStyleExpression; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_jsep__ = __webpack_require__(13); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_jsep___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_jsep__); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__functions__ = __webpack_require__(11); + var ids = new Float32Array(points.length); + for (var i = 0; i < points.length; i += 2) { + ids[i + 0] = ((i / 2) % width) / width; + ids[i + 1] = Math.floor((i / 2) / width) / height; + } + gl.bindBuffer(gl.ARRAY_BUFFER, tile.vertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW); + gl.bindBuffer(gl.ARRAY_BUFFER, tile.featureIDBuffer); + gl.bufferData(gl.ARRAY_BUFFER, ids, gl.STATIC_DRAW); + gl.bindBuffer(gl.ARRAY_BUFFER, null); -//TODO document style expressions -//TODO create complete style API, a way to define a color and a width style at the same time, we just have style expressions now -/* - Returns a valid style expression or throws an exception upon invalid inputs. -*/ -var lowerCaseFunctions = {}; -Object.keys(__WEBPACK_IMPORTED_MODULE_1__functions__).map(name => { - lowerCaseFunctions[name.toLocaleLowerCase()] = __WEBPACK_IMPORTED_MODULE_1__functions__[name]; -}); + window.requestAnimationFrame(refresh.bind(this)); -function parseStyleExpression(str, scheme) { - // jsep addBinaryOp pollutes its module scope, we need to remove the custom operators afterwards - __WEBPACK_IMPORTED_MODULE_0_jsep___default.a.addBinaryOp("^", 10); - const r = parseNode(__WEBPACK_IMPORTED_MODULE_0_jsep___default()(str), scheme); - __WEBPACK_IMPORTED_MODULE_0_jsep___default.a.removeBinaryOp("^"); - return r; -} + return tile; +}; -function parseNode(node, scheme) { - if (node.type == 'CallExpression') { - const args = node.arguments.map(arg => parseNode(arg, scheme)); - const name = node.callee.name.toLowerCase(); - if (lowerCaseFunctions[name]) { - return lowerCaseFunctions[name](...args, scheme); - } - throw new Error(`Invalid function name '${node.callee.name}'`); - } else if (node.type == 'Literal') { - return node.value; - } else if (node.type == 'ArrayExpression') { - return node.elements.map(e => parseNode(e, scheme)); - } else if (node.type == 'BinaryExpression') { - const left = parseNode(node.left, scheme); - const right = parseNode(node.right, scheme); - switch (node.operator) { - case "*": - return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatMul"](left, right, scheme); - case "/": - return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatDiv"](left, right, scheme); - case "+": - return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatAdd"](left, right, scheme); - case "-": - return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatSub"](left, right, scheme); - case "^": - return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatPow"](left, right, scheme); - default: - throw new Error(`Invalid binary operator '${node.operator}'`); +/** + * Refresh the canvas by redrawing everything needed. + * Should only be called by requestAnimationFrame + * @param timestamp - timestamp of the animation provided by requestAnimationFrame + */ +Renderer.prototype.refresh = refresh; +function refresh(timestamp) { + // Don't re-render more than once per animation frame + if (this.lastFrame == timestamp) { + return; + } + this.lastFrame = timestamp; + var canvas = this.canvas; + var width = gl.canvas.clientWidth; + var height = gl.canvas.clientHeight; + if (gl.canvas.width != width || + gl.canvas.height != height) { + gl.canvas.width = width; + gl.canvas.height = height; + } + var aspect = canvas.clientWidth / canvas.clientHeight; + gl.clearColor(0., 0., 0., 0.);//TODO this should be a renderer property + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + + gl.enable(gl.CULL_FACE); + + //TODO refactor condition + gl.disable(gl.BLEND); + gl.disable(gl.DEPTH_TEST); + + if (!this.auxFB) { + this.auxFB = gl.createFramebuffer(); + } + gl.bindFramebuffer(gl.FRAMEBUFFER, this.auxFB); + //console.log("Restyle", timestamp) + // Render To Texture + // COLOR + this.tiles.forEach(tile => { + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tile.texColor, 0); + gl.viewport(0, 0, RTT_WIDTH, tile.height); + gl.clear(gl.COLOR_BUFFER_BIT); + + gl.useProgram(tile.style.colorShader.program); + var obj = { + freeTexUnit: 4 } - } else if (node.type == 'UnaryExpression') { - switch (node.operator) { - case '-': - return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatMul"](-1, parseNode(node.argument, scheme)); - case '+': - return parseNode(node.argument, scheme); - default: - throw new Error(`Invalid unary operator '${node.operator}'`); + tile.style._color._preDraw(obj); + + Object.keys(tile.style.propertyColorTID).forEach((name, i) => { + gl.activeTexture(gl.TEXTURE0 + i); + gl.bindTexture(gl.TEXTURE_2D, tile.propertyTex[tile.propertyID[name]]); + gl.uniform1i(tile.style.colorShader.textureLocations[i], i); + }); + + gl.enableVertexAttribArray(this.colorShaderVertex); + gl.bindBuffer(gl.ARRAY_BUFFER, this.squareBuffer); + gl.vertexAttribPointer(tile.style.colorShader.vertexAttribute, 2, gl.FLOAT, false, 0, 0); + + gl.drawArrays(gl.TRIANGLES, 0, 3); + }); + + //WIDTH + this.tiles.forEach(tile => { + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tile.texWidth, 0); + gl.useProgram(tile.style.widthShader.program); + gl.viewport(0, 0, RTT_WIDTH, tile.height); + gl.clear(gl.COLOR_BUFFER_BIT); + var obj = { + freeTexUnit: 4 } - } else if (node.type == 'Identifier') { - if (node.name[0] == '$') { - return __WEBPACK_IMPORTED_MODULE_1__functions__["Property"](node.name.substring(1), scheme); - } else if (__WEBPACK_IMPORTED_MODULE_1__functions__["schemes"][node.name.toLowerCase()]) { - return __WEBPACK_IMPORTED_MODULE_1__functions__["schemes"][node.name.toLowerCase()](); + tile.style._width._preDraw(obj); + Object.keys(tile.style.propertyWidthTID).forEach((name, i) => { + gl.activeTexture(gl.TEXTURE0 + i); + gl.bindTexture(gl.TEXTURE_2D, tile.propertyTex[tile.propertyID[name]]); + gl.uniform1i(tile.style.widthShader.textureLocations[i], i); + }); + + gl.enableVertexAttribArray(tile.style.widthShader.vertexAttribute); + gl.bindBuffer(gl.ARRAY_BUFFER, this.squareBuffer); + gl.vertexAttribPointer(tile.style.widthShader.vertexAttribute, 2, gl.FLOAT, false, 0, 0); + + gl.drawArrays(gl.TRIANGLES, 0, 3); + + tile.style.updated = false; + tile.initialized = true; + }); + + + gl.enable(gl.DEPTH_TEST); + + gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); + gl.enable(gl.BLEND); + + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); + + gl.useProgram(this.finalRendererProgram.program); + var s = 1. / this._zoom; + + + this.tiles.forEach(tile => { + /*console.log((s / aspect) * tile.scale, + s * tile.scale, + (s / aspect) * this._center.x - tile.center.x, + s * this._center.y - tile.center.y + );*/ + gl.uniform2f(this.finalRendererProgram.vertexScaleUniformLocation, + (s / aspect) * tile.scale, + s * tile.scale); + gl.uniform2f(this.finalRendererProgram.vertexOffsetUniformLocation, + (s / aspect) * (this._center.x - tile.center.x), + s * (this._center.y - tile.center.y)); + + gl.enableVertexAttribArray(this.finalRendererProgram.vertexPositionAttribute); + gl.bindBuffer(gl.ARRAY_BUFFER, tile.vertexBuffer); + gl.vertexAttribPointer(this.finalRendererProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); + + + gl.enableVertexAttribArray(this.finalRendererProgram.featureIdAttr); + gl.bindBuffer(gl.ARRAY_BUFFER, tile.featureIDBuffer); + gl.vertexAttribPointer(this.finalRendererProgram.featureIdAttr, 2, gl.FLOAT, false, 0, 0); + + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, tile.texColor); + gl.uniform1i(this.finalRendererProgram.colorTexture, 0); + + gl.activeTexture(gl.TEXTURE1); + gl.bindTexture(gl.TEXTURE_2D, tile.texWidth); + gl.uniform1i(this.finalRendererProgram.widthTexture, 1); + + gl.drawArrays(gl.POINTS, 0, tile.numVertex); + + }); + + this.tiles.forEach(t => { + if (t.style._color.isAnimated() || t.style._width.isAnimated()) { + window.requestAnimationFrame(refresh.bind(this)); } - } - throw new Error(`Invalid expression '${JSON.stringify(node)}'`); + }); } - +/** + * Initialize static shaders + */ +Renderer.prototype._initShaders = function () { + this.finalRendererProgram = __WEBPACK_IMPORTED_MODULE_0__shaders__["a" /* renderer */].createPointShader(gl); +} /***/ }), -/* 15 */ +/* 7 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__point__ = __webpack_require__(16); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__point__ = __webpack_require__(8); /* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "a", function() { return __WEBPACK_IMPORTED_MODULE_0__point__; }); /***/ }), -/* 16 */ +/* 8 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -3460,12 +2254,12 @@ void main(void) { /***/ }), -/* 17 */ +/* 9 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__color__ = __webpack_require__(18); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__width__ = __webpack_require__(19); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__color__ = __webpack_require__(10); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__width__ = __webpack_require__(11); /* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "a", function() { return __WEBPACK_IMPORTED_MODULE_0__color__; }); /* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "b", function() { return __WEBPACK_IMPORTED_MODULE_1__width__; }); @@ -3473,7 +2267,7 @@ void main(void) { /***/ }), -/* 18 */ +/* 10 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -3519,7 +2313,7 @@ void main(void) { /***/ }), -/* 19 */ +/* 11 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -3564,18 +2358,18 @@ void main(void) { /***/ }), -/* 20 */ +/* 12 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Style", function() { return Style; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "setGL", function() { return setGL; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_jsep__ = __webpack_require__(13); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_jsep__ = __webpack_require__(2); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_jsep___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_jsep__); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__functions__ = __webpack_require__(11); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__parser__ = __webpack_require__(14); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__shaders__ = __webpack_require__(12); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__functions__ = __webpack_require__(0); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__parser__ = __webpack_require__(3); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__shaders__ = __webpack_require__(1); /* harmony namespace reexport (by provided) */ __webpack_require__.d(__webpack_exports__, "Property", function() { return __WEBPACK_IMPORTED_MODULE_1__functions__["Property"]; }); /* harmony namespace reexport (by provided) */ __webpack_require__.d(__webpack_exports__, "Blend", function() { return __WEBPACK_IMPORTED_MODULE_1__functions__["Blend"]; }); /* harmony namespace reexport (by provided) */ __webpack_require__.d(__webpack_exports__, "Now", function() { return __WEBPACK_IMPORTED_MODULE_1__functions__["Now"]; }); @@ -3588,7 +2382,7 @@ Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); /* harmony namespace reexport (by provided) */ __webpack_require__.d(__webpack_exports__, "FloatAdd", function() { return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatAdd"]; }); /* harmony namespace reexport (by provided) */ __webpack_require__.d(__webpack_exports__, "FloatSub", function() { return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatSub"]; }); /* harmony namespace reexport (by provided) */ __webpack_require__.d(__webpack_exports__, "FloatPow", function() { return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatPow"]; }); -/* harmony namespace reexport (by provided) */ __webpack_require__.d(__webpack_exports__, "schemes", function() { return __WEBPACK_IMPORTED_MODULE_1__functions__["schemes"]; }); +/* harmony namespace reexport (by provided) */ __webpack_require__.d(__webpack_exports__, "schemas", function() { return __WEBPACK_IMPORTED_MODULE_1__functions__["schemas"]; }); /* harmony namespace reexport (by provided) */ __webpack_require__.d(__webpack_exports__, "parseStyleExpression", function() { return __WEBPACK_IMPORTED_MODULE_2__parser__["a"]; }); var gl = null; @@ -3637,11 +2431,16 @@ Style.prototype._compileWidthShader = function () { this.widthShader = r.shader; } - -function Style(renderer, scheme) { +/** + * @api + * @constructor + * @param {*} renderer + * @param {*} schema + */ +function Style(renderer, schema) { this.renderer = renderer; this.updated = true; - this.scheme = scheme; + this.schema = schema; this._width = __WEBPACK_IMPORTED_MODULE_1__functions__["Float"](5); this._width.parent = this; @@ -3656,6 +2455,10 @@ function Style(renderer, scheme) { window.requestAnimationFrame(this.renderer.refresh.bind(this.renderer)); }; } +/** + * @api + * @param {*} float + */ Style.prototype.setWidth = function (float) { this._width = float; this.updated = true; @@ -3679,7 +2482,10 @@ Style.prototype.replaceChild = function (toReplace, replacer) { console.warn('No child found'); } } - +/** + * @api + * @param {*} color + */ Style.prototype.setColor = function (color) { this._color = color; this.updated = true; @@ -3690,22 +2496,28 @@ Style.prototype.setColor = function (color) { }; color.notify(); } +/** + * @api + */ Style.prototype.getWidth = function () { return this._width; } +/** + * @api + */ Style.prototype.getColor = function () { return this._color; } /***/ }), -/* 21 */ +/* 13 */ /***/ (function(module, exports, __webpack_require__) { -module.exports = __webpack_require__(22); +module.exports = __webpack_require__(14); /***/ }), -/* 22 */ +/* 14 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;!function() { @@ -5558,7 +4370,7 @@ var colorbrewer_tags = { "YlOrRd": { "tags": ["quantitative"] } } -var colorbrewer = __webpack_require__(23); +var colorbrewer = __webpack_require__(15); // augment colorbrewer with tags for (var r in colorbrewer) { @@ -5591,14 +4403,14 @@ if (true) { /***/ }), -/* 23 */ +/* 15 */ /***/ (function(module, exports, __webpack_require__) { -module.exports = __webpack_require__(24); +module.exports = __webpack_require__(16); /***/ }), -/* 24 */ +/* 16 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;// This product includes color specifications and designs developed by Cynthia Brewer (http://colorbrewer.org/). @@ -5907,44 +4719,1335 @@ var colorbrewer = {YlGn: { 12: ["#8dd3c7","#ffffb3","#bebada","#fb8072","#80b1d3","#fdb462","#b3de69","#fccde5","#d9d9d9","#bc80bd","#ccebc5","#ffed6f"] }}; -if (true) { - !(__WEBPACK_AMD_DEFINE_FACTORY__ = (colorbrewer), - __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? - (__WEBPACK_AMD_DEFINE_FACTORY__.call(exports, __webpack_require__, exports, module)) : - __WEBPACK_AMD_DEFINE_FACTORY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} else if (typeof module === "object" && module.exports) { - module.exports = colorbrewer; -} else { - this.colorbrewer = colorbrewer; +if (true) { + !(__WEBPACK_AMD_DEFINE_FACTORY__ = (colorbrewer), + __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? + (__WEBPACK_AMD_DEFINE_FACTORY__.call(exports, __webpack_require__, exports, module)) : + __WEBPACK_AMD_DEFINE_FACTORY__), + __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); +} else if (typeof module === "object" && module.exports) { + module.exports = colorbrewer; +} else { + this.colorbrewer = colorbrewer; +} + +}(); + + +/***/ }), +/* 17 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Schema; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return checkschemaMatch; }); +/** + * @api + * @constructor + * @param {*} propertyNames + * @param {*} propertyTypes + */ +function Schema(propertyNames, propertyTypes) { + if (propertyNames.length != propertyTypes.length) { + throw new Error("propertyNames and propertyTypes lengths mismatch"); + } + propertyNames.map((name, index) => this[name] = propertyTypes[index]); +} + +/** + * + * @param {*} schemaA + * @param {*} schemaB + */ +function checkschemaMatch(schemaA, schemaB) { + if (schemaA && schemaB) { + const equals = Object.keys(schemaA).map(name => schemaA[name] == schemaB[name]).reduce((a, b) => a && b); + if (!equals) { + throw new Error(`schema mismatch: ${JSON.stringify(schemaA)}, ${JSON.stringify(schemaB)}`); + } + } +} + + + +/***/ }), +/* 18 */ +/***/ (function(module, exports, __webpack_require__) { + +module.exports.VectorTile = __webpack_require__(19); +module.exports.VectorTileFeature = __webpack_require__(5); +module.exports.VectorTileLayer = __webpack_require__(4); + + +/***/ }), +/* 19 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var VectorTileLayer = __webpack_require__(4); + +module.exports = VectorTile; + +function VectorTile(pbf, end) { + this.layers = pbf.readFields(readTile, {}, end); +} + +function readTile(tag, layers, pbf) { + if (tag === 3) { + var layer = new VectorTileLayer(pbf, pbf.readVarint() + pbf.pos); + if (layer.length) layers[layer.name] = layer; + } +} + + + +/***/ }), +/* 20 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +module.exports = Point; + +/** + * A standalone point geometry with useful accessor, comparison, and + * modification methods. + * + * @class Point + * @param {Number} x the x-coordinate. this could be longitude or screen + * pixels, or any other sort of unit. + * @param {Number} y the y-coordinate. this could be latitude or screen + * pixels, or any other sort of unit. + * @example + * var point = new Point(-77, 38); + */ +function Point(x, y) { + this.x = x; + this.y = y; +} + +Point.prototype = { + + /** + * Clone this point, returning a new point that can be modified + * without affecting the old one. + * @return {Point} the clone + */ + clone: function() { return new Point(this.x, this.y); }, + + /** + * Add this point's x & y coordinates to another point, + * yielding a new point. + * @param {Point} p the other point + * @return {Point} output point + */ + add: function(p) { return this.clone()._add(p); }, + + /** + * Subtract this point's x & y coordinates to from point, + * yielding a new point. + * @param {Point} p the other point + * @return {Point} output point + */ + sub: function(p) { return this.clone()._sub(p); }, + + /** + * Multiply this point's x & y coordinates by point, + * yielding a new point. + * @param {Point} p the other point + * @return {Point} output point + */ + multByPoint: function(p) { return this.clone()._multByPoint(p); }, + + /** + * Divide this point's x & y coordinates by point, + * yielding a new point. + * @param {Point} p the other point + * @return {Point} output point + */ + divByPoint: function(p) { return this.clone()._divByPoint(p); }, + + /** + * Multiply this point's x & y coordinates by a factor, + * yielding a new point. + * @param {Point} k factor + * @return {Point} output point + */ + mult: function(k) { return this.clone()._mult(k); }, + + /** + * Divide this point's x & y coordinates by a factor, + * yielding a new point. + * @param {Point} k factor + * @return {Point} output point + */ + div: function(k) { return this.clone()._div(k); }, + + /** + * Rotate this point around the 0, 0 origin by an angle a, + * given in radians + * @param {Number} a angle to rotate around, in radians + * @return {Point} output point + */ + rotate: function(a) { return this.clone()._rotate(a); }, + + /** + * Rotate this point around p point by an angle a, + * given in radians + * @param {Number} a angle to rotate around, in radians + * @param {Point} p Point to rotate around + * @return {Point} output point + */ + rotateAround: function(a,p) { return this.clone()._rotateAround(a,p); }, + + /** + * Multiply this point by a 4x1 transformation matrix + * @param {Array} m transformation matrix + * @return {Point} output point + */ + matMult: function(m) { return this.clone()._matMult(m); }, + + /** + * Calculate this point but as a unit vector from 0, 0, meaning + * that the distance from the resulting point to the 0, 0 + * coordinate will be equal to 1 and the angle from the resulting + * point to the 0, 0 coordinate will be the same as before. + * @return {Point} unit vector point + */ + unit: function() { return this.clone()._unit(); }, + + /** + * Compute a perpendicular point, where the new y coordinate + * is the old x coordinate and the new x coordinate is the old y + * coordinate multiplied by -1 + * @return {Point} perpendicular point + */ + perp: function() { return this.clone()._perp(); }, + + /** + * Return a version of this point with the x & y coordinates + * rounded to integers. + * @return {Point} rounded point + */ + round: function() { return this.clone()._round(); }, + + /** + * Return the magitude of this point: this is the Euclidean + * distance from the 0, 0 coordinate to this point's x and y + * coordinates. + * @return {Number} magnitude + */ + mag: function() { + return Math.sqrt(this.x * this.x + this.y * this.y); + }, + + /** + * Judge whether this point is equal to another point, returning + * true or false. + * @param {Point} other the other point + * @return {boolean} whether the points are equal + */ + equals: function(other) { + return this.x === other.x && + this.y === other.y; + }, + + /** + * Calculate the distance from this point to another point + * @param {Point} p the other point + * @return {Number} distance + */ + dist: function(p) { + return Math.sqrt(this.distSqr(p)); + }, + + /** + * Calculate the distance from this point to another point, + * without the square root step. Useful if you're comparing + * relative distances. + * @param {Point} p the other point + * @return {Number} distance + */ + distSqr: function(p) { + var dx = p.x - this.x, + dy = p.y - this.y; + return dx * dx + dy * dy; + }, + + /** + * Get the angle from the 0, 0 coordinate to this point, in radians + * coordinates. + * @return {Number} angle + */ + angle: function() { + return Math.atan2(this.y, this.x); + }, + + /** + * Get the angle from this point to another point, in radians + * @param {Point} b the other point + * @return {Number} angle + */ + angleTo: function(b) { + return Math.atan2(this.y - b.y, this.x - b.x); + }, + + /** + * Get the angle between this point and another point, in radians + * @param {Point} b the other point + * @return {Number} angle + */ + angleWith: function(b) { + return this.angleWithSep(b.x, b.y); + }, + + /* + * Find the angle of the two vectors, solving the formula for + * the cross product a x b = |a||b|sin(θ) for θ. + * @param {Number} x the x-coordinate + * @param {Number} y the y-coordinate + * @return {Number} the angle in radians + */ + angleWithSep: function(x, y) { + return Math.atan2( + this.x * y - this.y * x, + this.x * x + this.y * y); + }, + + _matMult: function(m) { + var x = m[0] * this.x + m[1] * this.y, + y = m[2] * this.x + m[3] * this.y; + this.x = x; + this.y = y; + return this; + }, + + _add: function(p) { + this.x += p.x; + this.y += p.y; + return this; + }, + + _sub: function(p) { + this.x -= p.x; + this.y -= p.y; + return this; + }, + + _mult: function(k) { + this.x *= k; + this.y *= k; + return this; + }, + + _div: function(k) { + this.x /= k; + this.y /= k; + return this; + }, + + _multByPoint: function(p) { + this.x *= p.x; + this.y *= p.y; + return this; + }, + + _divByPoint: function(p) { + this.x /= p.x; + this.y /= p.y; + return this; + }, + + _unit: function() { + this._div(this.mag()); + return this; + }, + + _perp: function() { + var y = this.y; + this.y = this.x; + this.x = -y; + return this; + }, + + _rotate: function(angle) { + var cos = Math.cos(angle), + sin = Math.sin(angle), + x = cos * this.x - sin * this.y, + y = sin * this.x + cos * this.y; + this.x = x; + this.y = y; + return this; + }, + + _rotateAround: function(angle, p) { + var cos = Math.cos(angle), + sin = Math.sin(angle), + x = p.x + cos * (this.x - p.x) - sin * (this.y - p.y), + y = p.y + sin * (this.x - p.x) + cos * (this.y - p.y); + this.x = x; + this.y = y; + return this; + }, + + _round: function() { + this.x = Math.round(this.x); + this.y = Math.round(this.y); + return this; + } +}; + +/** + * Construct a point from an array if necessary, otherwise if the input + * is already a Point, or an unknown type, return it unchanged + * @param {Array|Point|*} a any kind of input value + * @return {Point} constructed point, or passed-through value. + * @example + * // this + * var point = Point.convert([0, 1]); + * // is equivalent to + * var point = new Point(0, 1); + */ +Point.convert = function (a) { + if (a instanceof Point) { + return a; + } + if (Array.isArray(a)) { + return new Point(a[0], a[1]); + } + return a; +}; + + +/***/ }), +/* 21 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +module.exports = Pbf; + +var ieee754 = __webpack_require__(22); + +function Pbf(buf) { + this.buf = ArrayBuffer.isView && ArrayBuffer.isView(buf) ? buf : new Uint8Array(buf || 0); + this.pos = 0; + this.type = 0; + this.length = this.buf.length; +} + +Pbf.Varint = 0; // varint: int32, int64, uint32, uint64, sint32, sint64, bool, enum +Pbf.Fixed64 = 1; // 64-bit: double, fixed64, sfixed64 +Pbf.Bytes = 2; // length-delimited: string, bytes, embedded messages, packed repeated fields +Pbf.Fixed32 = 5; // 32-bit: float, fixed32, sfixed32 + +var SHIFT_LEFT_32 = (1 << 16) * (1 << 16), + SHIFT_RIGHT_32 = 1 / SHIFT_LEFT_32; + +Pbf.prototype = { + + destroy: function() { + this.buf = null; + }, + + // === READING ================================================================= + + readFields: function(readField, result, end) { + end = end || this.length; + + while (this.pos < end) { + var val = this.readVarint(), + tag = val >> 3, + startPos = this.pos; + + this.type = val & 0x7; + readField(tag, result, this); + + if (this.pos === startPos) this.skip(val); + } + return result; + }, + + readMessage: function(readField, result) { + return this.readFields(readField, result, this.readVarint() + this.pos); + }, + + readFixed32: function() { + var val = readUInt32(this.buf, this.pos); + this.pos += 4; + return val; + }, + + readSFixed32: function() { + var val = readInt32(this.buf, this.pos); + this.pos += 4; + return val; + }, + + // 64-bit int handling is based on github.com/dpw/node-buffer-more-ints (MIT-licensed) + + readFixed64: function() { + var val = readUInt32(this.buf, this.pos) + readUInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32; + this.pos += 8; + return val; + }, + + readSFixed64: function() { + var val = readUInt32(this.buf, this.pos) + readInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32; + this.pos += 8; + return val; + }, + + readFloat: function() { + var val = ieee754.read(this.buf, this.pos, true, 23, 4); + this.pos += 4; + return val; + }, + + readDouble: function() { + var val = ieee754.read(this.buf, this.pos, true, 52, 8); + this.pos += 8; + return val; + }, + + readVarint: function(isSigned) { + var buf = this.buf, + val, b; + + b = buf[this.pos++]; val = b & 0x7f; if (b < 0x80) return val; + b = buf[this.pos++]; val |= (b & 0x7f) << 7; if (b < 0x80) return val; + b = buf[this.pos++]; val |= (b & 0x7f) << 14; if (b < 0x80) return val; + b = buf[this.pos++]; val |= (b & 0x7f) << 21; if (b < 0x80) return val; + b = buf[this.pos]; val |= (b & 0x0f) << 28; + + return readVarintRemainder(val, isSigned, this); + }, + + readVarint64: function() { // for compatibility with v2.0.1 + return this.readVarint(true); + }, + + readSVarint: function() { + var num = this.readVarint(); + return num % 2 === 1 ? (num + 1) / -2 : num / 2; // zigzag encoding + }, + + readBoolean: function() { + return Boolean(this.readVarint()); + }, + + readString: function() { + var end = this.readVarint() + this.pos, + str = readUtf8(this.buf, this.pos, end); + this.pos = end; + return str; + }, + + readBytes: function() { + var end = this.readVarint() + this.pos, + buffer = this.buf.subarray(this.pos, end); + this.pos = end; + return buffer; + }, + + // verbose for performance reasons; doesn't affect gzipped size + + readPackedVarint: function(arr, isSigned) { + var end = readPackedEnd(this); + arr = arr || []; + while (this.pos < end) arr.push(this.readVarint(isSigned)); + return arr; + }, + readPackedSVarint: function(arr) { + var end = readPackedEnd(this); + arr = arr || []; + while (this.pos < end) arr.push(this.readSVarint()); + return arr; + }, + readPackedBoolean: function(arr) { + var end = readPackedEnd(this); + arr = arr || []; + while (this.pos < end) arr.push(this.readBoolean()); + return arr; + }, + readPackedFloat: function(arr) { + var end = readPackedEnd(this); + arr = arr || []; + while (this.pos < end) arr.push(this.readFloat()); + return arr; + }, + readPackedDouble: function(arr) { + var end = readPackedEnd(this); + arr = arr || []; + while (this.pos < end) arr.push(this.readDouble()); + return arr; + }, + readPackedFixed32: function(arr) { + var end = readPackedEnd(this); + arr = arr || []; + while (this.pos < end) arr.push(this.readFixed32()); + return arr; + }, + readPackedSFixed32: function(arr) { + var end = readPackedEnd(this); + arr = arr || []; + while (this.pos < end) arr.push(this.readSFixed32()); + return arr; + }, + readPackedFixed64: function(arr) { + var end = readPackedEnd(this); + arr = arr || []; + while (this.pos < end) arr.push(this.readFixed64()); + return arr; + }, + readPackedSFixed64: function(arr) { + var end = readPackedEnd(this); + arr = arr || []; + while (this.pos < end) arr.push(this.readSFixed64()); + return arr; + }, + + skip: function(val) { + var type = val & 0x7; + if (type === Pbf.Varint) while (this.buf[this.pos++] > 0x7f) {} + else if (type === Pbf.Bytes) this.pos = this.readVarint() + this.pos; + else if (type === Pbf.Fixed32) this.pos += 4; + else if (type === Pbf.Fixed64) this.pos += 8; + else throw new Error('Unimplemented type: ' + type); + }, + + // === WRITING ================================================================= + + writeTag: function(tag, type) { + this.writeVarint((tag << 3) | type); + }, + + realloc: function(min) { + var length = this.length || 16; + + while (length < this.pos + min) length *= 2; + + if (length !== this.length) { + var buf = new Uint8Array(length); + buf.set(this.buf); + this.buf = buf; + this.length = length; + } + }, + + finish: function() { + this.length = this.pos; + this.pos = 0; + return this.buf.subarray(0, this.length); + }, + + writeFixed32: function(val) { + this.realloc(4); + writeInt32(this.buf, val, this.pos); + this.pos += 4; + }, + + writeSFixed32: function(val) { + this.realloc(4); + writeInt32(this.buf, val, this.pos); + this.pos += 4; + }, + + writeFixed64: function(val) { + this.realloc(8); + writeInt32(this.buf, val & -1, this.pos); + writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4); + this.pos += 8; + }, + + writeSFixed64: function(val) { + this.realloc(8); + writeInt32(this.buf, val & -1, this.pos); + writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4); + this.pos += 8; + }, + + writeVarint: function(val) { + val = +val || 0; + + if (val > 0xfffffff || val < 0) { + writeBigVarint(val, this); + return; + } + + this.realloc(4); + + this.buf[this.pos++] = val & 0x7f | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return; + this.buf[this.pos++] = ((val >>>= 7) & 0x7f) | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return; + this.buf[this.pos++] = ((val >>>= 7) & 0x7f) | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return; + this.buf[this.pos++] = (val >>> 7) & 0x7f; + }, + + writeSVarint: function(val) { + this.writeVarint(val < 0 ? -val * 2 - 1 : val * 2); + }, + + writeBoolean: function(val) { + this.writeVarint(Boolean(val)); + }, + + writeString: function(str) { + str = String(str); + this.realloc(str.length * 4); + + this.pos++; // reserve 1 byte for short string length + + var startPos = this.pos; + // write the string directly to the buffer and see how much was written + this.pos = writeUtf8(this.buf, str, this.pos); + var len = this.pos - startPos; + + if (len >= 0x80) makeRoomForExtraLength(startPos, len, this); + + // finally, write the message length in the reserved place and restore the position + this.pos = startPos - 1; + this.writeVarint(len); + this.pos += len; + }, + + writeFloat: function(val) { + this.realloc(4); + ieee754.write(this.buf, val, this.pos, true, 23, 4); + this.pos += 4; + }, + + writeDouble: function(val) { + this.realloc(8); + ieee754.write(this.buf, val, this.pos, true, 52, 8); + this.pos += 8; + }, + + writeBytes: function(buffer) { + var len = buffer.length; + this.writeVarint(len); + this.realloc(len); + for (var i = 0; i < len; i++) this.buf[this.pos++] = buffer[i]; + }, + + writeRawMessage: function(fn, obj) { + this.pos++; // reserve 1 byte for short message length + + // write the message directly to the buffer and see how much was written + var startPos = this.pos; + fn(obj, this); + var len = this.pos - startPos; + + if (len >= 0x80) makeRoomForExtraLength(startPos, len, this); + + // finally, write the message length in the reserved place and restore the position + this.pos = startPos - 1; + this.writeVarint(len); + this.pos += len; + }, + + writeMessage: function(tag, fn, obj) { + this.writeTag(tag, Pbf.Bytes); + this.writeRawMessage(fn, obj); + }, + + writePackedVarint: function(tag, arr) { this.writeMessage(tag, writePackedVarint, arr); }, + writePackedSVarint: function(tag, arr) { this.writeMessage(tag, writePackedSVarint, arr); }, + writePackedBoolean: function(tag, arr) { this.writeMessage(tag, writePackedBoolean, arr); }, + writePackedFloat: function(tag, arr) { this.writeMessage(tag, writePackedFloat, arr); }, + writePackedDouble: function(tag, arr) { this.writeMessage(tag, writePackedDouble, arr); }, + writePackedFixed32: function(tag, arr) { this.writeMessage(tag, writePackedFixed32, arr); }, + writePackedSFixed32: function(tag, arr) { this.writeMessage(tag, writePackedSFixed32, arr); }, + writePackedFixed64: function(tag, arr) { this.writeMessage(tag, writePackedFixed64, arr); }, + writePackedSFixed64: function(tag, arr) { this.writeMessage(tag, writePackedSFixed64, arr); }, + + writeBytesField: function(tag, buffer) { + this.writeTag(tag, Pbf.Bytes); + this.writeBytes(buffer); + }, + writeFixed32Field: function(tag, val) { + this.writeTag(tag, Pbf.Fixed32); + this.writeFixed32(val); + }, + writeSFixed32Field: function(tag, val) { + this.writeTag(tag, Pbf.Fixed32); + this.writeSFixed32(val); + }, + writeFixed64Field: function(tag, val) { + this.writeTag(tag, Pbf.Fixed64); + this.writeFixed64(val); + }, + writeSFixed64Field: function(tag, val) { + this.writeTag(tag, Pbf.Fixed64); + this.writeSFixed64(val); + }, + writeVarintField: function(tag, val) { + this.writeTag(tag, Pbf.Varint); + this.writeVarint(val); + }, + writeSVarintField: function(tag, val) { + this.writeTag(tag, Pbf.Varint); + this.writeSVarint(val); + }, + writeStringField: function(tag, str) { + this.writeTag(tag, Pbf.Bytes); + this.writeString(str); + }, + writeFloatField: function(tag, val) { + this.writeTag(tag, Pbf.Fixed32); + this.writeFloat(val); + }, + writeDoubleField: function(tag, val) { + this.writeTag(tag, Pbf.Fixed64); + this.writeDouble(val); + }, + writeBooleanField: function(tag, val) { + this.writeVarintField(tag, Boolean(val)); + } +}; + +function readVarintRemainder(l, s, p) { + var buf = p.buf, + h, b; + + b = buf[p.pos++]; h = (b & 0x70) >> 4; if (b < 0x80) return toNum(l, h, s); + b = buf[p.pos++]; h |= (b & 0x7f) << 3; if (b < 0x80) return toNum(l, h, s); + b = buf[p.pos++]; h |= (b & 0x7f) << 10; if (b < 0x80) return toNum(l, h, s); + b = buf[p.pos++]; h |= (b & 0x7f) << 17; if (b < 0x80) return toNum(l, h, s); + b = buf[p.pos++]; h |= (b & 0x7f) << 24; if (b < 0x80) return toNum(l, h, s); + b = buf[p.pos++]; h |= (b & 0x01) << 31; if (b < 0x80) return toNum(l, h, s); + + throw new Error('Expected varint not more than 10 bytes'); +} + +function readPackedEnd(pbf) { + return pbf.type === Pbf.Bytes ? + pbf.readVarint() + pbf.pos : pbf.pos + 1; +} + +function toNum(low, high, isSigned) { + if (isSigned) { + return high * 0x100000000 + (low >>> 0); + } + + return ((high >>> 0) * 0x100000000) + (low >>> 0); +} + +function writeBigVarint(val, pbf) { + var low, high; + + if (val >= 0) { + low = (val % 0x100000000) | 0; + high = (val / 0x100000000) | 0; + } else { + low = ~(-val % 0x100000000); + high = ~(-val / 0x100000000); + + if (low ^ 0xffffffff) { + low = (low + 1) | 0; + } else { + low = 0; + high = (high + 1) | 0; + } + } + + if (val >= 0x10000000000000000 || val < -0x10000000000000000) { + throw new Error('Given varint doesn\'t fit into 10 bytes'); + } + + pbf.realloc(10); + + writeBigVarintLow(low, high, pbf); + writeBigVarintHigh(high, pbf); +} + +function writeBigVarintLow(low, high, pbf) { + pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7; + pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7; + pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7; + pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7; + pbf.buf[pbf.pos] = low & 0x7f; +} + +function writeBigVarintHigh(high, pbf) { + var lsb = (high & 0x07) << 4; + + pbf.buf[pbf.pos++] |= lsb | ((high >>>= 3) ? 0x80 : 0); if (!high) return; + pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return; + pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return; + pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return; + pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return; + pbf.buf[pbf.pos++] = high & 0x7f; +} + +function makeRoomForExtraLength(startPos, len, pbf) { + var extraLen = + len <= 0x3fff ? 1 : + len <= 0x1fffff ? 2 : + len <= 0xfffffff ? 3 : Math.ceil(Math.log(len) / (Math.LN2 * 7)); + + // if 1 byte isn't enough for encoding message length, shift the data to the right + pbf.realloc(extraLen); + for (var i = pbf.pos - 1; i >= startPos; i--) pbf.buf[i + extraLen] = pbf.buf[i]; +} + +function writePackedVarint(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeVarint(arr[i]); } +function writePackedSVarint(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSVarint(arr[i]); } +function writePackedFloat(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFloat(arr[i]); } +function writePackedDouble(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeDouble(arr[i]); } +function writePackedBoolean(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeBoolean(arr[i]); } +function writePackedFixed32(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFixed32(arr[i]); } +function writePackedSFixed32(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSFixed32(arr[i]); } +function writePackedFixed64(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFixed64(arr[i]); } +function writePackedSFixed64(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSFixed64(arr[i]); } + +// Buffer code below from https://github.com/feross/buffer, MIT-licensed + +function readUInt32(buf, pos) { + return ((buf[pos]) | + (buf[pos + 1] << 8) | + (buf[pos + 2] << 16)) + + (buf[pos + 3] * 0x1000000); +} + +function writeInt32(buf, val, pos) { + buf[pos] = val; + buf[pos + 1] = (val >>> 8); + buf[pos + 2] = (val >>> 16); + buf[pos + 3] = (val >>> 24); +} + +function readInt32(buf, pos) { + return ((buf[pos]) | + (buf[pos + 1] << 8) | + (buf[pos + 2] << 16)) + + (buf[pos + 3] << 24); +} + +function readUtf8(buf, pos, end) { + var str = ''; + var i = pos; + + while (i < end) { + var b0 = buf[i]; + var c = null; // codepoint + var bytesPerSequence = + b0 > 0xEF ? 4 : + b0 > 0xDF ? 3 : + b0 > 0xBF ? 2 : 1; + + if (i + bytesPerSequence > end) break; + + var b1, b2, b3; + + if (bytesPerSequence === 1) { + if (b0 < 0x80) { + c = b0; + } + } else if (bytesPerSequence === 2) { + b1 = buf[i + 1]; + if ((b1 & 0xC0) === 0x80) { + c = (b0 & 0x1F) << 0x6 | (b1 & 0x3F); + if (c <= 0x7F) { + c = null; + } + } + } else if (bytesPerSequence === 3) { + b1 = buf[i + 1]; + b2 = buf[i + 2]; + if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80) { + c = (b0 & 0xF) << 0xC | (b1 & 0x3F) << 0x6 | (b2 & 0x3F); + if (c <= 0x7FF || (c >= 0xD800 && c <= 0xDFFF)) { + c = null; + } + } + } else if (bytesPerSequence === 4) { + b1 = buf[i + 1]; + b2 = buf[i + 2]; + b3 = buf[i + 3]; + if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80 && (b3 & 0xC0) === 0x80) { + c = (b0 & 0xF) << 0x12 | (b1 & 0x3F) << 0xC | (b2 & 0x3F) << 0x6 | (b3 & 0x3F); + if (c <= 0xFFFF || c >= 0x110000) { + c = null; + } + } + } + + if (c === null) { + c = 0xFFFD; + bytesPerSequence = 1; + + } else if (c > 0xFFFF) { + c -= 0x10000; + str += String.fromCharCode(c >>> 10 & 0x3FF | 0xD800); + c = 0xDC00 | c & 0x3FF; + } + + str += String.fromCharCode(c); + i += bytesPerSequence; + } + + return str; +} + +function writeUtf8(buf, str, pos) { + for (var i = 0, c, lead; i < str.length; i++) { + c = str.charCodeAt(i); // code point + + if (c > 0xD7FF && c < 0xE000) { + if (lead) { + if (c < 0xDC00) { + buf[pos++] = 0xEF; + buf[pos++] = 0xBF; + buf[pos++] = 0xBD; + lead = c; + continue; + } else { + c = lead - 0xD800 << 10 | c - 0xDC00 | 0x10000; + lead = null; + } + } else { + if (c > 0xDBFF || (i + 1 === str.length)) { + buf[pos++] = 0xEF; + buf[pos++] = 0xBF; + buf[pos++] = 0xBD; + } else { + lead = c; + } + continue; + } + } else if (lead) { + buf[pos++] = 0xEF; + buf[pos++] = 0xBF; + buf[pos++] = 0xBD; + lead = null; + } + + if (c < 0x80) { + buf[pos++] = c; + } else { + if (c < 0x800) { + buf[pos++] = c >> 0x6 | 0xC0; + } else { + if (c < 0x10000) { + buf[pos++] = c >> 0xC | 0xE0; + } else { + buf[pos++] = c >> 0x12 | 0xF0; + buf[pos++] = c >> 0xC & 0x3F | 0x80; + } + buf[pos++] = c >> 0x6 & 0x3F | 0x80; + } + buf[pos++] = c & 0x3F | 0x80; + } + } + return pos; +} + + +/***/ }), +/* 22 */ +/***/ (function(module, exports) { + +exports.read = function (buffer, offset, isLE, mLen, nBytes) { + var e, m + var eLen = nBytes * 8 - mLen - 1 + var eMax = (1 << eLen) - 1 + var eBias = eMax >> 1 + var nBits = -7 + var i = isLE ? (nBytes - 1) : 0 + var d = isLE ? -1 : 1 + var s = buffer[offset + i] + + i += d + + e = s & ((1 << (-nBits)) - 1) + s >>= (-nBits) + nBits += eLen + for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {} + + m = e & ((1 << (-nBits)) - 1) + e >>= (-nBits) + nBits += mLen + for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {} + + if (e === 0) { + e = 1 - eBias + } else if (e === eMax) { + return m ? NaN : ((s ? -1 : 1) * Infinity) + } else { + m = m + Math.pow(2, mLen) + e = e - eBias + } + return (s ? -1 : 1) * m * Math.pow(2, e - mLen) } -}(); +exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { + var e, m, c + var eLen = nBytes * 8 - mLen - 1 + var eMax = (1 << eLen) - 1 + var eBias = eMax >> 1 + var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0) + var i = isLE ? 0 : (nBytes - 1) + var d = isLE ? 1 : -1 + var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0 + + value = Math.abs(value) + + if (isNaN(value) || value === Infinity) { + m = isNaN(value) ? 1 : 0 + e = eMax + } else { + e = Math.floor(Math.log(value) / Math.LN2) + if (value * (c = Math.pow(2, -e)) < 1) { + e-- + c *= 2 + } + if (e + eBias >= 1) { + value += rt / c + } else { + value += rt * Math.pow(2, 1 - eBias) + } + if (value * c >= 2) { + e++ + c /= 2 + } + + if (e + eBias >= eMax) { + m = 0 + e = eMax + } else if (e + eBias >= 1) { + m = (value * c - 1) * Math.pow(2, mLen) + e = e + eBias + } else { + m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen) + e = 0 + } + } + + for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} + + e = (e << mLen) | m + eLen += mLen + for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} + + buffer[offset + i - d] |= s * 128 +} /***/ }), +/* 23 */, +/* 24 */, /* 25 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Scheme; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return checkSchemeMatch; }); -function Scheme(propertyNames, propertyTypes) { - if (propertyNames.length != propertyTypes.length) { - throw new Error("propertyNames and propertyTypes lengths mismatch"); +Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__src_index__ = __webpack_require__(6); + + +var VectorTile = __webpack_require__(18).VectorTile; +var Protobuf = __webpack_require__(21); + +var renderer; +var layer; +var oldtile; +var ajax; + +function styleWidth(e) { + const v = document.getElementById("widthStyleEntry").value; + const Near = __WEBPACK_IMPORTED_MODULE_0__src_index__["c" /* Style */].Near; + const Float = __WEBPACK_IMPORTED_MODULE_0__src_index__["c" /* Style */].Float; + const Color = __WEBPACK_IMPORTED_MODULE_0__src_index__["c" /* Style */].Color; + const RampColor = __WEBPACK_IMPORTED_MODULE_0__src_index__["c" /* Style */].RampColor; + const width = eval(v); + if (width) { + layer.style.getWidth().blendTo(width, 1000); } - propertyNames.map((name, index) => this[name] = propertyTypes[index]); } -function checkSchemeMatch(schemeA, schemeB) { - if (schemeA && schemeB) { - const equals = Object.keys(schemeA).map(name => schemeA[name] == schemeB[name]).reduce((a, b) => a && b); - if (!equals) { - throw new Error(`Scheme mismatch: ${JSON.stringify(schemeA)}, ${JSON.stringify(schemeB)}`); +function styleColor(e) { + const v = document.getElementById("colorStyleEntry").value; + const Near = __WEBPACK_IMPORTED_MODULE_0__src_index__["c" /* Style */].Near; + const Float = __WEBPACK_IMPORTED_MODULE_0__src_index__["c" /* Style */].Float; + const Color = __WEBPACK_IMPORTED_MODULE_0__src_index__["c" /* Style */].Color; + const RampColor = __WEBPACK_IMPORTED_MODULE_0__src_index__["c" /* Style */].RampColor; + const color = eval(v); + if (color) { + layer.style.getColor().blendTo(color, 1000); + } +} + +function getData() { + if (ajax) { + ajax.abort(); + } + + var oReq = new XMLHttpRequest(); + oReq.open("GET", "https://dmanzanares.carto.com/api/v1/map/dmanzanares@789cad67@92456f0655aac0322b2572f4e05088e7:1509358508954/mapnik/0/0/0.mvt", true); + oReq.responseType = "arraybuffer"; + oReq.onload = function (oEvent) { + var arrayBuffer = oReq.response; + if (arrayBuffer) { + var tile = new VectorTile(new Protobuf(arrayBuffer)); + const mvtLayer = tile.layers[Object.keys(tile.layers)[0]]; + + var fieldMap = { + temp: 0, + daten: 1 + }; + //mvtLayer.length=1000; + var properties = [[new Float32Array(mvtLayer.length)], [new Float32Array(mvtLayer.length)]]; + var points = new Float32Array(mvtLayer.length * 2); + for (var i = 0; i < mvtLayer.length; i++) { + const f = mvtLayer.feature(i); + const geom = f.loadGeometry(); + points[2 * i + 0] = 2 * (geom[0][0].x) / 4096.0 - 1.; + points[2 * i + 1] = 2 * (1. - (geom[0][0].y) / 4096.0) - 1.; + + properties[0][i] = Number(f.properties.temp); + properties[1][i] = Number(f.properties.daten); + } + var tile = { + center: { x: 0, y: 0 }, + scale: 1 / 1., + count: mvtLayer.length, + geom: points, + properties: {} + }; + Object.keys(fieldMap).map((name, pid) => { + tile.properties[name] = properties[pid]; + }) + oldtile = layer.addTile(tile); + styleWidth(); + styleColor(); } + }; + + oReq.send(null); +} +function start(element) { + renderer = new __WEBPACK_IMPORTED_MODULE_0__src_index__["a" /* Renderer */](element); + layer = renderer.addLayer(); + + getData(); + $('#widthStyleEntry').on('input', styleWidth); + $('#colorStyleEntry').on('input', styleColor); + //$('#sqlEntry').on('input', getData); + + //window.onresize = function () { renderer.refresh(); }; +} +const DEG2RAD = Math.PI / 180; +const EARTH_RADIUS = 6378137; +const WM_EXT = EARTH_RADIUS * Math.PI * 2; +const TILE_SIZE = 256; +// Webmercator projection +function Wmxy(latLng) { + let lat = latLng.lat() * DEG2RAD; + let lng = latLng.lng() * DEG2RAD; + let x = lng * EARTH_RADIUS; + let y = Math.log(Math.tan(lat / 2 + Math.PI / 4)) * EARTH_RADIUS; + return { x: x, y: y }; +} + +function initMap() { + // Create a map object and specify the DOM element for display. + var map = new google.maps.Map(document.getElementById('map'), { + center: { lat: -34.397, lng: 150.644 }, + zoom: 8 + }); + + var cont = map.getDiv(); + var canvas = document.createElement('canvas') + canvas.id = 'good'; + cont.appendChild(canvas) + canvas.style.width = '100%'; + canvas.style.height = '100%'; + console.log(cont, cont.style.width, cont.getClientRects()[0].width, canvas.style.width); + function getZoom() { + var b = map.getBounds(); + var c = map.getCenter(); + var nw = b.getNorthEast(); + var sw = b.getSouthWest(); + var z = (Wmxy(nw).y - Wmxy(sw).y) / 40075019.834677525; + renderer.setCenter(c.lng() / 180., Wmxy(c).y / 40075019.834677525 * 2.); + return z; + } + function move(a, b, c) { + var b = map.getBounds(); + var nw = b.getNorthEast(); + var c = map.getCenter(); + + renderer.setCenter(c.lng / 180., Wmxy(c).y / 40075019.834677525 * 2.); + renderer.setZoom(getZoom()); + // console.log(renderer.getCenter(), renderer.getZoom(), c) } + start(canvas); + // move(); + window.map = map; + +var attatched = false; + /* map.addListener('drag', function () { + // debugger; + if (!attatched) { + var target = cont.querySelector('div.gm-style div div'); + + // create an observer instance + var observer = new MutationObserver(function (mutations) { + //move(); + }); + + // configuration of the observer: + var config = { attributes: true, childList: true, characterData: true }; + + // pass in the target node, as well as the observer options + observer.observe(target, config); + } + }); + + map.addListener('dragend', move); + map.addListener('dragstart', move); + map.addListener('drag', move);*/ + /*cont.addEventListener('mousemove', move); + cont.addEventListener('mousestart', move); + cont.addEventListener('mouseleave', move); + cont.addEventListener('mouseover', move); + cont.addEventListener('mousemove', move);*/ } +window.initMap = initMap; +/* +map.on('load', _ => { + var cont = map.getCanvasContainer(); + var canvas = document.createElement('canvas') + canvas.id = 'good'; + cont.appendChild(canvas) + canvas.style.width = map.getCanvas().style.width; + canvas.style.height = map.getCanvas().style.height; + + function move(a, b, c) { + var b = map.getBounds(); + var nw = b.getNorthWest(); + var c = map.getCenter(); + renderer.setCenter(c.lng / 180., Wmxy(c).y / 40075019.834677525 * 2.); + renderer.setZoom(getZoom()); + } + start(canvas); + move(); + map.on('movestart', move); + map.on('move', move); + map.on('moveend', move); + map.on('dragstart', move); + map.on('drag', move); + map.on('dragstart', move); + map.on('dragend', move); + map.on('zoomstart', move); + map.on('zoom', move); + map.on('zoomend', move); +}); +*/ /***/ }) /******/ ]); \ No newline at end of file diff --git a/dist/mapbox.js b/dist/mapbox.js index 4e2288821..1bb99c782 100644 --- a/dist/mapbox.js +++ b/dist/mapbox.js @@ -60,2593 +60,667 @@ /******/ __webpack_require__.p = ""; /******/ /******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 9); +/******/ return __webpack_require__(__webpack_require__.s = 24); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ -/***/ (function(module, exports, __webpack_require__) { +/***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; +Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Property", function() { return Property; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Blend", function() { return Blend; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Now", function() { return Now; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Near", function() { return Near; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Color", function() { return Color; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Float", function() { return Float; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RampColor", function() { return RampColor; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FloatMul", function() { return FloatMul; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FloatDiv", function() { return FloatDiv; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FloatAdd", function() { return FloatAdd; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FloatSub", function() { return FloatSub; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FloatPow", function() { return FloatPow; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "setGL", function() { return setGL; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "schemas", function() { return schemas; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_cartocolor__ = __webpack_require__(13); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_cartocolor___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_cartocolor__); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__schema__ = __webpack_require__(17); -var VectorTileFeature = __webpack_require__(1); - -module.exports = VectorTileLayer; - -function VectorTileLayer(pbf, end) { - // Public - this.version = 1; - this.name = null; - this.extent = 4096; - this.length = 0; - - // Private - this._pbf = pbf; - this._keys = []; - this._values = []; - this._features = []; - - pbf.readFields(readLayer, this, end); - - this.length = this._features.length; -} - -function readLayer(tag, layer, pbf) { - if (tag === 15) layer.version = pbf.readVarint(); - else if (tag === 1) layer.name = pbf.readString(); - else if (tag === 5) layer.extent = pbf.readVarint(); - else if (tag === 2) layer._features.push(pbf.pos); - else if (tag === 3) layer._keys.push(pbf.readString()); - else if (tag === 4) layer._values.push(readValueMessage(pbf)); -} - -function readValueMessage(pbf) { - var value = null, - end = pbf.readVarint() + pbf.pos; - - while (pbf.pos < end) { - var tag = pbf.readVarint() >> 3; - value = tag === 1 ? pbf.readString() : - tag === 2 ? pbf.readFloat() : - tag === 3 ? pbf.readDouble() : - tag === 4 ? pbf.readVarint64() : - tag === 5 ? pbf.readVarint() : - tag === 6 ? pbf.readSVarint() : - tag === 7 ? pbf.readBoolean() : null; +function implicitCast(value) { + if (Number.isFinite(value)) { + return Float(value); } - return value; } - -// return feature `i` from this layer as a `VectorTileFeature` -VectorTileLayer.prototype.feature = function(i) { - if (i < 0 || i >= this._features.length) throw new Error('feature index out of bounds'); - - this._pbf.pos = this._features[i]; - - var end = this._pbf.readVarint() + this._pbf.pos; - return new VectorTileFeature(this._pbf, end, this.extent, this._keys, this._values); -}; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +var gl = null; +function setGL(_gl) { + gl = _gl; +} -var Point = __webpack_require__(5); +const schemas = {}; +Object.keys(__WEBPACK_IMPORTED_MODULE_0_cartocolor__).map(name => { + const s = __WEBPACK_IMPORTED_MODULE_0_cartocolor__[name]; + var defaultFound = false; + for (let i = 20; i >= 0; i--) { + if (s[i]) { + if (!defaultFound) { + schemas[name.toLowerCase()] = () => s[i]; + defaultFound = true; + } + schemas[`${name.toLowerCase()}_${i}`] = () => s[i]; + } + } +}); -module.exports = VectorTileFeature; -function VectorTileFeature(pbf, end, extent, keys, values) { - // Public - this.properties = {}; - this.extent = extent; - this.type = 0; +/* + Each styling function should: + - Create their own objects, i.e.: be used without "new" + - Check input validity on user input (constructor and exposed functions). + - Have certain functions that never fail: + - _applyToShaderSource should use uniformIDMaker and propertyTIDMaker to get unique uniform IDs and property IDs as needed + - _postShaderCompile should get uniform location after program compilation as needed + - _preDraw should set any program's uniforms as needed + - isAnimated should return true if the function output could change depending on the timestamp + - Have a type property declaring the GLSL output type: 'float', 'color' +*/ - // Private - this._pbf = pbf; - this._geometry = -1; - this._keys = keys; - this._values = values; +/* + TODO + - Integrated color palettes + - Type checking for color palettes + - Allow multiplication, division and pow() to color expressions and color literals + - Add SetOpacity(colorExpr, opacityFloatOverride) + - HSV + - Think about uniform-only types / parameters + - Think about "Date" and "string" types. + - Heatmaps (renderer should be improved too to accommodate this) +*/ - pbf.readFields(readFeature, this, end); +function Property(name, schema) { + return new _Property(name, schema); } - -function readFeature(tag, feature, pbf) { - if (tag == 1) feature.id = pbf.readVarint(); - else if (tag == 2) readTag(pbf, feature); - else if (tag == 3) feature.type = pbf.readVarint(); - else if (tag == 4) feature._geometry = pbf.pos; +function _Property(name, schema) { + if (typeof name !== 'string' || name == '') { + throw new Error(`Invalid property name '${name}'`); + } + if (!schema[name]) { + throw new Error(`Property name not found`); + } + this.name = name; + this.type = 'float'; + this.schema = schema; +} +_Property.prototype._applyToShaderSource = function (uniformIDMaker, propertyTIDMaker) { + return { + preface: '', + inline: `p${propertyTIDMaker(this.name)}` + }; +} +_Property.prototype._postShaderCompile = function (program) { +} +_Property.prototype._preDraw = function () { +} +_Property.prototype.isAnimated = function () { + return false; } -function readTag(pbf, feature) { - var end = pbf.readVarint() + pbf.pos; - - while (pbf.pos < end) { - var key = feature._keys[pbf.readVarint()], - value = feature._values[pbf.readVarint()]; - feature.properties[key] = value; +function Now(speed) { + return new _Now(speed); +} +function _Now(speed) { + if (speed == undefined) { + speed = 1; + } + if (!Number.isFinite(Number(speed))) { + throw new Error('Now() only accepts number literals'); } + this.speed = Number(speed); + this.type = 'float'; + this.float = Float(0); +} +_Now.prototype._applyToShaderSource = function (uniformIDMaker) { + return this.float._applyToShaderSource(uniformIDMaker); +} +_Now.prototype._postShaderCompile = function (program) { + return this.float._postShaderCompile(program); +} +_Now.prototype._preDraw = function () { + this.float.expr = (Date.now() * this.speed / 1000.) % 1; + this.float._preDraw(); +} +_Now.prototype.isAnimated = function () { + return true; } -VectorTileFeature.types = ['Unknown', 'Point', 'LineString', 'Polygon']; - -VectorTileFeature.prototype.loadGeometry = function() { - var pbf = this._pbf; - pbf.pos = this._geometry; - - var end = pbf.readVarint() + pbf.pos, - cmd = 1, - length = 0, - x = 0, - y = 0, - lines = [], - line; +const FloatMul = genFloatBinaryOperation((x, y) => x * y, (x, y) => `(${x} * ${y})`); +const FloatDiv = genFloatBinaryOperation((x, y) => x / y, (x, y) => `(${x} / ${y})`); +const FloatAdd = genFloatBinaryOperation((x, y) => x + y, (x, y) => `(${x} + ${y})`); +const FloatSub = genFloatBinaryOperation((x, y) => x - y, (x, y) => `(${x} - ${y})`); +const FloatPow = genFloatBinaryOperation((x, y) => Math.pow(x, y), (x, y) => `pow(${x}, ${y})`); - while (pbf.pos < end) { - if (!length) { - var cmdLen = pbf.readVarint(); - cmd = cmdLen & 0x7; - length = cmdLen >> 3; +function genFloatBinaryOperation(jsFn, glsl) { + function BinaryOp(a, b) { + if (Number.isFinite(a) && Number.isFinite(b)) { + return Float(jsFn(a, b)); } - - length--; - - if (cmd === 1 || cmd === 2) { - x += pbf.readSVarint(); - y += pbf.readSVarint(); - - if (cmd === 1) { // moveTo - if (line) lines.push(line); - line = []; - } - - line.push(new Point(x, y)); - - } else if (cmd === 7) { - - // Workaround for https://github.com/mapbox/mapnik-vector-tile/issues/90 - if (line) { - line.push(line[0].clone()); // closePolygon - } - + if (Number.isFinite(a)) { + a = Float(a); + } + if (Number.isFinite(b)) { + b = Float(b); + } + if (a.type == 'float' && b.type == 'float') { + this.type = 'float'; } else { - throw new Error('unknown command ' + cmd); + console.warn(a, b); + throw new Error(`Binary operation cannot be performed between '${a}' and '${b}'`); } + return new _BinaryOp(a, b); } - - if (line) lines.push(line); - - return lines; -}; - -VectorTileFeature.prototype.bbox = function() { - var pbf = this._pbf; - pbf.pos = this._geometry; - - var end = pbf.readVarint() + pbf.pos, - cmd = 1, - length = 0, - x = 0, - y = 0, - x1 = Infinity, - x2 = -Infinity, - y1 = Infinity, - y2 = -Infinity; - - while (pbf.pos < end) { - if (!length) { - var cmdLen = pbf.readVarint(); - cmd = cmdLen & 0x7; - length = cmdLen >> 3; - } - - length--; - - if (cmd === 1 || cmd === 2) { - x += pbf.readSVarint(); - y += pbf.readSVarint(); - if (x < x1) x1 = x; - if (x > x2) x2 = x; - if (y < y1) y1 = y; - if (y > y2) y2 = y; - - } else if (cmd !== 7) { - throw new Error('unknown command ' + cmd); - } + function _BinaryOp(a, b) { + this.type = 'float'; + this.a = a; + this.b = b; + a.parent = this; + b.parent = this; } - - return [x1, y1, x2, y2]; -}; - -VectorTileFeature.prototype.toGeoJSON = function(x, y, z) { - var size = this.extent * Math.pow(2, z), - x0 = this.extent * x, - y0 = this.extent * y, - coords = this.loadGeometry(), - type = VectorTileFeature.types[this.type], - i, j; - - function project(line) { - for (var j = 0; j < line.length; j++) { - var p = line[j], y2 = 180 - (p.y + y0) * 360 / size; - line[j] = [ - (p.x + x0) * 360 / size - 180, - 360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90 - ]; - } + _BinaryOp.prototype._applyToShaderSource = function (uniformIDMaker, propertyTIDMaker) { + const a = this.a._applyToShaderSource(uniformIDMaker, propertyTIDMaker); + const b = this.b._applyToShaderSource(uniformIDMaker, propertyTIDMaker); + return { + preface: a.preface + b.preface, + inline: glsl(a.inline, b.inline) + }; } - - switch (this.type) { - case 1: - var points = []; - for (i = 0; i < coords.length; i++) { - points[i] = coords[i][0]; - } - coords = points; - project(coords); - break; - - case 2: - for (i = 0; i < coords.length; i++) { - project(coords[i]); - } - break; - - case 3: - coords = classifyRings(coords); - for (i = 0; i < coords.length; i++) { - for (j = 0; j < coords[i].length; j++) { - project(coords[i][j]); - } - } - break; + _BinaryOp.prototype._postShaderCompile = function (program) { + this.a._postShaderCompile(program); + this.b._postShaderCompile(program); } - - if (coords.length === 1) { - coords = coords[0]; - } else { - type = 'Multi' + type; + _BinaryOp.prototype._preDraw = function (l) { + this.a._preDraw(l); + this.b._preDraw(l); } - - var result = { - type: "Feature", - geometry: { - type: type, - coordinates: coords - }, - properties: this.properties - }; - - if ('id' in this) { - result.id = this.id; + _BinaryOp.prototype.isAnimated = function () { + return this.a.isAnimated() || this.b.isAnimated(); } - - return result; -}; - -// classifies an array of rings into polygons with outer rings and holes - -function classifyRings(rings) { - var len = rings.length; - - if (len <= 1) return [rings]; - - var polygons = [], - polygon, - ccw; - - for (var i = 0; i < len; i++) { - var area = signedArea(rings[i]); - if (area === 0) continue; - - if (ccw === undefined) ccw = area < 0; - - if (ccw === area < 0) { - if (polygon) polygons.push(polygon); - polygon = [rings[i]]; - + _BinaryOp.prototype.replaceChild = function (toReplace, replacer) { + if (this.a = toReplace) { + this.a = replacer; } else { - polygon.push(rings[i]); + this.b = replacer; } + replacer.parent = this; + replacer.notify = toReplace.notify; } - if (polygon) polygons.push(polygon); - - return polygons; -} - -function signedArea(ring) { - var sum = 0; - for (var i = 0, len = ring.length, j = len - 1, p1, p2; i < len; j = i++) { - p1 = ring[i]; - p2 = ring[j]; - sum += (p2.x - p1.x) * (p1.y + p2.y); + _BinaryOp.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { + genericBlend(this, finalValue, duration, blendFunc); } - return sum; + return BinaryOp; } - -/***/ }), -/* 2 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Renderer; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__shaders__ = __webpack_require__(12); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__style__ = __webpack_require__(20); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__scheme__ = __webpack_require__(25); -/* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "c", function() { return __WEBPACK_IMPORTED_MODULE_1__style__; }); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return __WEBPACK_IMPORTED_MODULE_2__scheme__["a"]; }); - - - - -// TODO remove -var gl; - -// The maximum number of features per tile is RTT_WIDTH^2, large RTT_WIDTH values can be unsupported by the hardware, -// they imply a small waste of resources too -const RTT_WIDTH = 1024; - -Renderer.prototype._initShaders = function () { - this.finalRendererProgram = __WEBPACK_IMPORTED_MODULE_0__shaders__["a" /* renderer */].createPointShader(gl); +function Animation(duration) { + return new _Animation(duration); } - -Renderer.prototype.refresh = refresh; -function refresh(timestamp) { - // Don't re-render more than once per animation frame - if (this.lastFrame == timestamp) { - return; +function _Animation(duration) { + if (!Number.isFinite(duration)) { + throw new Error("Animation only supports number literals"); } - this.lastFrame = timestamp; - var canvas = this.canvas; - var width = gl.canvas.clientWidth; - var height = gl.canvas.clientHeight; - if (gl.canvas.width != width || - gl.canvas.height != height) { - gl.canvas.width = width; - gl.canvas.height = height; + this.type = 'float'; + this.aTime = Date.now(); + this.bTime = this.aTime + Number(duration); +} +_Animation.prototype._applyToShaderSource = function (uniformIDMaker, propertyTIDMaker) { + this._uniformID = uniformIDMaker(); + return { + preface: `uniform float anim${this._uniformID};\n`, + inline: `anim${this._uniformID}` + }; +} +_Animation.prototype._postShaderCompile = function (program) { + this._uniformLocation = gl.getUniformLocation(program, `anim${this._uniformID}`); +} +_Animation.prototype._preDraw = function (l) { + const time = Date.now(); + this.mix = (time - this.aTime) / (this.bTime - this.aTime); + if (this.mix > 1.) { + gl.uniform1f(this._uniformLocation, 1); + } else { + gl.uniform1f(this._uniformLocation, this.mix); } - var aspect = canvas.clientWidth / canvas.clientHeight; - gl.clearColor(0., 0., 0., 0.);//TODO this should be a renderer property - gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); - - gl.enable(gl.CULL_FACE); - - //TODO refactor condition - gl.disable(gl.BLEND); - gl.disable(gl.DEPTH_TEST); +} +_Animation.prototype.isAnimated = function () { + return !this.mix || this.mix <= 1.; +} - if (!this.auxFB) { - this.auxFB = gl.createFramebuffer(); +function Near(property, center, threshold, falloff) { + const args = [property, center, threshold, falloff].map(implicitCast); + if (args.some(x => x === undefined || x === null)) { + throw new Error(`Invalid arguments to Near(): ${args}`); } - gl.bindFramebuffer(gl.FRAMEBUFFER, this.auxFB); - //console.log("Restyle", timestamp) - // Render To Texture - // COLOR - this.tiles.forEach(tile => { - gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tile.texColor, 0); - gl.viewport(0, 0, RTT_WIDTH, tile.height); - gl.clear(gl.COLOR_BUFFER_BIT); - - gl.useProgram(tile.style.colorShader.program); - var obj = { - freeTexUnit: 4 - } - tile.style._color._preDraw(obj); + return new _Near(...args); +} - Object.keys(tile.style.propertyColorTID).forEach((name, i) => { - gl.activeTexture(gl.TEXTURE0 + i); - gl.bindTexture(gl.TEXTURE_2D, tile.propertyTex[tile.propertyID[name]]); - gl.uniform1i(tile.style.colorShader.textureLocations[i], i); - }); - - gl.enableVertexAttribArray(this.colorShaderVertex); - gl.bindBuffer(gl.ARRAY_BUFFER, this.squareBuffer); - gl.vertexAttribPointer(tile.style.colorShader.vertexAttribute, 2, gl.FLOAT, false, 0, 0); - - gl.drawArrays(gl.TRIANGLES, 0, 3); - }); - - //WIDTH - this.tiles.forEach(tile => { - gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tile.texWidth, 0); - gl.useProgram(tile.style.widthShader.program); - gl.viewport(0, 0, RTT_WIDTH, tile.height); - gl.clear(gl.COLOR_BUFFER_BIT); - var obj = { - freeTexUnit: 4 - } - tile.style._width._preDraw(obj); - Object.keys(tile.style.propertyWidthTID).forEach((name, i) => { - gl.activeTexture(gl.TEXTURE0 + i); - gl.bindTexture(gl.TEXTURE_2D, tile.propertyTex[tile.propertyID[name]]); - gl.uniform1i(tile.style.widthShader.textureLocations[i], i); - }); - - gl.enableVertexAttribArray(tile.style.widthShader.vertexAttribute); - gl.bindBuffer(gl.ARRAY_BUFFER, this.squareBuffer); - gl.vertexAttribPointer(tile.style.widthShader.vertexAttribute, 2, gl.FLOAT, false, 0, 0); - - gl.drawArrays(gl.TRIANGLES, 0, 3); - - tile.style.updated = false; - tile.initialized = true; - }); - - - gl.enable(gl.DEPTH_TEST); - - gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); - gl.enable(gl.BLEND); - - gl.bindFramebuffer(gl.FRAMEBUFFER, null); - gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); - - gl.useProgram(this.finalRendererProgram.program); - var s = 1. / this._zoom; - - - this.tiles.forEach(tile => { - /*console.log((s / aspect) * tile.scale, - s * tile.scale, - (s / aspect) * this._center.x - tile.center.x, - s * this._center.y - tile.center.y - );*/ - gl.uniform2f(this.finalRendererProgram.vertexScaleUniformLocation, - (s / aspect) * tile.scale, - s * tile.scale); - gl.uniform2f(this.finalRendererProgram.vertexOffsetUniformLocation, - (s / aspect) * (this._center.x - tile.center.x), - s * (this._center.y - tile.center.y)); - - gl.enableVertexAttribArray(this.finalRendererProgram.vertexPositionAttribute); - gl.bindBuffer(gl.ARRAY_BUFFER, tile.vertexBuffer); - gl.vertexAttribPointer(this.finalRendererProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); +function _Near(input, center, threshold, falloff) { + if (input.type != 'float' || center.type != 'float' || threshold.type != 'float' || falloff.type != 'float') { + throw new Error('Near(): invalid parameter type'); + } + this.type = 'float'; + this.input = input; + this.center = center; + this.threshold = threshold; + this.falloff = falloff; +} +_Near.prototype._applyToShaderSource = function (uniformIDMaker, propertyTIDMaker) { + this._UID = uniformIDMaker(); + const tid = propertyTIDMaker(this.property); + const input = this.input._applyToShaderSource(uniformIDMaker, propertyTIDMaker); + const center = this.center._applyToShaderSource(uniformIDMaker, propertyTIDMaker); + const threshold = this.threshold._applyToShaderSource(uniformIDMaker, propertyTIDMaker); + const falloff = this.falloff._applyToShaderSource(uniformIDMaker, propertyTIDMaker); + return { + preface: + input.preface + center.preface + threshold.preface + falloff.preface, + inline: `1.-clamp((abs(${input.inline}-${center.inline})-${threshold.inline})/${falloff.inline}, + 0., 1.)` + }; +} +_Near.prototype._postShaderCompile = function (program) { + this.center._postShaderCompile(program); + this.threshold._postShaderCompile(program); + this.falloff._postShaderCompile(program); + this.input._postShaderCompile(program); +} +_Near.prototype._preDraw = function () { + this.center._preDraw(); + this.threshold._preDraw(); + this.falloff._preDraw(); + this.input._preDraw(); +} +_Near.prototype.isAnimated = function () { + return this.center.isAnimated(); +} - gl.enableVertexAttribArray(this.finalRendererProgram.featureIdAttr); - gl.bindBuffer(gl.ARRAY_BUFFER, tile.featureIDBuffer); - gl.vertexAttribPointer(this.finalRendererProgram.featureIdAttr, 2, gl.FLOAT, false, 0, 0); - gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, tile.texColor); - gl.uniform1i(this.finalRendererProgram.colorTexture, 0); +function Blend(a, b, mix) { + const args = [a, b, mix].map(implicitCast); + if (args.some(x => x === undefined || x === null)) { + throw new Error(`Invalid arguments to Blend(): ${args}`); + } + return new _Blend(...args); +} +function _Blend(a, b, mix) { + if (a.type == 'float' && b.type == 'float') { + this.type = 'float'; + } else if (a.type == 'color' && b.type == 'color') { + this.type = 'color'; + } else { + console.warn(a, b); + throw new Error(`Blending cannot be performed between types '${a.type}' and '${b.type}'`); + } + if (__WEBPACK_IMPORTED_MODULE_1__schema__["b" /* checkschemaMatch */](a.schema, b.schema)) { + throw new Error('Blend parameters schemas mismatch'); + } + this.schema = a.schema; + this.a = a; + this.b = b; + this.mix = mix; + a.parent = this; + b.parent = this; + mix.parent = this; +} +_Blend.prototype._applyToShaderSource = function (uniformIDMaker, propertyTIDMaker) { + const a = this.a._applyToShaderSource(uniformIDMaker, propertyTIDMaker); + const b = this.b._applyToShaderSource(uniformIDMaker, propertyTIDMaker); + const mix = this.mix._applyToShaderSource(uniformIDMaker, propertyTIDMaker); + return { + preface: `${a.preface}${b.preface}${mix.preface}`, + inline: `mix(${a.inline}, ${b.inline}, ${mix.inline})` + }; +} +_Blend.prototype._postShaderCompile = function (program) { + this.a._postShaderCompile(program); + this.b._postShaderCompile(program); + this.mix._postShaderCompile(program); +} +_Blend.prototype._preDraw = function (l) { + this.a._preDraw(l); + this.b._preDraw(l); + this.mix._preDraw(l); + if (this.mix instanceof _Animation && !this.mix.isAnimated()) { + this.parent.replaceChild(this, this.b); + } +} +_Blend.prototype.isAnimated = function () { + return this.a.isAnimated() || this.b.isAnimated() || this.mix.isAnimated(); +} +_Blend.prototype.replaceChild = function (toReplace, replacer) { + if (this.a = toReplace) { + this.a = replacer; + } else { + this.b = replacer; + } + replacer.parent = this; + replacer.notify = toReplace.notify; +} - gl.activeTexture(gl.TEXTURE1); - gl.bindTexture(gl.TEXTURE_2D, tile.texWidth); - gl.uniform1i(this.finalRendererProgram.widthTexture, 1); +function genericBlend(initial, final, duration, blendFunc) { + const parent = initial.parent; + const blend = Blend(initial, final, Animation(duration)); + parent.replaceChild(initial, blend); + blend.notify(); +} +UniformColor.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { + genericBlend(this, finalValue, duration, blendFunc); +} +_RampColor.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { + genericBlend(this, finalValue, duration, blendFunc); +} - gl.drawArrays(gl.POINTS, 0, tile.numVertex); +_Near.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { + genericBlend(this, finalValue, duration, blendFunc); +} +UniformFloat.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { + genericBlend(this, finalValue, duration, blendFunc); +} +_Blend.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { + genericBlend(this, finalValue, duration, blendFunc); +} +_Property.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { + genericBlend(this, finalValue, duration, blendFunc); +} - }); - this.tiles.forEach(t => { - if (t.style._color.isAnimated() || t.style._width.isAnimated()) { - window.requestAnimationFrame(refresh.bind(this)); +function Color(color) { + if (Array.isArray(color)) { + color = color.filter(x => true); + if (color.length != 4 || !color.every(Number.isFinite)) { + throw new Error(`Invalid arguments to Color(): ${args}`); } + return new UniformColor(color); + } + throw new Error(`Invalid arguments to Color(): ${args}`); +} +function UniformColor(color) { + this.type = 'color'; + this.color = color; +} +UniformColor.prototype._applyToShaderSource = function (uniformIDMaker) { + this._uniformID = uniformIDMaker(); + return { + preface: `uniform vec4 color${this._uniformID};\n`, + inline: `color${this._uniformID}` + }; +} +UniformColor.prototype._postShaderCompile = function (program) { + this._uniformLocation = gl.getUniformLocation(program, `color${this._uniformID}`); +} +function evalColor(color, time) { + if (Array.isArray(color)) { + return color; + } + var a = evalColor(color.a, time); + var b = evalColor(color.b, time); + var m = (time - color.aTime) / (color.bTime - color.aTime); + return a.map((va, index) => { + return (1 - m) * va + m * b[index];//TODO non linear functions }); } - -Renderer.prototype.removeTile = function (tile) { - this.tiles = this.tiles.filter(t => t !== tile); - tile.propertyTex.map(tex => gl.deleteTexture(tex)); - gl.deleteTexture(tile.texColor); - gl.deleteTexture(tile.texWidth); - gl.deleteBuffer(tile.vertexBuffer); - gl.deleteBuffer(tile.featureIDBuffer); +function simplifyColorExpr(color, time) { + if (Array.isArray(color)) { + return color; + } + var m = (time - color.aTime) / (color.bTime - color.aTime); + if (m >= 1) { + return color.b; + } + return color; +} +UniformColor.prototype._preDraw = function () { + const t = Date.now(); + this.color = simplifyColorExpr(this.color, t); + const color = evalColor(this.color, t); + gl.uniform4f(this._uniformLocation, color[0], color[1], color[2], color[3]); +} +UniformColor.prototype.isAnimated = function () { + return false; } -Renderer.prototype.addTile = function (tile) { - this.tiles.push(tile); - tile.propertyTex = []; - - var points = tile.geom; - const level = 0; - const width = RTT_WIDTH; - tile.numVertex = points.length / 2; - const height = Math.ceil(tile.numVertex / width); - const border = 0; - const srcFormat = gl.RED; - const srcType = gl.FLOAT; - tile.height = height; - tile.propertyID = {}; //Name => PID - tile.propertyCount = 0; - - - for (var k in tile.properties) { - if (tile.properties.hasOwnProperty(k) && tile.properties[k].length > 0) { - const isCategory = !Number.isFinite(tile.properties[k][0]); - const property = tile.properties[k]; - var propertyID = tile.propertyID[k]; - if (propertyID === undefined) { - propertyID = tile.propertyCount; - tile.propertyCount++; - tile.propertyID[k] = propertyID; - } - tile.propertyTex[propertyID] = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, tile.propertyTex[propertyID]); - const pixel = new Float32Array(width * height); - for (var i = 0; i < property.length; i++) { - pixel[i] = property[i]; - } - gl.texImage2D(gl.TEXTURE_2D, level, gl.ALPHA, - width, height, 0, gl.ALPHA, srcType, - pixel); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); - } +function Float(x) { + if (!Number.isFinite(x)) { + throw new Error(`Invalid arguments to Float(): ${args}`); } + return new UniformFloat(x); +} - tile.setStyle = function (style) { - __WEBPACK_IMPORTED_MODULE_2__scheme__["b" /* checkSchemeMatch */](style.scheme, tile.scheme); - this.style = style; +function UniformFloat(size) { + this.type = 'float'; + this.expr = size; +} +UniformFloat.prototype._applyToShaderSource = function (uniformIDMaker) { + this._uniformID = uniformIDMaker(); + return { + preface: `uniform float float${this._uniformID};\n`, + inline: `float${this._uniformID}` + }; +} +UniformFloat.prototype._postShaderCompile = function (program) { + this._uniformLocation = gl.getUniformLocation(program, `float${this._uniformID}`); +} +function evalFloatExpr(expr, time) { + if (Number.isFinite(expr)) { + return expr; } - tile.style = null; - - tile.vertexBuffer = gl.createBuffer(); - tile.featureIDBuffer = gl.createBuffer(); - - - tile.texColor = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, tile.texColor); - gl.texImage2D(gl.TEXTURE_2D, level, gl.RGBA, - width, height, border, gl.RGBA, gl.UNSIGNED_BYTE, - new Uint8Array(4 * width * height).fill(255)); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); - - tile.texWidth = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, tile.texWidth); - gl.texImage2D(gl.TEXTURE_2D, level, gl.RGBA, - width, height, border, gl.RGBA, gl.UNSIGNED_BYTE, - new Uint8Array(4 * width * height).fill(100)); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); - - - - var ids = new Float32Array(points.length); - for (var i = 0; i < points.length; i += 2) { - ids[i + 0] = ((i / 2) % width) / width; - ids[i + 1] = Math.floor((i / 2) / width) / height; + if (typeof expr === "function") { + return x(time); } - - gl.bindBuffer(gl.ARRAY_BUFFER, tile.vertexBuffer); - gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW); - - gl.bindBuffer(gl.ARRAY_BUFFER, tile.featureIDBuffer); - gl.bufferData(gl.ARRAY_BUFFER, ids, gl.STATIC_DRAW); - - gl.bindBuffer(gl.ARRAY_BUFFER, null); - - window.requestAnimationFrame(refresh.bind(this)); - - return tile; + return expr.eval(); } - -/** - * THIS IS A RENDERER. - * @constructor - * @param {HTMLElement} canvas - */ -function Renderer(canvas) { - this.canvas = canvas; - this.tiles = []; - if (!gl) { - gl = canvas.getContext('webgl'); - __WEBPACK_IMPORTED_MODULE_1__style__["setGL"](gl); - var ext = gl.getExtension("OES_texture_float"); - if (!ext) { - console.error("this machine or browser does not support OES_texture_float"); - } - if (!gl) { - console.warn('Unable to initialize WebGL2. Your browser may not support it.'); - return null - } - this._initShaders(); - this._center = { x: 0, y: 0 }; - this._zoom = 1; +function simplifyFloatExpr(expr, time) { + if (Number.isFinite(expr)) { + return expr; } - this.squareBuffer = gl.createBuffer(); - gl.bindBuffer(gl.ARRAY_BUFFER, this.squareBuffer); - var vertices = [ - 10.0, -10.0, - 0.0, 10.0, - -10.0, -10.0, - ]; - gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); + return expr.simplify(); +} +UniformFloat.prototype._preDraw = function (time) { + this.expr = simplifyFloatExpr(this.expr, time); + const v = evalFloatExpr(this.expr, time); + gl.uniform1f(this._uniformLocation, v); +} +UniformFloat.prototype.isAnimated = function () { + return !Number.isFinite(this.expr); } -/** - * Wadus qwuasdfdasfasd fsadfads - * @api Get Renderer center in Renderer coordinates - * @param {fff} - * @name Renderer#getCenter - */ -Renderer.prototype.getCenter = function () { - return { x: this._center.x, y: this._center.y }; -}; +function hexToRgb(hex) { + var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); + return result ? { + r: parseInt(result[1], 16), + g: parseInt(result[2], 16), + b: parseInt(result[3], 16) + } : null; +} -Renderer.prototype.setCenter = function (x, y) { - this._center.x = x; - this._center.y = y; - window.requestAnimationFrame(refresh.bind(this)); -}; -Renderer.prototype.getZoom = function () { - return this._zoom; -} -Renderer.prototype.setZoom = function (zoom) { - this._zoom = zoom; - window.requestAnimationFrame(refresh.bind(this)); +function RampColor(input, minKey, maxKey, values) { + //TODO contiunuos vs discrete should be decided based on input type => cartegory vs float + const args = [input, minKey, maxKey, values].map(implicitCast); + if (args.some(x => x === undefined || x === null)) { + throw new Error(`Invalid arguments to RampColor(): ${args}`); + } + return new _RampColor(...args); } +//Palette => used by Ramp, Ramp gets texture2D from palette by asking for number of buckets (0/interpolated palette, 2,3,4,5,6...) +function _RampColor(input, minKey, maxKey, values) { + this.type = 'color'; + this.input = input; + this.minKey = minKey.expr; + this.maxKey = maxKey.expr; + this.values = values; + this.texture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, this.texture); + const level = 0; + const internalFormat = gl.RGBA; + const width = 256; + const height = 1; + const border = 0; + const srcFormat = gl.RGBA; + const srcType = gl.UNSIGNED_BYTE; + const pixel = new Uint8Array(4 * width); + for (var i = 0; i < width; i++) { + const vlowRaw = values[Math.floor(i / width * (values.length - 1))]; + const vhighRaw = values[Math.ceil(i / width * (values.length - 1))]; + const vlow = [hexToRgb(vlowRaw).r, hexToRgb(vlowRaw).g, hexToRgb(vlowRaw).b, 255]; + const vhigh = [hexToRgb(vhighRaw).r, hexToRgb(vhighRaw).g, hexToRgb(vhighRaw).b, 255]; + const m = i / width * (values.length - 1) - Math.floor(i / width * (values.length - 1)); + const v = vlow.map((low, index) => low * (1. - m) + vhigh[index] * m); + pixel[4 * i + 0] = v[0]; + pixel[4 * i + 1] = v[1]; + pixel[4 * i + 2] = v[2]; + pixel[4 * i + 3] = v[3]; + } -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { + gl.texImage2D(gl.TEXTURE_2D, level, internalFormat, + width, height, border, srcFormat, srcType, + pixel); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); +} -module.exports.VectorTile = __webpack_require__(4); -module.exports.VectorTileFeature = __webpack_require__(1); -module.exports.VectorTileLayer = __webpack_require__(0); +_RampColor.prototype._free = function () { + gl.deleteTexture(this.texture); +} +_RampColor.prototype._applyToShaderSource = function (uniformIDMaker, propertyTIDMaker) { + this._UID = uniformIDMaker(); + const input = this.input._applyToShaderSource(uniformIDMaker, propertyTIDMaker); + return { + preface: input.preface + ` + uniform sampler2D texRamp${this._UID}; + uniform float keyMin${this._UID}; + uniform float keyWidth${this._UID}; + `, + inline: `texture2D(texRamp${this._UID}, vec2((${input.inline}-keyMin${this._UID})/keyWidth${this._UID}, 0.5)).rgba` + }; +} +_RampColor.prototype._postShaderCompile = function (program) { + this.input._postShaderCompile(program); + this._texLoc = gl.getUniformLocation(program, `texRamp${this._UID}`); + this._keyMinLoc = gl.getUniformLocation(program, `keyMin${this._UID}`); + this._keyWidthLoc = gl.getUniformLocation(program, `keyWidth${this._UID}`); +} +_RampColor.prototype._preDraw = function (l) { + this.input._preDraw(l); + gl.activeTexture(gl.TEXTURE0 + l.freeTexUnit);//TODO remove hardcode + gl.bindTexture(gl.TEXTURE_2D, this.texture); + gl.uniform1i(this._texLoc, l.freeTexUnit); + gl.uniform1f(this._keyMinLoc, evalFloatExpr(this.minKey)); + gl.uniform1f(this._keyWidthLoc, evalFloatExpr(this.maxKey) - evalFloatExpr(this.minKey)); + l.freeTexUnit++; +} +_RampColor.prototype.isAnimated = function () { + return false; +} /***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { +/* 1 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return renderer; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return styler; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__renderer__ = __webpack_require__(7); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__styler__ = __webpack_require__(9); -var VectorTileLayer = __webpack_require__(0); -module.exports = VectorTile; +const NUM_TEXTURE_LOCATIONS = 4; -function VectorTile(pbf, end) { - this.layers = pbf.readFields(readTile, {}, end); +function compileShader(gl, sourceCode, type) { + const shader = gl.createShader(type); + gl.shaderSource(shader, sourceCode); + gl.compileShader(shader); + if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { + const log = gl.getShaderInfoLog(shader); + gl.deleteShader(shader); + throw new Error('An error occurred compiling the shaders: ' + log + '\nSource:\n' + sourceCode); + } + return shader; } -function readTile(tag, layers, pbf) { - if (tag === 3) { - var layer = new VectorTileLayer(pbf, pbf.readVarint() + pbf.pos); - if (layer.length) layers[layer.name] = layer; +function compileProgram(gl, glslVS, glslFS) { + const VS = compileShader(gl, glslVS, gl.VERTEX_SHADER); + const FS = compileShader(gl, glslFS, gl.FRAGMENT_SHADER); + this.program = gl.createProgram(); + gl.attachShader(this.program, VS); + gl.attachShader(this.program, FS); + gl.linkProgram(this.program); + gl.deleteShader(VS); + gl.deleteShader(FS); + if (!gl.getProgramParameter(this.program, gl.LINK_STATUS)) { + throw new Error('Unable to link the shader program: ' + gl.getProgramInfoLog(this.program)); } } - - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -module.exports = Point; - -/** - * A standalone point geometry with useful accessor, comparison, and - * modification methods. - * - * @class Point - * @param {Number} x the x-coordinate. this could be longitude or screen - * pixels, or any other sort of unit. - * @param {Number} y the y-coordinate. this could be latitude or screen - * pixels, or any other sort of unit. - * @example - * var point = new Point(-77, 38); - */ -function Point(x, y) { - this.x = x; - this.y = y; +function Point(gl) { + compileProgram.call(this, gl, __WEBPACK_IMPORTED_MODULE_0__renderer__["a" /* point */].VS, __WEBPACK_IMPORTED_MODULE_0__renderer__["a" /* point */].FS); + this.vertexPositionAttribute = gl.getAttribLocation(this.program, 'vertexPosition'); + this.featureIdAttr = gl.getAttribLocation(this.program, 'featureID'); + this.vertexScaleUniformLocation = gl.getUniformLocation(this.program, 'vertexScale'); + this.vertexOffsetUniformLocation = gl.getUniformLocation(this.program, 'vertexOffset'); + this.colorTexture = gl.getUniformLocation(this.program, 'colorTex'); + this.widthTexture = gl.getUniformLocation(this.program, 'widthTex'); +} +function GenericStyler(gl, glsl, preface, inline) { + const VS = glsl.VS; + let FS = glsl.FS; + FS = FS.replace('$PREFACE', preface); + FS = FS.replace('$INLINE', inline); + //console.log(FS) + compileProgram.call(this, gl, VS, FS); + this.vertexAttribute = gl.getAttribLocation(this.program, 'vertex'); + this.textureLocations = []; + for (let i = 0; i < NUM_TEXTURE_LOCATIONS; i++) { + this.textureLocations[i] = gl.getUniformLocation(this.program, `property${i}`); + } +} +function Color(gl, preface, inline) { + GenericStyler.call(this, gl, __WEBPACK_IMPORTED_MODULE_1__styler__["a" /* color */], preface, inline); +} +function Width(gl, preface, inline) { + GenericStyler.call(this, gl, __WEBPACK_IMPORTED_MODULE_1__styler__["b" /* width */], preface, inline); } -Point.prototype = { - - /** - * Clone this point, returning a new point that can be modified - * without affecting the old one. - * @return {Point} the clone - */ - clone: function() { return new Point(this.x, this.y); }, - - /** - * Add this point's x & y coordinates to another point, - * yielding a new point. - * @param {Point} p the other point - * @return {Point} output point - */ - add: function(p) { return this.clone()._add(p); }, - - /** - * Subtract this point's x & y coordinates to from point, - * yielding a new point. - * @param {Point} p the other point - * @return {Point} output point - */ - sub: function(p) { return this.clone()._sub(p); }, - - /** - * Multiply this point's x & y coordinates by point, - * yielding a new point. - * @param {Point} p the other point - * @return {Point} output point - */ - multByPoint: function(p) { return this.clone()._multByPoint(p); }, - - /** - * Divide this point's x & y coordinates by point, - * yielding a new point. - * @param {Point} p the other point - * @return {Point} output point - */ - divByPoint: function(p) { return this.clone()._divByPoint(p); }, - - /** - * Multiply this point's x & y coordinates by a factor, - * yielding a new point. - * @param {Point} k factor - * @return {Point} output point - */ - mult: function(k) { return this.clone()._mult(k); }, - - /** - * Divide this point's x & y coordinates by a factor, - * yielding a new point. - * @param {Point} k factor - * @return {Point} output point - */ - div: function(k) { return this.clone()._div(k); }, - - /** - * Rotate this point around the 0, 0 origin by an angle a, - * given in radians - * @param {Number} a angle to rotate around, in radians - * @return {Point} output point - */ - rotate: function(a) { return this.clone()._rotate(a); }, - - /** - * Rotate this point around p point by an angle a, - * given in radians - * @param {Number} a angle to rotate around, in radians - * @param {Point} p Point to rotate around - * @return {Point} output point - */ - rotateAround: function(a,p) { return this.clone()._rotateAround(a,p); }, - - /** - * Multiply this point by a 4x1 transformation matrix - * @param {Array} m transformation matrix - * @return {Point} output point - */ - matMult: function(m) { return this.clone()._matMult(m); }, - - /** - * Calculate this point but as a unit vector from 0, 0, meaning - * that the distance from the resulting point to the 0, 0 - * coordinate will be equal to 1 and the angle from the resulting - * point to the 0, 0 coordinate will be the same as before. - * @return {Point} unit vector point - */ - unit: function() { return this.clone()._unit(); }, - - /** - * Compute a perpendicular point, where the new y coordinate - * is the old x coordinate and the new x coordinate is the old y - * coordinate multiplied by -1 - * @return {Point} perpendicular point - */ - perp: function() { return this.clone()._perp(); }, - - /** - * Return a version of this point with the x & y coordinates - * rounded to integers. - * @return {Point} rounded point - */ - round: function() { return this.clone()._round(); }, - - /** - * Return the magitude of this point: this is the Euclidean - * distance from the 0, 0 coordinate to this point's x and y - * coordinates. - * @return {Number} magnitude - */ - mag: function() { - return Math.sqrt(this.x * this.x + this.y * this.y); - }, +const renderer = { + createPointShader: function (gl) { + return new Point(gl); + } +}; - /** - * Judge whether this point is equal to another point, returning - * true or false. - * @param {Point} other the other point - * @return {boolean} whether the points are equal - */ - equals: function(other) { - return this.x === other.x && - this.y === other.y; +const styler = { + createColorShader: function (gl, preface, inline) { + return new Color(gl, preface, inline); }, + createWidthShader: function (gl, preface, inline) { + return new Width(gl, preface, inline); + } +}; - /** - * Calculate the distance from this point to another point - * @param {Point} p the other point - * @return {Number} distance - */ - dist: function(p) { - return Math.sqrt(this.distSqr(p)); - }, - /** - * Calculate the distance from this point to another point, - * without the square root step. Useful if you're comparing - * relative distances. - * @param {Point} p the other point - * @return {Number} distance - */ - distSqr: function(p) { - var dx = p.x - this.x, - dy = p.y - this.y; - return dx * dx + dy * dy; - }, - /** - * Get the angle from the 0, 0 coordinate to this point, in radians - * coordinates. - * @return {Number} angle - */ - angle: function() { - return Math.atan2(this.y, this.x); - }, - /** - * Get the angle from this point to another point, in radians - * @param {Point} b the other point - * @return {Number} angle - */ - angleTo: function(b) { - return Math.atan2(this.y - b.y, this.x - b.x); - }, - - /** - * Get the angle between this point and another point, in radians - * @param {Point} b the other point - * @return {Number} angle - */ - angleWith: function(b) { - return this.angleWithSep(b.x, b.y); - }, - - /* - * Find the angle of the two vectors, solving the formula for - * the cross product a x b = |a||b|sin(θ) for θ. - * @param {Number} x the x-coordinate - * @param {Number} y the y-coordinate - * @return {Number} the angle in radians - */ - angleWithSep: function(x, y) { - return Math.atan2( - this.x * y - this.y * x, - this.x * x + this.y * y); - }, - - _matMult: function(m) { - var x = m[0] * this.x + m[1] * this.y, - y = m[2] * this.x + m[3] * this.y; - this.x = x; - this.y = y; - return this; - }, - - _add: function(p) { - this.x += p.x; - this.y += p.y; - return this; - }, - - _sub: function(p) { - this.x -= p.x; - this.y -= p.y; - return this; - }, - - _mult: function(k) { - this.x *= k; - this.y *= k; - return this; - }, - - _div: function(k) { - this.x /= k; - this.y /= k; - return this; - }, - - _multByPoint: function(p) { - this.x *= p.x; - this.y *= p.y; - return this; - }, - - _divByPoint: function(p) { - this.x /= p.x; - this.y /= p.y; - return this; - }, - - _unit: function() { - this._div(this.mag()); - return this; - }, - - _perp: function() { - var y = this.y; - this.y = this.x; - this.x = -y; - return this; - }, - - _rotate: function(angle) { - var cos = Math.cos(angle), - sin = Math.sin(angle), - x = cos * this.x - sin * this.y, - y = sin * this.x + cos * this.y; - this.x = x; - this.y = y; - return this; - }, - - _rotateAround: function(angle, p) { - var cos = Math.cos(angle), - sin = Math.sin(angle), - x = p.x + cos * (this.x - p.x) - sin * (this.y - p.y), - y = p.y + sin * (this.x - p.x) + cos * (this.y - p.y); - this.x = x; - this.y = y; - return this; - }, - - _round: function() { - this.x = Math.round(this.x); - this.y = Math.round(this.y); - return this; - } -}; - -/** - * Construct a point from an array if necessary, otherwise if the input - * is already a Point, or an unknown type, return it unchanged - * @param {Array|Point|*} a any kind of input value - * @return {Point} constructed point, or passed-through value. - * @example - * // this - * var point = Point.convert([0, 1]); - * // is equivalent to - * var point = new Point(0, 1); - */ -Point.convert = function (a) { - if (a instanceof Point) { - return a; - } - if (Array.isArray(a)) { - return new Point(a[0], a[1]); - } - return a; -}; - - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -module.exports = Pbf; - -var ieee754 = __webpack_require__(7); - -function Pbf(buf) { - this.buf = ArrayBuffer.isView && ArrayBuffer.isView(buf) ? buf : new Uint8Array(buf || 0); - this.pos = 0; - this.type = 0; - this.length = this.buf.length; -} - -Pbf.Varint = 0; // varint: int32, int64, uint32, uint64, sint32, sint64, bool, enum -Pbf.Fixed64 = 1; // 64-bit: double, fixed64, sfixed64 -Pbf.Bytes = 2; // length-delimited: string, bytes, embedded messages, packed repeated fields -Pbf.Fixed32 = 5; // 32-bit: float, fixed32, sfixed32 - -var SHIFT_LEFT_32 = (1 << 16) * (1 << 16), - SHIFT_RIGHT_32 = 1 / SHIFT_LEFT_32; - -Pbf.prototype = { - - destroy: function() { - this.buf = null; - }, - - // === READING ================================================================= - - readFields: function(readField, result, end) { - end = end || this.length; - - while (this.pos < end) { - var val = this.readVarint(), - tag = val >> 3, - startPos = this.pos; - - this.type = val & 0x7; - readField(tag, result, this); - - if (this.pos === startPos) this.skip(val); - } - return result; - }, - - readMessage: function(readField, result) { - return this.readFields(readField, result, this.readVarint() + this.pos); - }, - - readFixed32: function() { - var val = readUInt32(this.buf, this.pos); - this.pos += 4; - return val; - }, - - readSFixed32: function() { - var val = readInt32(this.buf, this.pos); - this.pos += 4; - return val; - }, - - // 64-bit int handling is based on github.com/dpw/node-buffer-more-ints (MIT-licensed) - - readFixed64: function() { - var val = readUInt32(this.buf, this.pos) + readUInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32; - this.pos += 8; - return val; - }, - - readSFixed64: function() { - var val = readUInt32(this.buf, this.pos) + readInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32; - this.pos += 8; - return val; - }, - - readFloat: function() { - var val = ieee754.read(this.buf, this.pos, true, 23, 4); - this.pos += 4; - return val; - }, - - readDouble: function() { - var val = ieee754.read(this.buf, this.pos, true, 52, 8); - this.pos += 8; - return val; - }, - - readVarint: function(isSigned) { - var buf = this.buf, - val, b; - - b = buf[this.pos++]; val = b & 0x7f; if (b < 0x80) return val; - b = buf[this.pos++]; val |= (b & 0x7f) << 7; if (b < 0x80) return val; - b = buf[this.pos++]; val |= (b & 0x7f) << 14; if (b < 0x80) return val; - b = buf[this.pos++]; val |= (b & 0x7f) << 21; if (b < 0x80) return val; - b = buf[this.pos]; val |= (b & 0x0f) << 28; - - return readVarintRemainder(val, isSigned, this); - }, - - readVarint64: function() { // for compatibility with v2.0.1 - return this.readVarint(true); - }, - - readSVarint: function() { - var num = this.readVarint(); - return num % 2 === 1 ? (num + 1) / -2 : num / 2; // zigzag encoding - }, - - readBoolean: function() { - return Boolean(this.readVarint()); - }, - - readString: function() { - var end = this.readVarint() + this.pos, - str = readUtf8(this.buf, this.pos, end); - this.pos = end; - return str; - }, - - readBytes: function() { - var end = this.readVarint() + this.pos, - buffer = this.buf.subarray(this.pos, end); - this.pos = end; - return buffer; - }, - - // verbose for performance reasons; doesn't affect gzipped size - - readPackedVarint: function(arr, isSigned) { - var end = readPackedEnd(this); - arr = arr || []; - while (this.pos < end) arr.push(this.readVarint(isSigned)); - return arr; - }, - readPackedSVarint: function(arr) { - var end = readPackedEnd(this); - arr = arr || []; - while (this.pos < end) arr.push(this.readSVarint()); - return arr; - }, - readPackedBoolean: function(arr) { - var end = readPackedEnd(this); - arr = arr || []; - while (this.pos < end) arr.push(this.readBoolean()); - return arr; - }, - readPackedFloat: function(arr) { - var end = readPackedEnd(this); - arr = arr || []; - while (this.pos < end) arr.push(this.readFloat()); - return arr; - }, - readPackedDouble: function(arr) { - var end = readPackedEnd(this); - arr = arr || []; - while (this.pos < end) arr.push(this.readDouble()); - return arr; - }, - readPackedFixed32: function(arr) { - var end = readPackedEnd(this); - arr = arr || []; - while (this.pos < end) arr.push(this.readFixed32()); - return arr; - }, - readPackedSFixed32: function(arr) { - var end = readPackedEnd(this); - arr = arr || []; - while (this.pos < end) arr.push(this.readSFixed32()); - return arr; - }, - readPackedFixed64: function(arr) { - var end = readPackedEnd(this); - arr = arr || []; - while (this.pos < end) arr.push(this.readFixed64()); - return arr; - }, - readPackedSFixed64: function(arr) { - var end = readPackedEnd(this); - arr = arr || []; - while (this.pos < end) arr.push(this.readSFixed64()); - return arr; - }, - - skip: function(val) { - var type = val & 0x7; - if (type === Pbf.Varint) while (this.buf[this.pos++] > 0x7f) {} - else if (type === Pbf.Bytes) this.pos = this.readVarint() + this.pos; - else if (type === Pbf.Fixed32) this.pos += 4; - else if (type === Pbf.Fixed64) this.pos += 8; - else throw new Error('Unimplemented type: ' + type); - }, - - // === WRITING ================================================================= - - writeTag: function(tag, type) { - this.writeVarint((tag << 3) | type); - }, - - realloc: function(min) { - var length = this.length || 16; - - while (length < this.pos + min) length *= 2; - - if (length !== this.length) { - var buf = new Uint8Array(length); - buf.set(this.buf); - this.buf = buf; - this.length = length; - } - }, - - finish: function() { - this.length = this.pos; - this.pos = 0; - return this.buf.subarray(0, this.length); - }, - - writeFixed32: function(val) { - this.realloc(4); - writeInt32(this.buf, val, this.pos); - this.pos += 4; - }, - - writeSFixed32: function(val) { - this.realloc(4); - writeInt32(this.buf, val, this.pos); - this.pos += 4; - }, - - writeFixed64: function(val) { - this.realloc(8); - writeInt32(this.buf, val & -1, this.pos); - writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4); - this.pos += 8; - }, - - writeSFixed64: function(val) { - this.realloc(8); - writeInt32(this.buf, val & -1, this.pos); - writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4); - this.pos += 8; - }, - - writeVarint: function(val) { - val = +val || 0; - - if (val > 0xfffffff || val < 0) { - writeBigVarint(val, this); - return; - } - - this.realloc(4); - - this.buf[this.pos++] = val & 0x7f | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return; - this.buf[this.pos++] = ((val >>>= 7) & 0x7f) | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return; - this.buf[this.pos++] = ((val >>>= 7) & 0x7f) | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return; - this.buf[this.pos++] = (val >>> 7) & 0x7f; - }, - - writeSVarint: function(val) { - this.writeVarint(val < 0 ? -val * 2 - 1 : val * 2); - }, - - writeBoolean: function(val) { - this.writeVarint(Boolean(val)); - }, - - writeString: function(str) { - str = String(str); - this.realloc(str.length * 4); - - this.pos++; // reserve 1 byte for short string length - - var startPos = this.pos; - // write the string directly to the buffer and see how much was written - this.pos = writeUtf8(this.buf, str, this.pos); - var len = this.pos - startPos; - - if (len >= 0x80) makeRoomForExtraLength(startPos, len, this); - - // finally, write the message length in the reserved place and restore the position - this.pos = startPos - 1; - this.writeVarint(len); - this.pos += len; - }, - - writeFloat: function(val) { - this.realloc(4); - ieee754.write(this.buf, val, this.pos, true, 23, 4); - this.pos += 4; - }, - - writeDouble: function(val) { - this.realloc(8); - ieee754.write(this.buf, val, this.pos, true, 52, 8); - this.pos += 8; - }, - - writeBytes: function(buffer) { - var len = buffer.length; - this.writeVarint(len); - this.realloc(len); - for (var i = 0; i < len; i++) this.buf[this.pos++] = buffer[i]; - }, - - writeRawMessage: function(fn, obj) { - this.pos++; // reserve 1 byte for short message length - - // write the message directly to the buffer and see how much was written - var startPos = this.pos; - fn(obj, this); - var len = this.pos - startPos; - - if (len >= 0x80) makeRoomForExtraLength(startPos, len, this); - - // finally, write the message length in the reserved place and restore the position - this.pos = startPos - 1; - this.writeVarint(len); - this.pos += len; - }, - - writeMessage: function(tag, fn, obj) { - this.writeTag(tag, Pbf.Bytes); - this.writeRawMessage(fn, obj); - }, - - writePackedVarint: function(tag, arr) { this.writeMessage(tag, writePackedVarint, arr); }, - writePackedSVarint: function(tag, arr) { this.writeMessage(tag, writePackedSVarint, arr); }, - writePackedBoolean: function(tag, arr) { this.writeMessage(tag, writePackedBoolean, arr); }, - writePackedFloat: function(tag, arr) { this.writeMessage(tag, writePackedFloat, arr); }, - writePackedDouble: function(tag, arr) { this.writeMessage(tag, writePackedDouble, arr); }, - writePackedFixed32: function(tag, arr) { this.writeMessage(tag, writePackedFixed32, arr); }, - writePackedSFixed32: function(tag, arr) { this.writeMessage(tag, writePackedSFixed32, arr); }, - writePackedFixed64: function(tag, arr) { this.writeMessage(tag, writePackedFixed64, arr); }, - writePackedSFixed64: function(tag, arr) { this.writeMessage(tag, writePackedSFixed64, arr); }, - - writeBytesField: function(tag, buffer) { - this.writeTag(tag, Pbf.Bytes); - this.writeBytes(buffer); - }, - writeFixed32Field: function(tag, val) { - this.writeTag(tag, Pbf.Fixed32); - this.writeFixed32(val); - }, - writeSFixed32Field: function(tag, val) { - this.writeTag(tag, Pbf.Fixed32); - this.writeSFixed32(val); - }, - writeFixed64Field: function(tag, val) { - this.writeTag(tag, Pbf.Fixed64); - this.writeFixed64(val); - }, - writeSFixed64Field: function(tag, val) { - this.writeTag(tag, Pbf.Fixed64); - this.writeSFixed64(val); - }, - writeVarintField: function(tag, val) { - this.writeTag(tag, Pbf.Varint); - this.writeVarint(val); - }, - writeSVarintField: function(tag, val) { - this.writeTag(tag, Pbf.Varint); - this.writeSVarint(val); - }, - writeStringField: function(tag, str) { - this.writeTag(tag, Pbf.Bytes); - this.writeString(str); - }, - writeFloatField: function(tag, val) { - this.writeTag(tag, Pbf.Fixed32); - this.writeFloat(val); - }, - writeDoubleField: function(tag, val) { - this.writeTag(tag, Pbf.Fixed64); - this.writeDouble(val); - }, - writeBooleanField: function(tag, val) { - this.writeVarintField(tag, Boolean(val)); - } -}; - -function readVarintRemainder(l, s, p) { - var buf = p.buf, - h, b; - - b = buf[p.pos++]; h = (b & 0x70) >> 4; if (b < 0x80) return toNum(l, h, s); - b = buf[p.pos++]; h |= (b & 0x7f) << 3; if (b < 0x80) return toNum(l, h, s); - b = buf[p.pos++]; h |= (b & 0x7f) << 10; if (b < 0x80) return toNum(l, h, s); - b = buf[p.pos++]; h |= (b & 0x7f) << 17; if (b < 0x80) return toNum(l, h, s); - b = buf[p.pos++]; h |= (b & 0x7f) << 24; if (b < 0x80) return toNum(l, h, s); - b = buf[p.pos++]; h |= (b & 0x01) << 31; if (b < 0x80) return toNum(l, h, s); - - throw new Error('Expected varint not more than 10 bytes'); -} - -function readPackedEnd(pbf) { - return pbf.type === Pbf.Bytes ? - pbf.readVarint() + pbf.pos : pbf.pos + 1; -} - -function toNum(low, high, isSigned) { - if (isSigned) { - return high * 0x100000000 + (low >>> 0); - } - - return ((high >>> 0) * 0x100000000) + (low >>> 0); -} - -function writeBigVarint(val, pbf) { - var low, high; - - if (val >= 0) { - low = (val % 0x100000000) | 0; - high = (val / 0x100000000) | 0; - } else { - low = ~(-val % 0x100000000); - high = ~(-val / 0x100000000); - - if (low ^ 0xffffffff) { - low = (low + 1) | 0; - } else { - low = 0; - high = (high + 1) | 0; - } - } - - if (val >= 0x10000000000000000 || val < -0x10000000000000000) { - throw new Error('Given varint doesn\'t fit into 10 bytes'); - } - - pbf.realloc(10); - - writeBigVarintLow(low, high, pbf); - writeBigVarintHigh(high, pbf); -} - -function writeBigVarintLow(low, high, pbf) { - pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7; - pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7; - pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7; - pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7; - pbf.buf[pbf.pos] = low & 0x7f; -} - -function writeBigVarintHigh(high, pbf) { - var lsb = (high & 0x07) << 4; - - pbf.buf[pbf.pos++] |= lsb | ((high >>>= 3) ? 0x80 : 0); if (!high) return; - pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return; - pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return; - pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return; - pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return; - pbf.buf[pbf.pos++] = high & 0x7f; -} - -function makeRoomForExtraLength(startPos, len, pbf) { - var extraLen = - len <= 0x3fff ? 1 : - len <= 0x1fffff ? 2 : - len <= 0xfffffff ? 3 : Math.ceil(Math.log(len) / (Math.LN2 * 7)); - - // if 1 byte isn't enough for encoding message length, shift the data to the right - pbf.realloc(extraLen); - for (var i = pbf.pos - 1; i >= startPos; i--) pbf.buf[i + extraLen] = pbf.buf[i]; -} - -function writePackedVarint(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeVarint(arr[i]); } -function writePackedSVarint(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSVarint(arr[i]); } -function writePackedFloat(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFloat(arr[i]); } -function writePackedDouble(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeDouble(arr[i]); } -function writePackedBoolean(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeBoolean(arr[i]); } -function writePackedFixed32(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFixed32(arr[i]); } -function writePackedSFixed32(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSFixed32(arr[i]); } -function writePackedFixed64(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFixed64(arr[i]); } -function writePackedSFixed64(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSFixed64(arr[i]); } - -// Buffer code below from https://github.com/feross/buffer, MIT-licensed - -function readUInt32(buf, pos) { - return ((buf[pos]) | - (buf[pos + 1] << 8) | - (buf[pos + 2] << 16)) + - (buf[pos + 3] * 0x1000000); -} - -function writeInt32(buf, val, pos) { - buf[pos] = val; - buf[pos + 1] = (val >>> 8); - buf[pos + 2] = (val >>> 16); - buf[pos + 3] = (val >>> 24); -} - -function readInt32(buf, pos) { - return ((buf[pos]) | - (buf[pos + 1] << 8) | - (buf[pos + 2] << 16)) + - (buf[pos + 3] << 24); -} - -function readUtf8(buf, pos, end) { - var str = ''; - var i = pos; - - while (i < end) { - var b0 = buf[i]; - var c = null; // codepoint - var bytesPerSequence = - b0 > 0xEF ? 4 : - b0 > 0xDF ? 3 : - b0 > 0xBF ? 2 : 1; - - if (i + bytesPerSequence > end) break; - - var b1, b2, b3; - - if (bytesPerSequence === 1) { - if (b0 < 0x80) { - c = b0; - } - } else if (bytesPerSequence === 2) { - b1 = buf[i + 1]; - if ((b1 & 0xC0) === 0x80) { - c = (b0 & 0x1F) << 0x6 | (b1 & 0x3F); - if (c <= 0x7F) { - c = null; - } - } - } else if (bytesPerSequence === 3) { - b1 = buf[i + 1]; - b2 = buf[i + 2]; - if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80) { - c = (b0 & 0xF) << 0xC | (b1 & 0x3F) << 0x6 | (b2 & 0x3F); - if (c <= 0x7FF || (c >= 0xD800 && c <= 0xDFFF)) { - c = null; - } - } - } else if (bytesPerSequence === 4) { - b1 = buf[i + 1]; - b2 = buf[i + 2]; - b3 = buf[i + 3]; - if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80 && (b3 & 0xC0) === 0x80) { - c = (b0 & 0xF) << 0x12 | (b1 & 0x3F) << 0xC | (b2 & 0x3F) << 0x6 | (b3 & 0x3F); - if (c <= 0xFFFF || c >= 0x110000) { - c = null; - } - } - } - - if (c === null) { - c = 0xFFFD; - bytesPerSequence = 1; - - } else if (c > 0xFFFF) { - c -= 0x10000; - str += String.fromCharCode(c >>> 10 & 0x3FF | 0xD800); - c = 0xDC00 | c & 0x3FF; - } - - str += String.fromCharCode(c); - i += bytesPerSequence; - } - - return str; -} - -function writeUtf8(buf, str, pos) { - for (var i = 0, c, lead; i < str.length; i++) { - c = str.charCodeAt(i); // code point - - if (c > 0xD7FF && c < 0xE000) { - if (lead) { - if (c < 0xDC00) { - buf[pos++] = 0xEF; - buf[pos++] = 0xBF; - buf[pos++] = 0xBD; - lead = c; - continue; - } else { - c = lead - 0xD800 << 10 | c - 0xDC00 | 0x10000; - lead = null; - } - } else { - if (c > 0xDBFF || (i + 1 === str.length)) { - buf[pos++] = 0xEF; - buf[pos++] = 0xBF; - buf[pos++] = 0xBD; - } else { - lead = c; - } - continue; - } - } else if (lead) { - buf[pos++] = 0xEF; - buf[pos++] = 0xBF; - buf[pos++] = 0xBD; - lead = null; - } - - if (c < 0x80) { - buf[pos++] = c; - } else { - if (c < 0x800) { - buf[pos++] = c >> 0x6 | 0xC0; - } else { - if (c < 0x10000) { - buf[pos++] = c >> 0xC | 0xE0; - } else { - buf[pos++] = c >> 0x12 | 0xF0; - buf[pos++] = c >> 0xC & 0x3F | 0x80; - } - buf[pos++] = c >> 0x6 & 0x3F | 0x80; - } - buf[pos++] = c & 0x3F | 0x80; - } - } - return pos; -} - - -/***/ }), -/* 7 */ -/***/ (function(module, exports) { - -exports.read = function (buffer, offset, isLE, mLen, nBytes) { - var e, m - var eLen = nBytes * 8 - mLen - 1 - var eMax = (1 << eLen) - 1 - var eBias = eMax >> 1 - var nBits = -7 - var i = isLE ? (nBytes - 1) : 0 - var d = isLE ? -1 : 1 - var s = buffer[offset + i] - - i += d - - e = s & ((1 << (-nBits)) - 1) - s >>= (-nBits) - nBits += eLen - for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {} - - m = e & ((1 << (-nBits)) - 1) - e >>= (-nBits) - nBits += mLen - for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {} - - if (e === 0) { - e = 1 - eBias - } else if (e === eMax) { - return m ? NaN : ((s ? -1 : 1) * Infinity) - } else { - m = m + Math.pow(2, mLen) - e = e - eBias - } - return (s ? -1 : 1) * m * Math.pow(2, e - mLen) -} - -exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { - var e, m, c - var eLen = nBytes * 8 - mLen - 1 - var eMax = (1 << eLen) - 1 - var eBias = eMax >> 1 - var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0) - var i = isLE ? 0 : (nBytes - 1) - var d = isLE ? 1 : -1 - var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0 - - value = Math.abs(value) - - if (isNaN(value) || value === Infinity) { - m = isNaN(value) ? 1 : 0 - e = eMax - } else { - e = Math.floor(Math.log(value) / Math.LN2) - if (value * (c = Math.pow(2, -e)) < 1) { - e-- - c *= 2 - } - if (e + eBias >= 1) { - value += rt / c - } else { - value += rt * Math.pow(2, 1 - eBias) - } - if (value * c >= 2) { - e++ - c /= 2 - } - - if (e + eBias >= eMax) { - m = 0 - e = eMax - } else if (e + eBias >= 1) { - m = (value * c - 1) * Math.pow(2, mLen) - e = e + eBias - } else { - m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen) - e = 0 - } - } - - for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} - - e = (e << mLen) | m - eLen += mLen - for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} - - buffer[offset + i - d] |= s * 128 -} - - -/***/ }), -/* 8 */, -/* 9 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__src_index__ = __webpack_require__(2); - - -var VectorTile = __webpack_require__(3).VectorTile; -var Protobuf = __webpack_require__(6); - -var renderer; -var oldtiles = []; -var ajax; - -var style; -var scheme; - - -function styleWidth(e) { - const v = document.getElementById("widthStyleEntry").value; - try { - style.getWidth().blendTo(__WEBPACK_IMPORTED_MODULE_0__src_index__["c" /* Style */].parseStyleExpression(v, scheme), 1000); - document.getElementById("feedback").value = 'ok'; - } catch (error) { - const err = `Invalid width expression: ${error}:${error.stack}`; - console.warn(err); - document.getElementById("feedback").value = err; - } -} -function styleColor(e) { - const v = document.getElementById("colorStyleEntry").value; - try { - style.getColor().blendTo(__WEBPACK_IMPORTED_MODULE_0__src_index__["c" /* Style */].parseStyleExpression(v, scheme), 1000); - document.getElementById("feedback").value = 'ok'; - } catch (error) { - const err = `Invalid color expression: ${error}:${error.stack}`; - console.warn(err); - document.getElementById("feedback").value = err; - } -} - -function getTileList(c, iz, aspect) { - var list = []; - var z = Math.ceil(Math.log2(1. / iz)); - var x = c.x; - var y = c.y; - const numTiles = Math.pow(2, z); - function saturate(x) { - return Math.min(Math.max(x, 0), 1); - } - const minx = Math.floor(numTiles * saturate((x - iz * aspect) * 0.5 + 0.5)); - const maxx = Math.ceil(numTiles * saturate((x + iz * aspect) * 0.5 + 0.5)); - const miny = Math.floor(numTiles * saturate(1. - ((y + iz) * 0.5 + 0.5))); - const maxy = Math.ceil(numTiles * saturate(1. - ((y - iz) * 0.5 + 0.5))); - for (let i = minx; i < maxx; i++) { - for (let j = miny; j < maxy; j++) { - list.push({ - x: i, - y: j, - z: z - }); - } - } - return list; -} -function getData(aspect) { - const tiles = getTileList(renderer.getCenter(), renderer.getZoom(), aspect); - var completedTiles = []; - var needToComplete = tiles.length; - tiles.forEach(t => { - const x = t.x; - const y = t.y; - const z = t.z; - const mvt_extent = 1024; - const subpixelBufferSize = 0; - const query = - `select st_asmvt(geom, 'lid') FROM - ( - SELECT - ST_AsMVTGeom( - ST_SetSRID(ST_MakePoint(avg(ST_X(the_geom_webmercator)), avg(ST_Y(the_geom_webmercator))),3857), - CDB_XYZ_Extent(${x},${y},${z}), ${mvt_extent}, ${subpixelBufferSize}, false - ) - FROM tx_0125_copy_copy AS cdbq - WHERE the_geom_webmercator && CDB_XYZ_Extent(${x},${y},${z}) - GROUP BY ST_SnapToGrid(the_geom_webmercator, CDB_XYZ_Resolution(${z})*3.) - )AS geom - `; - var oReq = new XMLHttpRequest(); - oReq.open("GET", "https://dmanzanares-core.carto.com/api/v2/sql?q=" + encodeURIComponent(query) + "", true); - oReq.onload = function (oEvent) { - const json = JSON.parse(oReq.response); - if (json.rows[0].st_asmvt.data.length == 0) { - needToComplete--; - return; - } - var tile = new VectorTile(new Protobuf(new Uint8Array(json.rows[0].st_asmvt.data))); - const mvtLayer = tile.layers[Object.keys(tile.layers)[0]]; - var fieldMap = { - temp: 0, - daten: 1 - }; - var properties = [[new Float32Array(mvtLayer.length)], [new Float32Array(mvtLayer.length)]]; - var points = new Float32Array(mvtLayer.length * 2); - const r = Math.random(); - for (var i = 0; i < mvtLayer.length; i++) { - const f = mvtLayer.feature(i); - const geom = f.loadGeometry(); - points[2 * i + 0] = 2 * (geom[0][0].x) / mvt_extent - 1.; - points[2 * i + 1] = 2 * (1. - (geom[0][0].y) / mvt_extent) - 1.; - properties[0][i] = Number(r); - properties[1][i] = Number(Math.random()); - } - var tile = { - center: { x: ((x + 0.5) / Math.pow(2, z)) * 2. - 1, y: (1. - (y + 0.5) / Math.pow(2, z)) * 2. - 1. }, - scale: 1 / Math.pow(2, z), - count: mvtLayer.length, - geom: points, - properties: {}, - }; - Object.keys(fieldMap).map((name, pid) => { - tile.properties[name] = properties[pid]; - }); - tile.scheme = new __WEBPACK_IMPORTED_MODULE_0__src_index__["b" /* Scheme */](Object.keys(tile.properties), Object.keys(tile.properties).map(() => 'float')); - console.log(Object.keys(tile.properties), Object.keys(tile.properties).map(() => 'float'), tile.scheme); - completedTiles.push(tile); - if (completedTiles.length == needToComplete) { - oldtiles.forEach(t => renderer.removeTile(t)); - completedTiles.forEach(t => renderer.addTile(t).setStyle(style)); - oldtiles = completedTiles; - styleWidth(); - styleColor(); - } - }; - oReq.send(null); - }); -} - -const DEG2RAD = Math.PI / 180; -const EARTH_RADIUS = 6378137; -const WM_EXT = EARTH_RADIUS * Math.PI * 2; -const TILE_SIZE = 256; -// Webmercator projection -function Wmxy(latLng) { - let lat = latLng.lat * DEG2RAD; - let lng = latLng.lng * DEG2RAD; - let x = lng * EARTH_RADIUS; - let y = Math.log(Math.tan(lat / 2 + Math.PI / 4)) * EARTH_RADIUS; - return { x: x, y: y }; -} - -var mapboxgl = window.mapboxgl; -mapboxgl.accessToken = 'pk.eyJ1IjoiZG1hbnphbmFyZXMiLCJhIjoiY2o5cHRhOGg5NWdzbTJxcXltb2g2dmE5NyJ9.RVto4DnlLzQc26j9H0g9_A'; -var map = new mapboxgl.Map({ - container: 'map', // container id - style: 'mapbox://styles/dmanzanares/cj9qx712c0l7u2rpix0913d5g', // stylesheet location - center: [-74.50, 40], // starting position [lng, lat] - zoom: 0, // starting zoom, -}); -map.repaint = false; -function getZoom() { - var b = map.getBounds(); - var c = map.getCenter(); - var nw = b.getNorthWest(); - var sw = b.getSouthWest(); - var z = (Wmxy(nw).y - Wmxy(sw).y) / 40075019.834677525; - renderer.setCenter(c.lng / 180., Wmxy(c).y / 40075019.834677525 * 2.); - return z; -} - -map.on('load', _ => { - var cont = map.getCanvasContainer(); - var canvas = document.createElement('canvas') - canvas.id = 'good'; - cont.appendChild(canvas) - canvas.style.width = map.getCanvas().style.width; - canvas.style.height = map.getCanvas().style.height; - - function move() { - var b = map.getBounds(); - var nw = b.getNorthWest(); - var c = map.getCenter(); - - renderer.setCenter(c.lng / 180., Wmxy(c).y / 40075019.834677525 * 2.); - renderer.setZoom(getZoom()); - - c = renderer.getCenter(); - var z = renderer.getZoom(); - } - function moveEnd() { - move(); - getData(canvas.clientWidth / canvas.clientHeight); - }; - function resize() { - canvas.style.width = map.getCanvas().style.width; - canvas.style.height = map.getCanvas().style.height; - move(); - } - - renderer = new __WEBPACK_IMPORTED_MODULE_0__src_index__["a" /* Renderer */](canvas); - scheme = new __WEBPACK_IMPORTED_MODULE_0__src_index__["b" /* Scheme */](['temp', 'daten'], ['float', 'float']); - style = new __WEBPACK_IMPORTED_MODULE_0__src_index__["c" /* Style */].Style(renderer, scheme); - const aspect = canvas.clientWidth / canvas.clientHeight; - getData(aspect); - $('#widthStyleEntry').on('input', styleWidth); - $('#colorStyleEntry').on('input', styleColor); - move(); - - map.on('resize', resize); - map.on('movestart', move); - map.on('move', move); - map.on('moveend', moveEnd); - map.on('dragstart', move); - map.on('drag', move); - map.on('dragstart', move); - map.on('dragend', moveEnd); - map.on('zoomstart', move); - map.on('zoom', move); - map.on('zoomend', moveEnd); -}); - - -/***/ }), -/* 10 */, -/* 11 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Property", function() { return Property; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Blend", function() { return Blend; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Now", function() { return Now; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Near", function() { return Near; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Color", function() { return Color; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Float", function() { return Float; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RampColor", function() { return RampColor; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FloatMul", function() { return FloatMul; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FloatDiv", function() { return FloatDiv; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FloatAdd", function() { return FloatAdd; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FloatSub", function() { return FloatSub; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FloatPow", function() { return FloatPow; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "setGL", function() { return setGL; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "schemes", function() { return schemes; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_cartocolor__ = __webpack_require__(21); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_cartocolor___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_cartocolor__); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__scheme__ = __webpack_require__(25); - - - -function implicitCast(value) { - if (Number.isFinite(value)) { - return Float(value); - } - return value; -} -var gl = null; -function setGL(_gl) { - gl = _gl; -} - - -const schemes = {}; -Object.keys(__WEBPACK_IMPORTED_MODULE_0_cartocolor__).map(name => { - const s = __WEBPACK_IMPORTED_MODULE_0_cartocolor__[name]; - var defaultFound = false; - for (let i = 20; i >= 0; i--) { - if (s[i]) { - if (!defaultFound) { - schemes[name.toLowerCase()] = () => s[i]; - defaultFound = true; - } - schemes[`${name.toLowerCase()}_${i}`] = () => s[i]; - } - } -}); - - -/* - Each styling function should: - - Create their own objects, i.e.: be used without "new" - - Check input validity on user input (constructor and exposed functions). - - Have certain functions that never fail: - - _applyToShaderSource should use uniformIDMaker and propertyTIDMaker to get unique uniform IDs and property IDs as needed - - _postShaderCompile should get uniform location after program compilation as needed - - _preDraw should set any program's uniforms as needed - - isAnimated should return true if the function output could change depending on the timestamp - - Have a type property declaring the GLSL output type: 'float', 'color' -*/ - -/* - TODO - - Integrated color palettes - - Type checking for color palettes - - Allow multiplication, division and pow() to color expressions and color literals - - Add SetOpacity(colorExpr, opacityFloatOverride) - - HSV - - Think about uniform-only types / parameters - - Think about "Date" and "string" types. - - Heatmaps (renderer should be improved too to accommodate this) -*/ - -function Property(name, scheme) { - return new _Property(name, scheme); -} -function _Property(name, scheme) { - if (typeof name !== 'string' || name == '') { - throw new Error(`Invalid property name '${name}'`); - } - if (!scheme[name]) { - throw new Error(`Property name not found`); - } - this.name = name; - this.type = 'float'; - this.scheme = scheme; -} -_Property.prototype._applyToShaderSource = function (uniformIDMaker, propertyTIDMaker) { - return { - preface: '', - inline: `p${propertyTIDMaker(this.name)}` - }; -} -_Property.prototype._postShaderCompile = function (program) { -} -_Property.prototype._preDraw = function () { -} -_Property.prototype.isAnimated = function () { - return false; -} - -function Now(speed) { - return new _Now(speed); -} -function _Now(speed) { - if (speed == undefined) { - speed = 1; - } - if (!Number.isFinite(Number(speed))) { - throw new Error('Now() only accepts number literals'); - } - this.speed = Number(speed); - this.type = 'float'; - this.float = Float(0); -} -_Now.prototype._applyToShaderSource = function (uniformIDMaker) { - return this.float._applyToShaderSource(uniformIDMaker); -} -_Now.prototype._postShaderCompile = function (program) { - return this.float._postShaderCompile(program); -} -_Now.prototype._preDraw = function () { - this.float.expr = (Date.now() * this.speed / 1000.) % 1; - this.float._preDraw(); -} -_Now.prototype.isAnimated = function () { - return true; -} - -const FloatMul = genFloatBinaryOperation((x, y) => x * y, (x, y) => `(${x} * ${y})`); -const FloatDiv = genFloatBinaryOperation((x, y) => x / y, (x, y) => `(${x} / ${y})`); -const FloatAdd = genFloatBinaryOperation((x, y) => x + y, (x, y) => `(${x} + ${y})`); -const FloatSub = genFloatBinaryOperation((x, y) => x - y, (x, y) => `(${x} - ${y})`); -const FloatPow = genFloatBinaryOperation((x, y) => Math.pow(x, y), (x, y) => `pow(${x}, ${y})`); - -function genFloatBinaryOperation(jsFn, glsl) { - function BinaryOp(a, b) { - if (Number.isFinite(a) && Number.isFinite(b)) { - return Float(jsFn(a, b)); - } - if (Number.isFinite(a)) { - a = Float(a); - } - if (Number.isFinite(b)) { - b = Float(b); - } - if (a.type == 'float' && b.type == 'float') { - this.type = 'float'; - } else { - console.warn(a, b); - throw new Error(`Binary operation cannot be performed between '${a}' and '${b}'`); - } - return new _BinaryOp(a, b); - } - function _BinaryOp(a, b) { - this.type = 'float'; - this.a = a; - this.b = b; - a.parent = this; - b.parent = this; - } - _BinaryOp.prototype._applyToShaderSource = function (uniformIDMaker, propertyTIDMaker) { - const a = this.a._applyToShaderSource(uniformIDMaker, propertyTIDMaker); - const b = this.b._applyToShaderSource(uniformIDMaker, propertyTIDMaker); - return { - preface: a.preface + b.preface, - inline: glsl(a.inline, b.inline) - }; - } - _BinaryOp.prototype._postShaderCompile = function (program) { - this.a._postShaderCompile(program); - this.b._postShaderCompile(program); - } - _BinaryOp.prototype._preDraw = function (l) { - this.a._preDraw(l); - this.b._preDraw(l); - } - _BinaryOp.prototype.isAnimated = function () { - return this.a.isAnimated() || this.b.isAnimated(); - } - _BinaryOp.prototype.replaceChild = function (toReplace, replacer) { - if (this.a = toReplace) { - this.a = replacer; - } else { - this.b = replacer; - } - replacer.parent = this; - replacer.notify = toReplace.notify; - } - _BinaryOp.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { - genericBlend(this, finalValue, duration, blendFunc); - } - return BinaryOp; -} - -function Animation(duration) { - return new _Animation(duration); -} -function _Animation(duration) { - if (!Number.isFinite(duration)) { - throw new Error("Animation only supports number literals"); - } - this.type = 'float'; - this.aTime = Date.now(); - this.bTime = this.aTime + Number(duration); -} -_Animation.prototype._applyToShaderSource = function (uniformIDMaker, propertyTIDMaker) { - this._uniformID = uniformIDMaker(); - return { - preface: `uniform float anim${this._uniformID};\n`, - inline: `anim${this._uniformID}` - }; -} -_Animation.prototype._postShaderCompile = function (program) { - this._uniformLocation = gl.getUniformLocation(program, `anim${this._uniformID}`); -} -_Animation.prototype._preDraw = function (l) { - const time = Date.now(); - this.mix = (time - this.aTime) / (this.bTime - this.aTime); - if (this.mix > 1.) { - gl.uniform1f(this._uniformLocation, 1); - } else { - gl.uniform1f(this._uniformLocation, this.mix); - } -} -_Animation.prototype.isAnimated = function () { - return !this.mix || this.mix <= 1.; -} - -function Near(property, center, threshold, falloff) { - const args = [property, center, threshold, falloff].map(implicitCast); - if (args.some(x => x === undefined || x === null)) { - throw new Error(`Invalid arguments to Near(): ${args}`); - } - return new _Near(...args); -} - -function _Near(input, center, threshold, falloff) { - if (input.type != 'float' || center.type != 'float' || threshold.type != 'float' || falloff.type != 'float') { - throw new Error('Near(): invalid parameter type'); - } - this.type = 'float'; - this.input = input; - this.center = center; - this.threshold = threshold; - this.falloff = falloff; -} -_Near.prototype._applyToShaderSource = function (uniformIDMaker, propertyTIDMaker) { - this._UID = uniformIDMaker(); - const tid = propertyTIDMaker(this.property); - const input = this.input._applyToShaderSource(uniformIDMaker, propertyTIDMaker); - const center = this.center._applyToShaderSource(uniformIDMaker, propertyTIDMaker); - const threshold = this.threshold._applyToShaderSource(uniformIDMaker, propertyTIDMaker); - const falloff = this.falloff._applyToShaderSource(uniformIDMaker, propertyTIDMaker); - return { - preface: - input.preface + center.preface + threshold.preface + falloff.preface, - inline: `1.-clamp((abs(${input.inline}-${center.inline})-${threshold.inline})/${falloff.inline}, - 0., 1.)` - }; -} -_Near.prototype._postShaderCompile = function (program) { - this.center._postShaderCompile(program); - this.threshold._postShaderCompile(program); - this.falloff._postShaderCompile(program); - this.input._postShaderCompile(program); -} -_Near.prototype._preDraw = function () { - this.center._preDraw(); - this.threshold._preDraw(); - this.falloff._preDraw(); - this.input._preDraw(); -} -_Near.prototype.isAnimated = function () { - return this.center.isAnimated(); -} - - - -function Blend(a, b, mix) { - const args = [a, b, mix].map(implicitCast); - if (args.some(x => x === undefined || x === null)) { - throw new Error(`Invalid arguments to Blend(): ${args}`); - } - return new _Blend(...args); -} -function _Blend(a, b, mix) { - if (a.type == 'float' && b.type == 'float') { - this.type = 'float'; - } else if (a.type == 'color' && b.type == 'color') { - this.type = 'color'; - } else { - console.warn(a, b); - throw new Error(`Blending cannot be performed between types '${a.type}' and '${b.type}'`); - } - if (__WEBPACK_IMPORTED_MODULE_1__scheme__["b" /* checkSchemeMatch */](a.scheme, b.scheme)) { - throw new Error('Blend parameters schemes mismatch'); - } - this.scheme = a.scheme; - this.a = a; - this.b = b; - this.mix = mix; - a.parent = this; - b.parent = this; - mix.parent = this; -} -_Blend.prototype._applyToShaderSource = function (uniformIDMaker, propertyTIDMaker) { - const a = this.a._applyToShaderSource(uniformIDMaker, propertyTIDMaker); - const b = this.b._applyToShaderSource(uniformIDMaker, propertyTIDMaker); - const mix = this.mix._applyToShaderSource(uniformIDMaker, propertyTIDMaker); - return { - preface: `${a.preface}${b.preface}${mix.preface}`, - inline: `mix(${a.inline}, ${b.inline}, ${mix.inline})` - }; -} -_Blend.prototype._postShaderCompile = function (program) { - this.a._postShaderCompile(program); - this.b._postShaderCompile(program); - this.mix._postShaderCompile(program); -} -_Blend.prototype._preDraw = function (l) { - this.a._preDraw(l); - this.b._preDraw(l); - this.mix._preDraw(l); - if (this.mix instanceof _Animation && !this.mix.isAnimated()) { - this.parent.replaceChild(this, this.b); - } -} -_Blend.prototype.isAnimated = function () { - return this.a.isAnimated() || this.b.isAnimated() || this.mix.isAnimated(); -} -_Blend.prototype.replaceChild = function (toReplace, replacer) { - if (this.a = toReplace) { - this.a = replacer; - } else { - this.b = replacer; - } - replacer.parent = this; - replacer.notify = toReplace.notify; -} - -function genericBlend(initial, final, duration, blendFunc) { - const parent = initial.parent; - const blend = Blend(initial, final, Animation(duration)); - parent.replaceChild(initial, blend); - blend.notify(); -} -UniformColor.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { - genericBlend(this, finalValue, duration, blendFunc); -} -_RampColor.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { - genericBlend(this, finalValue, duration, blendFunc); -} - -_Near.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { - genericBlend(this, finalValue, duration, blendFunc); -} -UniformFloat.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { - genericBlend(this, finalValue, duration, blendFunc); -} -_Blend.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { - genericBlend(this, finalValue, duration, blendFunc); -} -_Property.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { - genericBlend(this, finalValue, duration, blendFunc); -} - - -function Color(color) { - if (Array.isArray(color)) { - color = color.filter(x => true); - if (color.length != 4 || !color.every(Number.isFinite)) { - throw new Error(`Invalid arguments to Color(): ${args}`); - } - return new UniformColor(color); - } - throw new Error(`Invalid arguments to Color(): ${args}`); -} -function UniformColor(color) { - this.type = 'color'; - this.color = color; -} -UniformColor.prototype._applyToShaderSource = function (uniformIDMaker) { - this._uniformID = uniformIDMaker(); - return { - preface: `uniform vec4 color${this._uniformID};\n`, - inline: `color${this._uniformID}` - }; -} -UniformColor.prototype._postShaderCompile = function (program) { - this._uniformLocation = gl.getUniformLocation(program, `color${this._uniformID}`); -} -function evalColor(color, time) { - if (Array.isArray(color)) { - return color; - } - var a = evalColor(color.a, time); - var b = evalColor(color.b, time); - var m = (time - color.aTime) / (color.bTime - color.aTime); - return a.map((va, index) => { - return (1 - m) * va + m * b[index];//TODO non linear functions - }); -} -function simplifyColorExpr(color, time) { - if (Array.isArray(color)) { - return color; - } - var m = (time - color.aTime) / (color.bTime - color.aTime); - if (m >= 1) { - return color.b; - } - return color; -} -UniformColor.prototype._preDraw = function () { - const t = Date.now(); - this.color = simplifyColorExpr(this.color, t); - const color = evalColor(this.color, t); - gl.uniform4f(this._uniformLocation, color[0], color[1], color[2], color[3]); -} -UniformColor.prototype.isAnimated = function () { - return false; -} - -function Float(x) { - if (!Number.isFinite(x)) { - throw new Error(`Invalid arguments to Float(): ${args}`); - } - return new UniformFloat(x); -} - -function UniformFloat(size) { - this.type = 'float'; - this.expr = size; -} -UniformFloat.prototype._applyToShaderSource = function (uniformIDMaker) { - this._uniformID = uniformIDMaker(); - return { - preface: `uniform float float${this._uniformID};\n`, - inline: `float${this._uniformID}` - }; -} -UniformFloat.prototype._postShaderCompile = function (program) { - this._uniformLocation = gl.getUniformLocation(program, `float${this._uniformID}`); -} -function evalFloatExpr(expr, time) { - if (Number.isFinite(expr)) { - return expr; - } - if (typeof expr === "function") { - return x(time); - } - return expr.eval(); -} -function simplifyFloatExpr(expr, time) { - if (Number.isFinite(expr)) { - return expr; - } - return expr.simplify(); -} -UniformFloat.prototype._preDraw = function (time) { - this.expr = simplifyFloatExpr(this.expr, time); - const v = evalFloatExpr(this.expr, time); - gl.uniform1f(this._uniformLocation, v); -} -UniformFloat.prototype.isAnimated = function () { - return !Number.isFinite(this.expr); -} - -function hexToRgb(hex) { - var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); - return result ? { - r: parseInt(result[1], 16), - g: parseInt(result[2], 16), - b: parseInt(result[3], 16) - } : null; -} - - -function RampColor(input, minKey, maxKey, values) { - //TODO contiunuos vs discrete should be decided based on input type => cartegory vs float - const args = [input, minKey, maxKey, values].map(implicitCast); - if (args.some(x => x === undefined || x === null)) { - throw new Error(`Invalid arguments to RampColor(): ${args}`); - } - return new _RampColor(...args); -} - -//Palette => used by Ramp, Ramp gets texture2D from palette by asking for number of buckets (0/interpolated palette, 2,3,4,5,6...) -function _RampColor(input, minKey, maxKey, values) { - this.type = 'color'; - this.input = input; - this.minKey = minKey.expr; - this.maxKey = maxKey.expr; - this.values = values; - - this.texture = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, this.texture); - const level = 0; - const internalFormat = gl.RGBA; - const width = 256; - const height = 1; - const border = 0; - const srcFormat = gl.RGBA; - const srcType = gl.UNSIGNED_BYTE; - const pixel = new Uint8Array(4 * width); - for (var i = 0; i < width; i++) { - const vlowRaw = values[Math.floor(i / width * (values.length - 1))]; - const vhighRaw = values[Math.ceil(i / width * (values.length - 1))]; - const vlow = [hexToRgb(vlowRaw).r, hexToRgb(vlowRaw).g, hexToRgb(vlowRaw).b, 255]; - const vhigh = [hexToRgb(vhighRaw).r, hexToRgb(vhighRaw).g, hexToRgb(vhighRaw).b, 255]; - const m = i / width * (values.length - 1) - Math.floor(i / width * (values.length - 1)); - const v = vlow.map((low, index) => low * (1. - m) + vhigh[index] * m); - pixel[4 * i + 0] = v[0]; - pixel[4 * i + 1] = v[1]; - pixel[4 * i + 2] = v[2]; - pixel[4 * i + 3] = v[3]; - } - - - gl.texImage2D(gl.TEXTURE_2D, level, internalFormat, - width, height, border, srcFormat, srcType, - pixel); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); -} - -_RampColor.prototype._free = function () { - gl.deleteTexture(this.texture); -} -_RampColor.prototype._applyToShaderSource = function (uniformIDMaker, propertyTIDMaker) { - this._UID = uniformIDMaker(); - const input = this.input._applyToShaderSource(uniformIDMaker, propertyTIDMaker); - return { - preface: input.preface + ` - uniform sampler2D texRamp${this._UID}; - uniform float keyMin${this._UID}; - uniform float keyWidth${this._UID}; - `, - inline: `texture2D(texRamp${this._UID}, vec2((${input.inline}-keyMin${this._UID})/keyWidth${this._UID}, 0.5)).rgba` - }; -} -_RampColor.prototype._postShaderCompile = function (program) { - this.input._postShaderCompile(program); - this._texLoc = gl.getUniformLocation(program, `texRamp${this._UID}`); - this._keyMinLoc = gl.getUniformLocation(program, `keyMin${this._UID}`); - this._keyWidthLoc = gl.getUniformLocation(program, `keyWidth${this._UID}`); -} -_RampColor.prototype._preDraw = function (l) { - this.input._preDraw(l); - gl.activeTexture(gl.TEXTURE0 + l.freeTexUnit);//TODO remove hardcode - gl.bindTexture(gl.TEXTURE_2D, this.texture); - gl.uniform1i(this._texLoc, l.freeTexUnit); - gl.uniform1f(this._keyMinLoc, evalFloatExpr(this.minKey)); - gl.uniform1f(this._keyWidthLoc, evalFloatExpr(this.maxKey) - evalFloatExpr(this.minKey)); - l.freeTexUnit++; -} -_RampColor.prototype.isAnimated = function () { - return false; -} - - -/***/ }), -/* 12 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return renderer; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return styler; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__renderer__ = __webpack_require__(15); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__styler__ = __webpack_require__(17); - - - -const NUM_TEXTURE_LOCATIONS = 4; - -function compileShader(gl, sourceCode, type) { - const shader = gl.createShader(type); - gl.shaderSource(shader, sourceCode); - gl.compileShader(shader); - if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { - const log = gl.getShaderInfoLog(shader); - gl.deleteShader(shader); - throw new Error('An error occurred compiling the shaders: ' + log + '\nSource:\n' + sourceCode); - } - return shader; -} - -function compileProgram(gl, glslVS, glslFS) { - const VS = compileShader(gl, glslVS, gl.VERTEX_SHADER); - const FS = compileShader(gl, glslFS, gl.FRAGMENT_SHADER); - this.program = gl.createProgram(); - gl.attachShader(this.program, VS); - gl.attachShader(this.program, FS); - gl.linkProgram(this.program); - gl.deleteShader(VS); - gl.deleteShader(FS); - if (!gl.getProgramParameter(this.program, gl.LINK_STATUS)) { - throw new Error('Unable to link the shader program: ' + gl.getProgramInfoLog(this.program)); - } -} - -function Point(gl) { - compileProgram.call(this, gl, __WEBPACK_IMPORTED_MODULE_0__renderer__["a" /* point */].VS, __WEBPACK_IMPORTED_MODULE_0__renderer__["a" /* point */].FS); - this.vertexPositionAttribute = gl.getAttribLocation(this.program, 'vertexPosition'); - this.featureIdAttr = gl.getAttribLocation(this.program, 'featureID'); - this.vertexScaleUniformLocation = gl.getUniformLocation(this.program, 'vertexScale'); - this.vertexOffsetUniformLocation = gl.getUniformLocation(this.program, 'vertexOffset'); - this.colorTexture = gl.getUniformLocation(this.program, 'colorTex'); - this.widthTexture = gl.getUniformLocation(this.program, 'widthTex'); -} -function GenericStyler(gl, glsl, preface, inline) { - const VS = glsl.VS; - let FS = glsl.FS; - FS = FS.replace('$PREFACE', preface); - FS = FS.replace('$INLINE', inline); - console.log(FS) - compileProgram.call(this, gl, VS, FS); - this.vertexAttribute = gl.getAttribLocation(this.program, 'vertex'); - this.textureLocations = []; - for (let i = 0; i < NUM_TEXTURE_LOCATIONS; i++) { - this.textureLocations[i] = gl.getUniformLocation(this.program, `property${i}`); - } -} -function Color(gl, preface, inline) { - GenericStyler.call(this, gl, __WEBPACK_IMPORTED_MODULE_1__styler__["a" /* color */], preface, inline); -} -function Width(gl, preface, inline) { - GenericStyler.call(this, gl, __WEBPACK_IMPORTED_MODULE_1__styler__["b" /* width */], preface, inline); -} - -const renderer = { - createPointShader: function (gl) { - return new Point(gl); - } -}; - -const styler = { - createColorShader: function (gl, preface, inline) { - return new Color(gl, preface, inline); - }, - createWidthShader: function (gl, preface, inline) { - return new Width(gl, preface, inline); - } -}; - - - - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { +/***/ }), +/* 2 */ +/***/ (function(module, exports, __webpack_require__) { // JavaScript Expression Parser (JSEP) 0.3.2 // JSEP may be freely distributed under the MIT License @@ -3329,100 +1403,806 @@ const styler = { }(this)); -/***/ }), -/* 14 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +/***/ }), +/* 3 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (immutable) */ __webpack_exports__["a"] = parseStyleExpression; +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_jsep__ = __webpack_require__(2); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_jsep___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_jsep__); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__functions__ = __webpack_require__(0); + + + + +//TODO document style expressions +//TODO create complete style API, a way to define a color and a width style at the same time, we just have style expressions now +/* + Returns a valid style expression or throws an exception upon invalid inputs. +*/ +var lowerCaseFunctions = {}; +Object.keys(__WEBPACK_IMPORTED_MODULE_1__functions__).map(name => { + lowerCaseFunctions[name.toLocaleLowerCase()] = __WEBPACK_IMPORTED_MODULE_1__functions__[name]; +}); + +/** + * @api + * @param {*} str + * @param {*} schema + */ +function parseStyleExpression(str, schema) { + // jsep addBinaryOp pollutes its module scope, we need to remove the custom operators afterwards + __WEBPACK_IMPORTED_MODULE_0_jsep___default.a.addBinaryOp("^", 10); + const r = parseNode(__WEBPACK_IMPORTED_MODULE_0_jsep___default()(str), schema); + __WEBPACK_IMPORTED_MODULE_0_jsep___default.a.removeBinaryOp("^"); + return r; +} + +function parseNode(node, schema) { + if (node.type == 'CallExpression') { + const args = node.arguments.map(arg => parseNode(arg, schema)); + const name = node.callee.name.toLowerCase(); + if (lowerCaseFunctions[name]) { + return lowerCaseFunctions[name](...args, schema); + } + throw new Error(`Invalid function name '${node.callee.name}'`); + } else if (node.type == 'Literal') { + return node.value; + } else if (node.type == 'ArrayExpression') { + return node.elements.map(e => parseNode(e, schema)); + } else if (node.type == 'BinaryExpression') { + const left = parseNode(node.left, schema); + const right = parseNode(node.right, schema); + switch (node.operator) { + case "*": + return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatMul"](left, right, schema); + case "/": + return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatDiv"](left, right, schema); + case "+": + return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatAdd"](left, right, schema); + case "-": + return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatSub"](left, right, schema); + case "^": + return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatPow"](left, right, schema); + default: + throw new Error(`Invalid binary operator '${node.operator}'`); + } + } else if (node.type == 'UnaryExpression') { + switch (node.operator) { + case '-': + return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatMul"](-1, parseNode(node.argument, schema)); + case '+': + return parseNode(node.argument, schema); + default: + throw new Error(`Invalid unary operator '${node.operator}'`); + } + } else if (node.type == 'Identifier') { + if (node.name[0] == '$') { + return __WEBPACK_IMPORTED_MODULE_1__functions__["Property"](node.name.substring(1), schema); + } else if (__WEBPACK_IMPORTED_MODULE_1__functions__["schemas"][node.name.toLowerCase()]) { + return __WEBPACK_IMPORTED_MODULE_1__functions__["schemas"][node.name.toLowerCase()](); + } + } + throw new Error(`Invalid expression '${JSON.stringify(node)}'`); +} + + + + +/***/ }), +/* 4 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var VectorTileFeature = __webpack_require__(5); + +module.exports = VectorTileLayer; + +function VectorTileLayer(pbf, end) { + // Public + this.version = 1; + this.name = null; + this.extent = 4096; + this.length = 0; + + // Private + this._pbf = pbf; + this._keys = []; + this._values = []; + this._features = []; + + pbf.readFields(readLayer, this, end); + + this.length = this._features.length; +} + +function readLayer(tag, layer, pbf) { + if (tag === 15) layer.version = pbf.readVarint(); + else if (tag === 1) layer.name = pbf.readString(); + else if (tag === 5) layer.extent = pbf.readVarint(); + else if (tag === 2) layer._features.push(pbf.pos); + else if (tag === 3) layer._keys.push(pbf.readString()); + else if (tag === 4) layer._values.push(readValueMessage(pbf)); +} + +function readValueMessage(pbf) { + var value = null, + end = pbf.readVarint() + pbf.pos; + + while (pbf.pos < end) { + var tag = pbf.readVarint() >> 3; + + value = tag === 1 ? pbf.readString() : + tag === 2 ? pbf.readFloat() : + tag === 3 ? pbf.readDouble() : + tag === 4 ? pbf.readVarint64() : + tag === 5 ? pbf.readVarint() : + tag === 6 ? pbf.readSVarint() : + tag === 7 ? pbf.readBoolean() : null; + } + + return value; +} + +// return feature `i` from this layer as a `VectorTileFeature` +VectorTileLayer.prototype.feature = function(i) { + if (i < 0 || i >= this._features.length) throw new Error('feature index out of bounds'); + + this._pbf.pos = this._features[i]; + + var end = this._pbf.readVarint() + this._pbf.pos; + return new VectorTileFeature(this._pbf, end, this.extent, this._keys, this._values); +}; + + +/***/ }), +/* 5 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var Point = __webpack_require__(20); + +module.exports = VectorTileFeature; + +function VectorTileFeature(pbf, end, extent, keys, values) { + // Public + this.properties = {}; + this.extent = extent; + this.type = 0; + + // Private + this._pbf = pbf; + this._geometry = -1; + this._keys = keys; + this._values = values; + + pbf.readFields(readFeature, this, end); +} + +function readFeature(tag, feature, pbf) { + if (tag == 1) feature.id = pbf.readVarint(); + else if (tag == 2) readTag(pbf, feature); + else if (tag == 3) feature.type = pbf.readVarint(); + else if (tag == 4) feature._geometry = pbf.pos; +} + +function readTag(pbf, feature) { + var end = pbf.readVarint() + pbf.pos; + + while (pbf.pos < end) { + var key = feature._keys[pbf.readVarint()], + value = feature._values[pbf.readVarint()]; + feature.properties[key] = value; + } +} + +VectorTileFeature.types = ['Unknown', 'Point', 'LineString', 'Polygon']; + +VectorTileFeature.prototype.loadGeometry = function() { + var pbf = this._pbf; + pbf.pos = this._geometry; + + var end = pbf.readVarint() + pbf.pos, + cmd = 1, + length = 0, + x = 0, + y = 0, + lines = [], + line; + + while (pbf.pos < end) { + if (!length) { + var cmdLen = pbf.readVarint(); + cmd = cmdLen & 0x7; + length = cmdLen >> 3; + } + + length--; + + if (cmd === 1 || cmd === 2) { + x += pbf.readSVarint(); + y += pbf.readSVarint(); + + if (cmd === 1) { // moveTo + if (line) lines.push(line); + line = []; + } + + line.push(new Point(x, y)); + + } else if (cmd === 7) { + + // Workaround for https://github.com/mapbox/mapnik-vector-tile/issues/90 + if (line) { + line.push(line[0].clone()); // closePolygon + } + + } else { + throw new Error('unknown command ' + cmd); + } + } + + if (line) lines.push(line); + + return lines; +}; + +VectorTileFeature.prototype.bbox = function() { + var pbf = this._pbf; + pbf.pos = this._geometry; + + var end = pbf.readVarint() + pbf.pos, + cmd = 1, + length = 0, + x = 0, + y = 0, + x1 = Infinity, + x2 = -Infinity, + y1 = Infinity, + y2 = -Infinity; + + while (pbf.pos < end) { + if (!length) { + var cmdLen = pbf.readVarint(); + cmd = cmdLen & 0x7; + length = cmdLen >> 3; + } + + length--; + + if (cmd === 1 || cmd === 2) { + x += pbf.readSVarint(); + y += pbf.readSVarint(); + if (x < x1) x1 = x; + if (x > x2) x2 = x; + if (y < y1) y1 = y; + if (y > y2) y2 = y; + + } else if (cmd !== 7) { + throw new Error('unknown command ' + cmd); + } + } + + return [x1, y1, x2, y2]; +}; + +VectorTileFeature.prototype.toGeoJSON = function(x, y, z) { + var size = this.extent * Math.pow(2, z), + x0 = this.extent * x, + y0 = this.extent * y, + coords = this.loadGeometry(), + type = VectorTileFeature.types[this.type], + i, j; + + function project(line) { + for (var j = 0; j < line.length; j++) { + var p = line[j], y2 = 180 - (p.y + y0) * 360 / size; + line[j] = [ + (p.x + x0) * 360 / size - 180, + 360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90 + ]; + } + } + + switch (this.type) { + case 1: + var points = []; + for (i = 0; i < coords.length; i++) { + points[i] = coords[i][0]; + } + coords = points; + project(coords); + break; + + case 2: + for (i = 0; i < coords.length; i++) { + project(coords[i]); + } + break; + + case 3: + coords = classifyRings(coords); + for (i = 0; i < coords.length; i++) { + for (j = 0; j < coords[i].length; j++) { + project(coords[i][j]); + } + } + break; + } + + if (coords.length === 1) { + coords = coords[0]; + } else { + type = 'Multi' + type; + } + + var result = { + type: "Feature", + geometry: { + type: type, + coordinates: coords + }, + properties: this.properties + }; + + if ('id' in this) { + result.id = this.id; + } + + return result; +}; + +// classifies an array of rings into polygons with outer rings and holes + +function classifyRings(rings) { + var len = rings.length; + + if (len <= 1) return [rings]; + + var polygons = [], + polygon, + ccw; + + for (var i = 0; i < len; i++) { + var area = signedArea(rings[i]); + if (area === 0) continue; + + if (ccw === undefined) ccw = area < 0; + + if (ccw === area < 0) { + if (polygon) polygons.push(polygon); + polygon = [rings[i]]; + + } else { + polygon.push(rings[i]); + } + } + if (polygon) polygons.push(polygon); + + return polygons; +} + +function signedArea(ring) { + var sum = 0; + for (var i = 0, len = ring.length, j = len - 1, p1, p2; i < len; j = i++) { + p1 = ring[i]; + p2 = ring[j]; + sum += (p2.x - p1.x) * (p1.y + p2.y); + } + return sum; +} + + +/***/ }), +/* 6 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Renderer; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__shaders__ = __webpack_require__(1); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__style__ = __webpack_require__(12); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__schema__ = __webpack_require__(17); +/* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "c", function() { return __WEBPACK_IMPORTED_MODULE_1__style__; }); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return __WEBPACK_IMPORTED_MODULE_2__schema__["a"]; }); + + + + + + + +/** + * @api + * @typedef {object} RPoint - Point in renderer coordinates space + * @property {number} x + * @property {number} y + */ + + /** + * @api + * @typedef {object} Dataframe - Point in renderer coordinates space + * @property {RPoint} center + * @property {number} scale + * @property {geom} geometry + * @property {Properties} properties + */ + + +// TODO remove +var gl; + +/** + * @description The Render To Texture Width limits the maximum number of features per tile: *maxFeatureCount = RTT_WIDTH^2* + * + * Large RTT_WIDTH values are unsupported by hardware. Limits vary on each machine. + * Support starts to drop from 2048, with a drastic reduction in support for more than 4096 pixels. + * + * Large values imply a small overhead too. + */ +const RTT_WIDTH = 1024; + + +/** + * @description Renderer constructor. Use it to create a new renderer bound to the provided canvas. + * Initialization will be done synchronously. + * The function will fail in case that a WebGL context cannot be created this can happen because of the following reasons: + * * The provided canvas element is invalid + * * The browser or the machine doesn't support WebGL or the required WebGL extension and minimum parameter values + * @api + * @memberOf renderer + * @constructor + * @param {HTMLElement} canvas - the WebGL context will be created on this element + */ +function Renderer(canvas) { + this.canvas = canvas; + this.tiles = []; + if (!gl) { //TODO remove hack: remove global context + gl = canvas.getContext('webgl'); + if (!gl) { + throw new Error("WebGL extension OES_texture_float is unsupported"); + } + var ext = gl.getExtension("OES_texture_float"); + if (!ext) { + throw new Error("WebGL extension OES_texture_float is unsupported"); + } + const supportedRTT = gl.getParameter(gl.MAX_RENDERBUFFER_SIZE); + if (supportedRTT < RTT_WIDTH) { + throw new Error(`WebGL parameter 'gl.MAX_RENDERBUFFER_SIZE' is below the requirement: ${supportedRTT} < ${RTT_WIDTH}`); + } + __WEBPACK_IMPORTED_MODULE_1__style__["setGL"](gl); + this._initShaders(); + this._center = { x: 0, y: 0 }; + this._zoom = 1; + } + this.squareBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, this.squareBuffer); + var vertices = [ + 10.0, -10.0, + 0.0, 10.0, + -10.0, -10.0, + ]; + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); +} + +/** + * Get Renderer visualization center + * @api + * @return {RPoint} + */ +Renderer.prototype.getCenter = function () { + return { x: this._center.x, y: this._center.y }; +}; +/** + * Set Renderer visualization center + * @api + * @param {number} x + * @param {number} y + */ +Renderer.prototype.setCenter = function (x, y) { + this._center.x = x; + this._center.y = y; + window.requestAnimationFrame(refresh.bind(this)); +}; +/** + * Get Renderer visualization zoom + * @api + * @return {number} + */ +Renderer.prototype.getZoom = function () { + return this._zoom; +}; +/** + * Set Renderer visualization zoom + * @api + * @param {number} zoom + */ +Renderer.prototype.setZoom = function (zoom) { + this._zoom = zoom; + window.requestAnimationFrame(refresh.bind(this)); +}; + +/** + * Removes a dataframe for the renderer. Freeing its resources. + * @api + * @param {*} tile + */ +Renderer.prototype.removeDataframe = function (dataframe) { + this.tiles = this.tiles.filter(t => t !== dataframe); + dataframe.propertyTex.map(tex => gl.deleteTexture(tex)); + gl.deleteTexture(dataframe.texColor); + gl.deleteTexture(dataframe.texWidth); + gl.deleteBuffer(dataframe.vertexBuffer); + gl.deleteBuffer(dataframe.featureIDBuffer); +}; + +/** + * @api + * @description Adds a new dataframe to the renderer. + * + * Performance-intensive. The required allocation and copy of resources will happen synchronously. + * To achieve good performance, avoid multiple calls within the same event, particularly with large dataframes. + * @param {Dataframe} dataframe + */ +Renderer.prototype.addDataframe = function (tile) { + this.tiles.push(tile); + tile.propertyTex = []; + + var points = tile.geom; + const level = 0; + const width = RTT_WIDTH; + tile.numVertex = points.length / 2; + const height = Math.ceil(tile.numVertex / width); + const border = 0; + const srcFormat = gl.RED; + const srcType = gl.FLOAT; + tile.height = height; + tile.propertyID = {}; //Name => PID + tile.propertyCount = 0; + + + for (var k in tile.properties) { + if (tile.properties.hasOwnProperty(k) && tile.properties[k].length > 0) { + const isCategory = !Number.isFinite(tile.properties[k][0]); + const property = tile.properties[k]; + var propertyID = tile.propertyID[k]; + if (propertyID === undefined) { + propertyID = tile.propertyCount; + tile.propertyCount++; + tile.propertyID[k] = propertyID; + } + tile.propertyTex[propertyID] = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tile.propertyTex[propertyID]); + const pixel = new Float32Array(width * height); + for (var i = 0; i < property.length; i++) { + pixel[i] = property[i]; + } + gl.texImage2D(gl.TEXTURE_2D, level, gl.ALPHA, + width, height, 0, gl.ALPHA, srcType, + pixel); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + } + } + + tile.setStyle = function (style) { + __WEBPACK_IMPORTED_MODULE_2__schema__["b" /* checkschemaMatch */](style.schema, tile.schema); + this.style = style; + } + tile.style = null; + + tile.vertexBuffer = gl.createBuffer(); + tile.featureIDBuffer = gl.createBuffer(); + + + tile.texColor = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tile.texColor); + gl.texImage2D(gl.TEXTURE_2D, level, gl.RGBA, + width, height, border, gl.RGBA, gl.UNSIGNED_BYTE, + new Uint8Array(4 * width * height).fill(255)); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + + tile.texWidth = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tile.texWidth); + gl.texImage2D(gl.TEXTURE_2D, level, gl.RGBA, + width, height, border, gl.RGBA, gl.UNSIGNED_BYTE, + new Uint8Array(4 * width * height).fill(100)); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + + + + var ids = new Float32Array(points.length); + for (var i = 0; i < points.length; i += 2) { + ids[i + 0] = ((i / 2) % width) / width; + ids[i + 1] = Math.floor((i / 2) / width) / height; + } + + gl.bindBuffer(gl.ARRAY_BUFFER, tile.vertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW); -"use strict"; -/* harmony export (immutable) */ __webpack_exports__["a"] = parseStyleExpression; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_jsep__ = __webpack_require__(13); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_jsep___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_jsep__); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__functions__ = __webpack_require__(11); + gl.bindBuffer(gl.ARRAY_BUFFER, tile.featureIDBuffer); + gl.bufferData(gl.ARRAY_BUFFER, ids, gl.STATIC_DRAW); + gl.bindBuffer(gl.ARRAY_BUFFER, null); + window.requestAnimationFrame(refresh.bind(this)); + return tile; +}; -//TODO document style expressions -//TODO create complete style API, a way to define a color and a width style at the same time, we just have style expressions now -/* - Returns a valid style expression or throws an exception upon invalid inputs. -*/ -var lowerCaseFunctions = {}; -Object.keys(__WEBPACK_IMPORTED_MODULE_1__functions__).map(name => { - lowerCaseFunctions[name.toLocaleLowerCase()] = __WEBPACK_IMPORTED_MODULE_1__functions__[name]; -}); +/** + * Refresh the canvas by redrawing everything needed. + * Should only be called by requestAnimationFrame + * @param timestamp - timestamp of the animation provided by requestAnimationFrame + */ +Renderer.prototype.refresh = refresh; +function refresh(timestamp) { + // Don't re-render more than once per animation frame + if (this.lastFrame == timestamp) { + return; + } + this.lastFrame = timestamp; + var canvas = this.canvas; + var width = gl.canvas.clientWidth; + var height = gl.canvas.clientHeight; + if (gl.canvas.width != width || + gl.canvas.height != height) { + gl.canvas.width = width; + gl.canvas.height = height; + } + var aspect = canvas.clientWidth / canvas.clientHeight; + gl.clearColor(0., 0., 0., 0.);//TODO this should be a renderer property + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); -function parseStyleExpression(str, scheme) { - // jsep addBinaryOp pollutes its module scope, we need to remove the custom operators afterwards - __WEBPACK_IMPORTED_MODULE_0_jsep___default.a.addBinaryOp("^", 10); - const r = parseNode(__WEBPACK_IMPORTED_MODULE_0_jsep___default()(str), scheme); - __WEBPACK_IMPORTED_MODULE_0_jsep___default.a.removeBinaryOp("^"); - return r; -} + gl.enable(gl.CULL_FACE); -function parseNode(node, scheme) { - if (node.type == 'CallExpression') { - const args = node.arguments.map(arg => parseNode(arg, scheme)); - const name = node.callee.name.toLowerCase(); - if (lowerCaseFunctions[name]) { - return lowerCaseFunctions[name](...args, scheme); - } - throw new Error(`Invalid function name '${node.callee.name}'`); - } else if (node.type == 'Literal') { - return node.value; - } else if (node.type == 'ArrayExpression') { - return node.elements.map(e => parseNode(e, scheme)); - } else if (node.type == 'BinaryExpression') { - const left = parseNode(node.left, scheme); - const right = parseNode(node.right, scheme); - switch (node.operator) { - case "*": - return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatMul"](left, right, scheme); - case "/": - return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatDiv"](left, right, scheme); - case "+": - return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatAdd"](left, right, scheme); - case "-": - return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatSub"](left, right, scheme); - case "^": - return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatPow"](left, right, scheme); - default: - throw new Error(`Invalid binary operator '${node.operator}'`); + //TODO refactor condition + gl.disable(gl.BLEND); + gl.disable(gl.DEPTH_TEST); + + if (!this.auxFB) { + this.auxFB = gl.createFramebuffer(); + } + gl.bindFramebuffer(gl.FRAMEBUFFER, this.auxFB); + //console.log("Restyle", timestamp) + // Render To Texture + // COLOR + this.tiles.forEach(tile => { + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tile.texColor, 0); + gl.viewport(0, 0, RTT_WIDTH, tile.height); + gl.clear(gl.COLOR_BUFFER_BIT); + + gl.useProgram(tile.style.colorShader.program); + var obj = { + freeTexUnit: 4 } - } else if (node.type == 'UnaryExpression') { - switch (node.operator) { - case '-': - return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatMul"](-1, parseNode(node.argument, scheme)); - case '+': - return parseNode(node.argument, scheme); - default: - throw new Error(`Invalid unary operator '${node.operator}'`); + tile.style._color._preDraw(obj); + + Object.keys(tile.style.propertyColorTID).forEach((name, i) => { + gl.activeTexture(gl.TEXTURE0 + i); + gl.bindTexture(gl.TEXTURE_2D, tile.propertyTex[tile.propertyID[name]]); + gl.uniform1i(tile.style.colorShader.textureLocations[i], i); + }); + + gl.enableVertexAttribArray(this.colorShaderVertex); + gl.bindBuffer(gl.ARRAY_BUFFER, this.squareBuffer); + gl.vertexAttribPointer(tile.style.colorShader.vertexAttribute, 2, gl.FLOAT, false, 0, 0); + + gl.drawArrays(gl.TRIANGLES, 0, 3); + }); + + //WIDTH + this.tiles.forEach(tile => { + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tile.texWidth, 0); + gl.useProgram(tile.style.widthShader.program); + gl.viewport(0, 0, RTT_WIDTH, tile.height); + gl.clear(gl.COLOR_BUFFER_BIT); + var obj = { + freeTexUnit: 4 } - } else if (node.type == 'Identifier') { - if (node.name[0] == '$') { - return __WEBPACK_IMPORTED_MODULE_1__functions__["Property"](node.name.substring(1), scheme); - } else if (__WEBPACK_IMPORTED_MODULE_1__functions__["schemes"][node.name.toLowerCase()]) { - return __WEBPACK_IMPORTED_MODULE_1__functions__["schemes"][node.name.toLowerCase()](); + tile.style._width._preDraw(obj); + Object.keys(tile.style.propertyWidthTID).forEach((name, i) => { + gl.activeTexture(gl.TEXTURE0 + i); + gl.bindTexture(gl.TEXTURE_2D, tile.propertyTex[tile.propertyID[name]]); + gl.uniform1i(tile.style.widthShader.textureLocations[i], i); + }); + + gl.enableVertexAttribArray(tile.style.widthShader.vertexAttribute); + gl.bindBuffer(gl.ARRAY_BUFFER, this.squareBuffer); + gl.vertexAttribPointer(tile.style.widthShader.vertexAttribute, 2, gl.FLOAT, false, 0, 0); + + gl.drawArrays(gl.TRIANGLES, 0, 3); + + tile.style.updated = false; + tile.initialized = true; + }); + + + gl.enable(gl.DEPTH_TEST); + + gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); + gl.enable(gl.BLEND); + + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); + + gl.useProgram(this.finalRendererProgram.program); + var s = 1. / this._zoom; + + + this.tiles.forEach(tile => { + /*console.log((s / aspect) * tile.scale, + s * tile.scale, + (s / aspect) * this._center.x - tile.center.x, + s * this._center.y - tile.center.y + );*/ + gl.uniform2f(this.finalRendererProgram.vertexScaleUniformLocation, + (s / aspect) * tile.scale, + s * tile.scale); + gl.uniform2f(this.finalRendererProgram.vertexOffsetUniformLocation, + (s / aspect) * (this._center.x - tile.center.x), + s * (this._center.y - tile.center.y)); + + gl.enableVertexAttribArray(this.finalRendererProgram.vertexPositionAttribute); + gl.bindBuffer(gl.ARRAY_BUFFER, tile.vertexBuffer); + gl.vertexAttribPointer(this.finalRendererProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); + + + gl.enableVertexAttribArray(this.finalRendererProgram.featureIdAttr); + gl.bindBuffer(gl.ARRAY_BUFFER, tile.featureIDBuffer); + gl.vertexAttribPointer(this.finalRendererProgram.featureIdAttr, 2, gl.FLOAT, false, 0, 0); + + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, tile.texColor); + gl.uniform1i(this.finalRendererProgram.colorTexture, 0); + + gl.activeTexture(gl.TEXTURE1); + gl.bindTexture(gl.TEXTURE_2D, tile.texWidth); + gl.uniform1i(this.finalRendererProgram.widthTexture, 1); + + gl.drawArrays(gl.POINTS, 0, tile.numVertex); + + }); + + this.tiles.forEach(t => { + if (t.style._color.isAnimated() || t.style._width.isAnimated()) { + window.requestAnimationFrame(refresh.bind(this)); } - } - throw new Error(`Invalid expression '${JSON.stringify(node)}'`); + }); } - +/** + * Initialize static shaders + */ +Renderer.prototype._initShaders = function () { + this.finalRendererProgram = __WEBPACK_IMPORTED_MODULE_0__shaders__["a" /* renderer */].createPointShader(gl); +} /***/ }), -/* 15 */ +/* 7 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__point__ = __webpack_require__(16); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__point__ = __webpack_require__(8); /* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "a", function() { return __WEBPACK_IMPORTED_MODULE_0__point__; }); /***/ }), -/* 16 */ +/* 8 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -3474,12 +2254,12 @@ void main(void) { /***/ }), -/* 17 */ +/* 9 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__color__ = __webpack_require__(18); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__width__ = __webpack_require__(19); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__color__ = __webpack_require__(10); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__width__ = __webpack_require__(11); /* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "a", function() { return __WEBPACK_IMPORTED_MODULE_0__color__; }); /* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "b", function() { return __WEBPACK_IMPORTED_MODULE_1__width__; }); @@ -3487,7 +2267,7 @@ void main(void) { /***/ }), -/* 18 */ +/* 10 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -3533,7 +2313,7 @@ void main(void) { /***/ }), -/* 19 */ +/* 11 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -3578,18 +2358,18 @@ void main(void) { /***/ }), -/* 20 */ +/* 12 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Style", function() { return Style; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "setGL", function() { return setGL; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_jsep__ = __webpack_require__(13); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_jsep__ = __webpack_require__(2); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_jsep___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_jsep__); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__functions__ = __webpack_require__(11); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__parser__ = __webpack_require__(14); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__shaders__ = __webpack_require__(12); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__functions__ = __webpack_require__(0); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__parser__ = __webpack_require__(3); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__shaders__ = __webpack_require__(1); /* harmony namespace reexport (by provided) */ __webpack_require__.d(__webpack_exports__, "Property", function() { return __WEBPACK_IMPORTED_MODULE_1__functions__["Property"]; }); /* harmony namespace reexport (by provided) */ __webpack_require__.d(__webpack_exports__, "Blend", function() { return __WEBPACK_IMPORTED_MODULE_1__functions__["Blend"]; }); /* harmony namespace reexport (by provided) */ __webpack_require__.d(__webpack_exports__, "Now", function() { return __WEBPACK_IMPORTED_MODULE_1__functions__["Now"]; }); @@ -3602,7 +2382,7 @@ Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); /* harmony namespace reexport (by provided) */ __webpack_require__.d(__webpack_exports__, "FloatAdd", function() { return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatAdd"]; }); /* harmony namespace reexport (by provided) */ __webpack_require__.d(__webpack_exports__, "FloatSub", function() { return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatSub"]; }); /* harmony namespace reexport (by provided) */ __webpack_require__.d(__webpack_exports__, "FloatPow", function() { return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatPow"]; }); -/* harmony namespace reexport (by provided) */ __webpack_require__.d(__webpack_exports__, "schemes", function() { return __WEBPACK_IMPORTED_MODULE_1__functions__["schemes"]; }); +/* harmony namespace reexport (by provided) */ __webpack_require__.d(__webpack_exports__, "schemas", function() { return __WEBPACK_IMPORTED_MODULE_1__functions__["schemas"]; }); /* harmony namespace reexport (by provided) */ __webpack_require__.d(__webpack_exports__, "parseStyleExpression", function() { return __WEBPACK_IMPORTED_MODULE_2__parser__["a"]; }); var gl = null; @@ -3651,11 +2431,16 @@ Style.prototype._compileWidthShader = function () { this.widthShader = r.shader; } - -function Style(renderer, scheme) { +/** + * @api + * @constructor + * @param {*} renderer + * @param {*} schema + */ +function Style(renderer, schema) { this.renderer = renderer; this.updated = true; - this.scheme = scheme; + this.schema = schema; this._width = __WEBPACK_IMPORTED_MODULE_1__functions__["Float"](5); this._width.parent = this; @@ -3670,6 +2455,10 @@ function Style(renderer, scheme) { window.requestAnimationFrame(this.renderer.refresh.bind(this.renderer)); }; } +/** + * @api + * @param {*} float + */ Style.prototype.setWidth = function (float) { this._width = float; this.updated = true; @@ -3693,7 +2482,10 @@ Style.prototype.replaceChild = function (toReplace, replacer) { console.warn('No child found'); } } - +/** + * @api + * @param {*} color + */ Style.prototype.setColor = function (color) { this._color = color; this.updated = true; @@ -3704,22 +2496,28 @@ Style.prototype.setColor = function (color) { }; color.notify(); } +/** + * @api + */ Style.prototype.getWidth = function () { return this._width; } +/** + * @api + */ Style.prototype.getColor = function () { return this._color; } /***/ }), -/* 21 */ +/* 13 */ /***/ (function(module, exports, __webpack_require__) { -module.exports = __webpack_require__(22); +module.exports = __webpack_require__(14); /***/ }), -/* 22 */ +/* 14 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;!function() { @@ -5572,7 +4370,7 @@ var colorbrewer_tags = { "YlOrRd": { "tags": ["quantitative"] } } -var colorbrewer = __webpack_require__(23); +var colorbrewer = __webpack_require__(15); // augment colorbrewer with tags for (var r in colorbrewer) { @@ -5605,14 +4403,14 @@ if (true) { /***/ }), -/* 23 */ +/* 15 */ /***/ (function(module, exports, __webpack_require__) { -module.exports = __webpack_require__(24); +module.exports = __webpack_require__(16); /***/ }), -/* 24 */ +/* 16 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;// This product includes color specifications and designs developed by Cynthia Brewer (http://colorbrewer.org/). @@ -5921,43 +4719,1354 @@ var colorbrewer = {YlGn: { 12: ["#8dd3c7","#ffffb3","#bebada","#fb8072","#80b1d3","#fdb462","#b3de69","#fccde5","#d9d9d9","#bc80bd","#ccebc5","#ffed6f"] }}; -if (true) { - !(__WEBPACK_AMD_DEFINE_FACTORY__ = (colorbrewer), - __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? - (__WEBPACK_AMD_DEFINE_FACTORY__.call(exports, __webpack_require__, exports, module)) : - __WEBPACK_AMD_DEFINE_FACTORY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} else if (typeof module === "object" && module.exports) { - module.exports = colorbrewer; -} else { - this.colorbrewer = colorbrewer; +if (true) { + !(__WEBPACK_AMD_DEFINE_FACTORY__ = (colorbrewer), + __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? + (__WEBPACK_AMD_DEFINE_FACTORY__.call(exports, __webpack_require__, exports, module)) : + __WEBPACK_AMD_DEFINE_FACTORY__), + __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); +} else if (typeof module === "object" && module.exports) { + module.exports = colorbrewer; +} else { + this.colorbrewer = colorbrewer; +} + +}(); + + +/***/ }), +/* 17 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Schema; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return checkschemaMatch; }); +/** + * @api + * @constructor + * @param {*} propertyNames + * @param {*} propertyTypes + */ +function Schema(propertyNames, propertyTypes) { + if (propertyNames.length != propertyTypes.length) { + throw new Error("propertyNames and propertyTypes lengths mismatch"); + } + propertyNames.map((name, index) => this[name] = propertyTypes[index]); +} + +/** + * + * @param {*} schemaA + * @param {*} schemaB + */ +function checkschemaMatch(schemaA, schemaB) { + if (schemaA && schemaB) { + const equals = Object.keys(schemaA).map(name => schemaA[name] == schemaB[name]).reduce((a, b) => a && b); + if (!equals) { + throw new Error(`schema mismatch: ${JSON.stringify(schemaA)}, ${JSON.stringify(schemaB)}`); + } + } +} + + + +/***/ }), +/* 18 */ +/***/ (function(module, exports, __webpack_require__) { + +module.exports.VectorTile = __webpack_require__(19); +module.exports.VectorTileFeature = __webpack_require__(5); +module.exports.VectorTileLayer = __webpack_require__(4); + + +/***/ }), +/* 19 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var VectorTileLayer = __webpack_require__(4); + +module.exports = VectorTile; + +function VectorTile(pbf, end) { + this.layers = pbf.readFields(readTile, {}, end); +} + +function readTile(tag, layers, pbf) { + if (tag === 3) { + var layer = new VectorTileLayer(pbf, pbf.readVarint() + pbf.pos); + if (layer.length) layers[layer.name] = layer; + } +} + + + +/***/ }), +/* 20 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +module.exports = Point; + +/** + * A standalone point geometry with useful accessor, comparison, and + * modification methods. + * + * @class Point + * @param {Number} x the x-coordinate. this could be longitude or screen + * pixels, or any other sort of unit. + * @param {Number} y the y-coordinate. this could be latitude or screen + * pixels, or any other sort of unit. + * @example + * var point = new Point(-77, 38); + */ +function Point(x, y) { + this.x = x; + this.y = y; +} + +Point.prototype = { + + /** + * Clone this point, returning a new point that can be modified + * without affecting the old one. + * @return {Point} the clone + */ + clone: function() { return new Point(this.x, this.y); }, + + /** + * Add this point's x & y coordinates to another point, + * yielding a new point. + * @param {Point} p the other point + * @return {Point} output point + */ + add: function(p) { return this.clone()._add(p); }, + + /** + * Subtract this point's x & y coordinates to from point, + * yielding a new point. + * @param {Point} p the other point + * @return {Point} output point + */ + sub: function(p) { return this.clone()._sub(p); }, + + /** + * Multiply this point's x & y coordinates by point, + * yielding a new point. + * @param {Point} p the other point + * @return {Point} output point + */ + multByPoint: function(p) { return this.clone()._multByPoint(p); }, + + /** + * Divide this point's x & y coordinates by point, + * yielding a new point. + * @param {Point} p the other point + * @return {Point} output point + */ + divByPoint: function(p) { return this.clone()._divByPoint(p); }, + + /** + * Multiply this point's x & y coordinates by a factor, + * yielding a new point. + * @param {Point} k factor + * @return {Point} output point + */ + mult: function(k) { return this.clone()._mult(k); }, + + /** + * Divide this point's x & y coordinates by a factor, + * yielding a new point. + * @param {Point} k factor + * @return {Point} output point + */ + div: function(k) { return this.clone()._div(k); }, + + /** + * Rotate this point around the 0, 0 origin by an angle a, + * given in radians + * @param {Number} a angle to rotate around, in radians + * @return {Point} output point + */ + rotate: function(a) { return this.clone()._rotate(a); }, + + /** + * Rotate this point around p point by an angle a, + * given in radians + * @param {Number} a angle to rotate around, in radians + * @param {Point} p Point to rotate around + * @return {Point} output point + */ + rotateAround: function(a,p) { return this.clone()._rotateAround(a,p); }, + + /** + * Multiply this point by a 4x1 transformation matrix + * @param {Array} m transformation matrix + * @return {Point} output point + */ + matMult: function(m) { return this.clone()._matMult(m); }, + + /** + * Calculate this point but as a unit vector from 0, 0, meaning + * that the distance from the resulting point to the 0, 0 + * coordinate will be equal to 1 and the angle from the resulting + * point to the 0, 0 coordinate will be the same as before. + * @return {Point} unit vector point + */ + unit: function() { return this.clone()._unit(); }, + + /** + * Compute a perpendicular point, where the new y coordinate + * is the old x coordinate and the new x coordinate is the old y + * coordinate multiplied by -1 + * @return {Point} perpendicular point + */ + perp: function() { return this.clone()._perp(); }, + + /** + * Return a version of this point with the x & y coordinates + * rounded to integers. + * @return {Point} rounded point + */ + round: function() { return this.clone()._round(); }, + + /** + * Return the magitude of this point: this is the Euclidean + * distance from the 0, 0 coordinate to this point's x and y + * coordinates. + * @return {Number} magnitude + */ + mag: function() { + return Math.sqrt(this.x * this.x + this.y * this.y); + }, + + /** + * Judge whether this point is equal to another point, returning + * true or false. + * @param {Point} other the other point + * @return {boolean} whether the points are equal + */ + equals: function(other) { + return this.x === other.x && + this.y === other.y; + }, + + /** + * Calculate the distance from this point to another point + * @param {Point} p the other point + * @return {Number} distance + */ + dist: function(p) { + return Math.sqrt(this.distSqr(p)); + }, + + /** + * Calculate the distance from this point to another point, + * without the square root step. Useful if you're comparing + * relative distances. + * @param {Point} p the other point + * @return {Number} distance + */ + distSqr: function(p) { + var dx = p.x - this.x, + dy = p.y - this.y; + return dx * dx + dy * dy; + }, + + /** + * Get the angle from the 0, 0 coordinate to this point, in radians + * coordinates. + * @return {Number} angle + */ + angle: function() { + return Math.atan2(this.y, this.x); + }, + + /** + * Get the angle from this point to another point, in radians + * @param {Point} b the other point + * @return {Number} angle + */ + angleTo: function(b) { + return Math.atan2(this.y - b.y, this.x - b.x); + }, + + /** + * Get the angle between this point and another point, in radians + * @param {Point} b the other point + * @return {Number} angle + */ + angleWith: function(b) { + return this.angleWithSep(b.x, b.y); + }, + + /* + * Find the angle of the two vectors, solving the formula for + * the cross product a x b = |a||b|sin(θ) for θ. + * @param {Number} x the x-coordinate + * @param {Number} y the y-coordinate + * @return {Number} the angle in radians + */ + angleWithSep: function(x, y) { + return Math.atan2( + this.x * y - this.y * x, + this.x * x + this.y * y); + }, + + _matMult: function(m) { + var x = m[0] * this.x + m[1] * this.y, + y = m[2] * this.x + m[3] * this.y; + this.x = x; + this.y = y; + return this; + }, + + _add: function(p) { + this.x += p.x; + this.y += p.y; + return this; + }, + + _sub: function(p) { + this.x -= p.x; + this.y -= p.y; + return this; + }, + + _mult: function(k) { + this.x *= k; + this.y *= k; + return this; + }, + + _div: function(k) { + this.x /= k; + this.y /= k; + return this; + }, + + _multByPoint: function(p) { + this.x *= p.x; + this.y *= p.y; + return this; + }, + + _divByPoint: function(p) { + this.x /= p.x; + this.y /= p.y; + return this; + }, + + _unit: function() { + this._div(this.mag()); + return this; + }, + + _perp: function() { + var y = this.y; + this.y = this.x; + this.x = -y; + return this; + }, + + _rotate: function(angle) { + var cos = Math.cos(angle), + sin = Math.sin(angle), + x = cos * this.x - sin * this.y, + y = sin * this.x + cos * this.y; + this.x = x; + this.y = y; + return this; + }, + + _rotateAround: function(angle, p) { + var cos = Math.cos(angle), + sin = Math.sin(angle), + x = p.x + cos * (this.x - p.x) - sin * (this.y - p.y), + y = p.y + sin * (this.x - p.x) + cos * (this.y - p.y); + this.x = x; + this.y = y; + return this; + }, + + _round: function() { + this.x = Math.round(this.x); + this.y = Math.round(this.y); + return this; + } +}; + +/** + * Construct a point from an array if necessary, otherwise if the input + * is already a Point, or an unknown type, return it unchanged + * @param {Array|Point|*} a any kind of input value + * @return {Point} constructed point, or passed-through value. + * @example + * // this + * var point = Point.convert([0, 1]); + * // is equivalent to + * var point = new Point(0, 1); + */ +Point.convert = function (a) { + if (a instanceof Point) { + return a; + } + if (Array.isArray(a)) { + return new Point(a[0], a[1]); + } + return a; +}; + + +/***/ }), +/* 21 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +module.exports = Pbf; + +var ieee754 = __webpack_require__(22); + +function Pbf(buf) { + this.buf = ArrayBuffer.isView && ArrayBuffer.isView(buf) ? buf : new Uint8Array(buf || 0); + this.pos = 0; + this.type = 0; + this.length = this.buf.length; +} + +Pbf.Varint = 0; // varint: int32, int64, uint32, uint64, sint32, sint64, bool, enum +Pbf.Fixed64 = 1; // 64-bit: double, fixed64, sfixed64 +Pbf.Bytes = 2; // length-delimited: string, bytes, embedded messages, packed repeated fields +Pbf.Fixed32 = 5; // 32-bit: float, fixed32, sfixed32 + +var SHIFT_LEFT_32 = (1 << 16) * (1 << 16), + SHIFT_RIGHT_32 = 1 / SHIFT_LEFT_32; + +Pbf.prototype = { + + destroy: function() { + this.buf = null; + }, + + // === READING ================================================================= + + readFields: function(readField, result, end) { + end = end || this.length; + + while (this.pos < end) { + var val = this.readVarint(), + tag = val >> 3, + startPos = this.pos; + + this.type = val & 0x7; + readField(tag, result, this); + + if (this.pos === startPos) this.skip(val); + } + return result; + }, + + readMessage: function(readField, result) { + return this.readFields(readField, result, this.readVarint() + this.pos); + }, + + readFixed32: function() { + var val = readUInt32(this.buf, this.pos); + this.pos += 4; + return val; + }, + + readSFixed32: function() { + var val = readInt32(this.buf, this.pos); + this.pos += 4; + return val; + }, + + // 64-bit int handling is based on github.com/dpw/node-buffer-more-ints (MIT-licensed) + + readFixed64: function() { + var val = readUInt32(this.buf, this.pos) + readUInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32; + this.pos += 8; + return val; + }, + + readSFixed64: function() { + var val = readUInt32(this.buf, this.pos) + readInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32; + this.pos += 8; + return val; + }, + + readFloat: function() { + var val = ieee754.read(this.buf, this.pos, true, 23, 4); + this.pos += 4; + return val; + }, + + readDouble: function() { + var val = ieee754.read(this.buf, this.pos, true, 52, 8); + this.pos += 8; + return val; + }, + + readVarint: function(isSigned) { + var buf = this.buf, + val, b; + + b = buf[this.pos++]; val = b & 0x7f; if (b < 0x80) return val; + b = buf[this.pos++]; val |= (b & 0x7f) << 7; if (b < 0x80) return val; + b = buf[this.pos++]; val |= (b & 0x7f) << 14; if (b < 0x80) return val; + b = buf[this.pos++]; val |= (b & 0x7f) << 21; if (b < 0x80) return val; + b = buf[this.pos]; val |= (b & 0x0f) << 28; + + return readVarintRemainder(val, isSigned, this); + }, + + readVarint64: function() { // for compatibility with v2.0.1 + return this.readVarint(true); + }, + + readSVarint: function() { + var num = this.readVarint(); + return num % 2 === 1 ? (num + 1) / -2 : num / 2; // zigzag encoding + }, + + readBoolean: function() { + return Boolean(this.readVarint()); + }, + + readString: function() { + var end = this.readVarint() + this.pos, + str = readUtf8(this.buf, this.pos, end); + this.pos = end; + return str; + }, + + readBytes: function() { + var end = this.readVarint() + this.pos, + buffer = this.buf.subarray(this.pos, end); + this.pos = end; + return buffer; + }, + + // verbose for performance reasons; doesn't affect gzipped size + + readPackedVarint: function(arr, isSigned) { + var end = readPackedEnd(this); + arr = arr || []; + while (this.pos < end) arr.push(this.readVarint(isSigned)); + return arr; + }, + readPackedSVarint: function(arr) { + var end = readPackedEnd(this); + arr = arr || []; + while (this.pos < end) arr.push(this.readSVarint()); + return arr; + }, + readPackedBoolean: function(arr) { + var end = readPackedEnd(this); + arr = arr || []; + while (this.pos < end) arr.push(this.readBoolean()); + return arr; + }, + readPackedFloat: function(arr) { + var end = readPackedEnd(this); + arr = arr || []; + while (this.pos < end) arr.push(this.readFloat()); + return arr; + }, + readPackedDouble: function(arr) { + var end = readPackedEnd(this); + arr = arr || []; + while (this.pos < end) arr.push(this.readDouble()); + return arr; + }, + readPackedFixed32: function(arr) { + var end = readPackedEnd(this); + arr = arr || []; + while (this.pos < end) arr.push(this.readFixed32()); + return arr; + }, + readPackedSFixed32: function(arr) { + var end = readPackedEnd(this); + arr = arr || []; + while (this.pos < end) arr.push(this.readSFixed32()); + return arr; + }, + readPackedFixed64: function(arr) { + var end = readPackedEnd(this); + arr = arr || []; + while (this.pos < end) arr.push(this.readFixed64()); + return arr; + }, + readPackedSFixed64: function(arr) { + var end = readPackedEnd(this); + arr = arr || []; + while (this.pos < end) arr.push(this.readSFixed64()); + return arr; + }, + + skip: function(val) { + var type = val & 0x7; + if (type === Pbf.Varint) while (this.buf[this.pos++] > 0x7f) {} + else if (type === Pbf.Bytes) this.pos = this.readVarint() + this.pos; + else if (type === Pbf.Fixed32) this.pos += 4; + else if (type === Pbf.Fixed64) this.pos += 8; + else throw new Error('Unimplemented type: ' + type); + }, + + // === WRITING ================================================================= + + writeTag: function(tag, type) { + this.writeVarint((tag << 3) | type); + }, + + realloc: function(min) { + var length = this.length || 16; + + while (length < this.pos + min) length *= 2; + + if (length !== this.length) { + var buf = new Uint8Array(length); + buf.set(this.buf); + this.buf = buf; + this.length = length; + } + }, + + finish: function() { + this.length = this.pos; + this.pos = 0; + return this.buf.subarray(0, this.length); + }, + + writeFixed32: function(val) { + this.realloc(4); + writeInt32(this.buf, val, this.pos); + this.pos += 4; + }, + + writeSFixed32: function(val) { + this.realloc(4); + writeInt32(this.buf, val, this.pos); + this.pos += 4; + }, + + writeFixed64: function(val) { + this.realloc(8); + writeInt32(this.buf, val & -1, this.pos); + writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4); + this.pos += 8; + }, + + writeSFixed64: function(val) { + this.realloc(8); + writeInt32(this.buf, val & -1, this.pos); + writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4); + this.pos += 8; + }, + + writeVarint: function(val) { + val = +val || 0; + + if (val > 0xfffffff || val < 0) { + writeBigVarint(val, this); + return; + } + + this.realloc(4); + + this.buf[this.pos++] = val & 0x7f | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return; + this.buf[this.pos++] = ((val >>>= 7) & 0x7f) | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return; + this.buf[this.pos++] = ((val >>>= 7) & 0x7f) | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return; + this.buf[this.pos++] = (val >>> 7) & 0x7f; + }, + + writeSVarint: function(val) { + this.writeVarint(val < 0 ? -val * 2 - 1 : val * 2); + }, + + writeBoolean: function(val) { + this.writeVarint(Boolean(val)); + }, + + writeString: function(str) { + str = String(str); + this.realloc(str.length * 4); + + this.pos++; // reserve 1 byte for short string length + + var startPos = this.pos; + // write the string directly to the buffer and see how much was written + this.pos = writeUtf8(this.buf, str, this.pos); + var len = this.pos - startPos; + + if (len >= 0x80) makeRoomForExtraLength(startPos, len, this); + + // finally, write the message length in the reserved place and restore the position + this.pos = startPos - 1; + this.writeVarint(len); + this.pos += len; + }, + + writeFloat: function(val) { + this.realloc(4); + ieee754.write(this.buf, val, this.pos, true, 23, 4); + this.pos += 4; + }, + + writeDouble: function(val) { + this.realloc(8); + ieee754.write(this.buf, val, this.pos, true, 52, 8); + this.pos += 8; + }, + + writeBytes: function(buffer) { + var len = buffer.length; + this.writeVarint(len); + this.realloc(len); + for (var i = 0; i < len; i++) this.buf[this.pos++] = buffer[i]; + }, + + writeRawMessage: function(fn, obj) { + this.pos++; // reserve 1 byte for short message length + + // write the message directly to the buffer and see how much was written + var startPos = this.pos; + fn(obj, this); + var len = this.pos - startPos; + + if (len >= 0x80) makeRoomForExtraLength(startPos, len, this); + + // finally, write the message length in the reserved place and restore the position + this.pos = startPos - 1; + this.writeVarint(len); + this.pos += len; + }, + + writeMessage: function(tag, fn, obj) { + this.writeTag(tag, Pbf.Bytes); + this.writeRawMessage(fn, obj); + }, + + writePackedVarint: function(tag, arr) { this.writeMessage(tag, writePackedVarint, arr); }, + writePackedSVarint: function(tag, arr) { this.writeMessage(tag, writePackedSVarint, arr); }, + writePackedBoolean: function(tag, arr) { this.writeMessage(tag, writePackedBoolean, arr); }, + writePackedFloat: function(tag, arr) { this.writeMessage(tag, writePackedFloat, arr); }, + writePackedDouble: function(tag, arr) { this.writeMessage(tag, writePackedDouble, arr); }, + writePackedFixed32: function(tag, arr) { this.writeMessage(tag, writePackedFixed32, arr); }, + writePackedSFixed32: function(tag, arr) { this.writeMessage(tag, writePackedSFixed32, arr); }, + writePackedFixed64: function(tag, arr) { this.writeMessage(tag, writePackedFixed64, arr); }, + writePackedSFixed64: function(tag, arr) { this.writeMessage(tag, writePackedSFixed64, arr); }, + + writeBytesField: function(tag, buffer) { + this.writeTag(tag, Pbf.Bytes); + this.writeBytes(buffer); + }, + writeFixed32Field: function(tag, val) { + this.writeTag(tag, Pbf.Fixed32); + this.writeFixed32(val); + }, + writeSFixed32Field: function(tag, val) { + this.writeTag(tag, Pbf.Fixed32); + this.writeSFixed32(val); + }, + writeFixed64Field: function(tag, val) { + this.writeTag(tag, Pbf.Fixed64); + this.writeFixed64(val); + }, + writeSFixed64Field: function(tag, val) { + this.writeTag(tag, Pbf.Fixed64); + this.writeSFixed64(val); + }, + writeVarintField: function(tag, val) { + this.writeTag(tag, Pbf.Varint); + this.writeVarint(val); + }, + writeSVarintField: function(tag, val) { + this.writeTag(tag, Pbf.Varint); + this.writeSVarint(val); + }, + writeStringField: function(tag, str) { + this.writeTag(tag, Pbf.Bytes); + this.writeString(str); + }, + writeFloatField: function(tag, val) { + this.writeTag(tag, Pbf.Fixed32); + this.writeFloat(val); + }, + writeDoubleField: function(tag, val) { + this.writeTag(tag, Pbf.Fixed64); + this.writeDouble(val); + }, + writeBooleanField: function(tag, val) { + this.writeVarintField(tag, Boolean(val)); + } +}; + +function readVarintRemainder(l, s, p) { + var buf = p.buf, + h, b; + + b = buf[p.pos++]; h = (b & 0x70) >> 4; if (b < 0x80) return toNum(l, h, s); + b = buf[p.pos++]; h |= (b & 0x7f) << 3; if (b < 0x80) return toNum(l, h, s); + b = buf[p.pos++]; h |= (b & 0x7f) << 10; if (b < 0x80) return toNum(l, h, s); + b = buf[p.pos++]; h |= (b & 0x7f) << 17; if (b < 0x80) return toNum(l, h, s); + b = buf[p.pos++]; h |= (b & 0x7f) << 24; if (b < 0x80) return toNum(l, h, s); + b = buf[p.pos++]; h |= (b & 0x01) << 31; if (b < 0x80) return toNum(l, h, s); + + throw new Error('Expected varint not more than 10 bytes'); +} + +function readPackedEnd(pbf) { + return pbf.type === Pbf.Bytes ? + pbf.readVarint() + pbf.pos : pbf.pos + 1; +} + +function toNum(low, high, isSigned) { + if (isSigned) { + return high * 0x100000000 + (low >>> 0); + } + + return ((high >>> 0) * 0x100000000) + (low >>> 0); +} + +function writeBigVarint(val, pbf) { + var low, high; + + if (val >= 0) { + low = (val % 0x100000000) | 0; + high = (val / 0x100000000) | 0; + } else { + low = ~(-val % 0x100000000); + high = ~(-val / 0x100000000); + + if (low ^ 0xffffffff) { + low = (low + 1) | 0; + } else { + low = 0; + high = (high + 1) | 0; + } + } + + if (val >= 0x10000000000000000 || val < -0x10000000000000000) { + throw new Error('Given varint doesn\'t fit into 10 bytes'); + } + + pbf.realloc(10); + + writeBigVarintLow(low, high, pbf); + writeBigVarintHigh(high, pbf); +} + +function writeBigVarintLow(low, high, pbf) { + pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7; + pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7; + pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7; + pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7; + pbf.buf[pbf.pos] = low & 0x7f; +} + +function writeBigVarintHigh(high, pbf) { + var lsb = (high & 0x07) << 4; + + pbf.buf[pbf.pos++] |= lsb | ((high >>>= 3) ? 0x80 : 0); if (!high) return; + pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return; + pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return; + pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return; + pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return; + pbf.buf[pbf.pos++] = high & 0x7f; +} + +function makeRoomForExtraLength(startPos, len, pbf) { + var extraLen = + len <= 0x3fff ? 1 : + len <= 0x1fffff ? 2 : + len <= 0xfffffff ? 3 : Math.ceil(Math.log(len) / (Math.LN2 * 7)); + + // if 1 byte isn't enough for encoding message length, shift the data to the right + pbf.realloc(extraLen); + for (var i = pbf.pos - 1; i >= startPos; i--) pbf.buf[i + extraLen] = pbf.buf[i]; +} + +function writePackedVarint(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeVarint(arr[i]); } +function writePackedSVarint(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSVarint(arr[i]); } +function writePackedFloat(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFloat(arr[i]); } +function writePackedDouble(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeDouble(arr[i]); } +function writePackedBoolean(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeBoolean(arr[i]); } +function writePackedFixed32(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFixed32(arr[i]); } +function writePackedSFixed32(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSFixed32(arr[i]); } +function writePackedFixed64(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFixed64(arr[i]); } +function writePackedSFixed64(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSFixed64(arr[i]); } + +// Buffer code below from https://github.com/feross/buffer, MIT-licensed + +function readUInt32(buf, pos) { + return ((buf[pos]) | + (buf[pos + 1] << 8) | + (buf[pos + 2] << 16)) + + (buf[pos + 3] * 0x1000000); +} + +function writeInt32(buf, val, pos) { + buf[pos] = val; + buf[pos + 1] = (val >>> 8); + buf[pos + 2] = (val >>> 16); + buf[pos + 3] = (val >>> 24); +} + +function readInt32(buf, pos) { + return ((buf[pos]) | + (buf[pos + 1] << 8) | + (buf[pos + 2] << 16)) + + (buf[pos + 3] << 24); +} + +function readUtf8(buf, pos, end) { + var str = ''; + var i = pos; + + while (i < end) { + var b0 = buf[i]; + var c = null; // codepoint + var bytesPerSequence = + b0 > 0xEF ? 4 : + b0 > 0xDF ? 3 : + b0 > 0xBF ? 2 : 1; + + if (i + bytesPerSequence > end) break; + + var b1, b2, b3; + + if (bytesPerSequence === 1) { + if (b0 < 0x80) { + c = b0; + } + } else if (bytesPerSequence === 2) { + b1 = buf[i + 1]; + if ((b1 & 0xC0) === 0x80) { + c = (b0 & 0x1F) << 0x6 | (b1 & 0x3F); + if (c <= 0x7F) { + c = null; + } + } + } else if (bytesPerSequence === 3) { + b1 = buf[i + 1]; + b2 = buf[i + 2]; + if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80) { + c = (b0 & 0xF) << 0xC | (b1 & 0x3F) << 0x6 | (b2 & 0x3F); + if (c <= 0x7FF || (c >= 0xD800 && c <= 0xDFFF)) { + c = null; + } + } + } else if (bytesPerSequence === 4) { + b1 = buf[i + 1]; + b2 = buf[i + 2]; + b3 = buf[i + 3]; + if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80 && (b3 & 0xC0) === 0x80) { + c = (b0 & 0xF) << 0x12 | (b1 & 0x3F) << 0xC | (b2 & 0x3F) << 0x6 | (b3 & 0x3F); + if (c <= 0xFFFF || c >= 0x110000) { + c = null; + } + } + } + + if (c === null) { + c = 0xFFFD; + bytesPerSequence = 1; + + } else if (c > 0xFFFF) { + c -= 0x10000; + str += String.fromCharCode(c >>> 10 & 0x3FF | 0xD800); + c = 0xDC00 | c & 0x3FF; + } + + str += String.fromCharCode(c); + i += bytesPerSequence; + } + + return str; +} + +function writeUtf8(buf, str, pos) { + for (var i = 0, c, lead; i < str.length; i++) { + c = str.charCodeAt(i); // code point + + if (c > 0xD7FF && c < 0xE000) { + if (lead) { + if (c < 0xDC00) { + buf[pos++] = 0xEF; + buf[pos++] = 0xBF; + buf[pos++] = 0xBD; + lead = c; + continue; + } else { + c = lead - 0xD800 << 10 | c - 0xDC00 | 0x10000; + lead = null; + } + } else { + if (c > 0xDBFF || (i + 1 === str.length)) { + buf[pos++] = 0xEF; + buf[pos++] = 0xBF; + buf[pos++] = 0xBD; + } else { + lead = c; + } + continue; + } + } else if (lead) { + buf[pos++] = 0xEF; + buf[pos++] = 0xBF; + buf[pos++] = 0xBD; + lead = null; + } + + if (c < 0x80) { + buf[pos++] = c; + } else { + if (c < 0x800) { + buf[pos++] = c >> 0x6 | 0xC0; + } else { + if (c < 0x10000) { + buf[pos++] = c >> 0xC | 0xE0; + } else { + buf[pos++] = c >> 0x12 | 0xF0; + buf[pos++] = c >> 0xC & 0x3F | 0x80; + } + buf[pos++] = c >> 0x6 & 0x3F | 0x80; + } + buf[pos++] = c & 0x3F | 0x80; + } + } + return pos; +} + + +/***/ }), +/* 22 */ +/***/ (function(module, exports) { + +exports.read = function (buffer, offset, isLE, mLen, nBytes) { + var e, m + var eLen = nBytes * 8 - mLen - 1 + var eMax = (1 << eLen) - 1 + var eBias = eMax >> 1 + var nBits = -7 + var i = isLE ? (nBytes - 1) : 0 + var d = isLE ? -1 : 1 + var s = buffer[offset + i] + + i += d + + e = s & ((1 << (-nBits)) - 1) + s >>= (-nBits) + nBits += eLen + for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {} + + m = e & ((1 << (-nBits)) - 1) + e >>= (-nBits) + nBits += mLen + for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {} + + if (e === 0) { + e = 1 - eBias + } else if (e === eMax) { + return m ? NaN : ((s ? -1 : 1) * Infinity) + } else { + m = m + Math.pow(2, mLen) + e = e - eBias + } + return (s ? -1 : 1) * m * Math.pow(2, e - mLen) } -}(); +exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { + var e, m, c + var eLen = nBytes * 8 - mLen - 1 + var eMax = (1 << eLen) - 1 + var eBias = eMax >> 1 + var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0) + var i = isLE ? 0 : (nBytes - 1) + var d = isLE ? 1 : -1 + var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0 + + value = Math.abs(value) + + if (isNaN(value) || value === Infinity) { + m = isNaN(value) ? 1 : 0 + e = eMax + } else { + e = Math.floor(Math.log(value) / Math.LN2) + if (value * (c = Math.pow(2, -e)) < 1) { + e-- + c *= 2 + } + if (e + eBias >= 1) { + value += rt / c + } else { + value += rt * Math.pow(2, 1 - eBias) + } + if (value * c >= 2) { + e++ + c /= 2 + } + + if (e + eBias >= eMax) { + m = 0 + e = eMax + } else if (e + eBias >= 1) { + m = (value * c - 1) * Math.pow(2, mLen) + e = e + eBias + } else { + m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen) + e = 0 + } + } + + for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} + + e = (e << mLen) | m + eLen += mLen + for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} + + buffer[offset + i - d] |= s * 128 +} /***/ }), -/* 25 */ +/* 23 */, +/* 24 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Scheme; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return checkSchemeMatch; }); -function Scheme(propertyNames, propertyTypes) { - if (propertyNames.length != propertyTypes.length) { - throw new Error("propertyNames and propertyTypes lengths mismatch"); +Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__src_index__ = __webpack_require__(6); + + +var VectorTile = __webpack_require__(18).VectorTile; +var Protobuf = __webpack_require__(21); + +var renderer; +var oldtiles = []; +var ajax; + +var style; +var schema; + + +function styleWidth(e) { + const v = document.getElementById("widthStyleEntry").value; + try { + style.getWidth().blendTo(__WEBPACK_IMPORTED_MODULE_0__src_index__["c" /* Style */].parseStyleExpression(v, schema), 1000); + document.getElementById("feedback").value = 'ok'; + } catch (error) { + const err = `Invalid width expression: ${error}:${error.stack}`; + console.warn(err); + document.getElementById("feedback").value = err; } - propertyNames.map((name, index) => this[name] = propertyTypes[index]); } -function checkSchemeMatch(schemeA, schemeB) { - if (schemeA && schemeB) { - const equals = Object.keys(schemeA).map(name => schemeA[name] == schemeB[name]).reduce((a, b) => a && b); - if (!equals) { - throw new Error(`Scheme mismatch: ${JSON.stringify(schemeA)}, ${JSON.stringify(schemeB)}`); +function styleColor(e) { + const v = document.getElementById("colorStyleEntry").value; + try { + style.getColor().blendTo(__WEBPACK_IMPORTED_MODULE_0__src_index__["c" /* Style */].parseStyleExpression(v, schema), 1000); + document.getElementById("feedback").value = 'ok'; + } catch (error) { + const err = `Invalid color expression: ${error}:${error.stack}`; + console.warn(err); + document.getElementById("feedback").value = err; + } +} + +function getTileList(c, iz, aspect) { + var list = []; + var z = Math.ceil(Math.log2(1. / iz)); + var x = c.x; + var y = c.y; + const numTiles = Math.pow(2, z); + function saturate(x) { + return Math.min(Math.max(x, 0), 1); + } + const minx = Math.floor(numTiles * saturate((x - iz * aspect) * 0.5 + 0.5)); + const maxx = Math.ceil(numTiles * saturate((x + iz * aspect) * 0.5 + 0.5)); + const miny = Math.floor(numTiles * saturate(1. - ((y + iz) * 0.5 + 0.5))); + const maxy = Math.ceil(numTiles * saturate(1. - ((y - iz) * 0.5 + 0.5))); + for (let i = minx; i < maxx; i++) { + for (let j = miny; j < maxy; j++) { + list.push({ + x: i, + y: j, + z: z + }); } } + return list; +} +function getData(aspect) { + const tiles = getTileList(renderer.getCenter(), renderer.getZoom(), aspect); + var completedTiles = []; + var needToComplete = tiles.length; + tiles.forEach(t => { + const x = t.x; + const y = t.y; + const z = t.z; + const mvt_extent = 1024; + const subpixelBufferSize = 0; + const query = + `select st_asmvt(geom, 'lid') FROM + ( + SELECT + ST_AsMVTGeom( + ST_SetSRID(ST_MakePoint(avg(ST_X(the_geom_webmercator)), avg(ST_Y(the_geom_webmercator))),3857), + CDB_XYZ_Extent(${x},${y},${z}), ${mvt_extent}, ${subpixelBufferSize}, false + ) + FROM tx_0125_copy_copy AS cdbq + WHERE the_geom_webmercator && CDB_XYZ_Extent(${x},${y},${z}) + GROUP BY ST_SnapToGrid(the_geom_webmercator, CDB_XYZ_Resolution(${z})*3.) + )AS geom + `; + var oReq = new XMLHttpRequest(); + oReq.open("GET", "https://dmanzanares-core.carto.com/api/v2/sql?q=" + encodeURIComponent(query) + "", true); + oReq.onload = function (oEvent) { + const json = JSON.parse(oReq.response); + if (json.rows[0].st_asmvt.data.length == 0) { + needToComplete--; + if (completedTiles.length == needToComplete) { + oldtiles.forEach(t => renderer.removeDataframe(t)); + completedTiles.forEach(f => renderer.addDataframe(f).setStyle(style)); + oldtiles = completedTiles; + styleWidth(); + styleColor(); + } + return; + } + var tile = new VectorTile(new Protobuf(new Uint8Array(json.rows[0].st_asmvt.data))); + const mvtLayer = tile.layers[Object.keys(tile.layers)[0]]; + var fieldMap = { + temp: 0, + daten: 1 + }; + var properties = [[new Float32Array(mvtLayer.length)], [new Float32Array(mvtLayer.length)]]; + var points = new Float32Array(mvtLayer.length * 2); + const r = Math.random(); + for (var i = 0; i < mvtLayer.length; i++) { + const f = mvtLayer.feature(i); + const geom = f.loadGeometry(); + points[2 * i + 0] = 2 * (geom[0][0].x) / mvt_extent - 1.; + points[2 * i + 1] = 2 * (1. - (geom[0][0].y) / mvt_extent) - 1.; + properties[0][i] = Number(r); + properties[1][i] = Number(Math.random()); + } + console.log(`dataframe feature count: ${mvtLayer.length}`); + var dataframe = { + center: { x: ((x + 0.5) / Math.pow(2, z)) * 2. - 1, y: (1. - (y + 0.5) / Math.pow(2, z)) * 2. - 1. }, + scale: 1 / Math.pow(2, z), + geom: points, + properties: {}, + }; + Object.keys(fieldMap).map((name, pid) => { + dataframe.properties[name] = properties[pid]; + }); + dataframe.schema = new __WEBPACK_IMPORTED_MODULE_0__src_index__["b" /* Schema */](Object.keys(dataframe.properties), Object.keys(dataframe.properties).map(() => 'float')); + console.log(Object.keys(dataframe.properties), Object.keys(dataframe.properties).map(() => 'float'), dataframe.schema); + completedTiles.push(dataframe); + if (completedTiles.length == needToComplete) { + oldtiles.forEach(t => renderer.removeDataframe(t)); + completedTiles.forEach(f => renderer.addDataframe(f).setStyle(style)); + oldtiles = completedTiles; + styleWidth(); + styleColor(); + } + }; + oReq.send(null); + }); +} + +const DEG2RAD = Math.PI / 180; +const EARTH_RADIUS = 6378137; +const WM_EXT = EARTH_RADIUS * Math.PI * 2; +const TILE_SIZE = 256; +// Webmercator projection +function Wmxy(latLng) { + let lat = latLng.lat * DEG2RAD; + let lng = latLng.lng * DEG2RAD; + let x = lng * EARTH_RADIUS; + let y = Math.log(Math.tan(lat / 2 + Math.PI / 4)) * EARTH_RADIUS; + return { x: x, y: y }; +} + +var mapboxgl = window.mapboxgl; +mapboxgl.accessToken = 'pk.eyJ1IjoiZG1hbnphbmFyZXMiLCJhIjoiY2o5cHRhOGg5NWdzbTJxcXltb2g2dmE5NyJ9.RVto4DnlLzQc26j9H0g9_A'; +var map = new mapboxgl.Map({ + container: 'map', // container id + style: 'mapbox://styles/dmanzanares/cj9qx712c0l7u2rpix0913d5g', // stylesheet location + center: [-74.50, 40], // starting position [lng, lat] + zoom: 0, // starting zoom, +}); +map.repaint = false; +function getZoom() { + var b = map.getBounds(); + var c = map.getCenter(); + var nw = b.getNorthWest(); + var sw = b.getSouthWest(); + var z = (Wmxy(nw).y - Wmxy(sw).y) / 40075019.834677525; + renderer.setCenter(c.lng / 180., Wmxy(c).y / 40075019.834677525 * 2.); + return z; } +map.on('load', _ => { + var cont = map.getCanvasContainer(); + var canvas = document.createElement('canvas') + canvas.id = 'good'; + cont.appendChild(canvas) + canvas.style.width = map.getCanvas().style.width; + canvas.style.height = map.getCanvas().style.height; + + function move() { + var b = map.getBounds(); + var nw = b.getNorthWest(); + var c = map.getCenter(); + + renderer.setCenter(c.lng / 180., Wmxy(c).y / 40075019.834677525 * 2.); + renderer.setZoom(getZoom()); + + c = renderer.getCenter(); + var z = renderer.getZoom(); + } + function moveEnd() { + move(); + getData(canvas.clientWidth / canvas.clientHeight); + }; + function resize() { + canvas.style.width = map.getCanvas().style.width; + canvas.style.height = map.getCanvas().style.height; + move(); + } + + renderer = new __WEBPACK_IMPORTED_MODULE_0__src_index__["a" /* Renderer */](canvas); + schema = new __WEBPACK_IMPORTED_MODULE_0__src_index__["b" /* Schema */](['temp', 'daten'], ['float', 'float']); + style = new __WEBPACK_IMPORTED_MODULE_0__src_index__["c" /* Style */].Style(renderer, schema); + const aspect = canvas.clientWidth / canvas.clientHeight; + getData(aspect); + $('#widthStyleEntry').on('input', styleWidth); + $('#colorStyleEntry').on('input', styleColor); + move(); + + map.on('resize', resize); + map.on('movestart', move); + map.on('move', move); + map.on('moveend', moveEnd); + map.on('dragstart', move); + map.on('drag', move); + map.on('dragstart', move); + map.on('dragend', moveEnd); + map.on('zoomstart', move); + map.on('zoom', move); + map.on('zoomend', moveEnd); +}); /***/ }) diff --git a/dist/standalone.js b/dist/standalone.js index 3a9d5beb4..51f9ce615 100644 --- a/dist/standalone.js +++ b/dist/standalone.js @@ -60,2554 +60,667 @@ /******/ __webpack_require__.p = ""; /******/ /******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 8); +/******/ return __webpack_require__(__webpack_require__.s = 23); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ -/***/ (function(module, exports, __webpack_require__) { +/***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; +Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Property", function() { return Property; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Blend", function() { return Blend; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Now", function() { return Now; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Near", function() { return Near; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Color", function() { return Color; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Float", function() { return Float; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RampColor", function() { return RampColor; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FloatMul", function() { return FloatMul; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FloatDiv", function() { return FloatDiv; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FloatAdd", function() { return FloatAdd; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FloatSub", function() { return FloatSub; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FloatPow", function() { return FloatPow; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "setGL", function() { return setGL; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "schemas", function() { return schemas; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_cartocolor__ = __webpack_require__(13); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_cartocolor___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_cartocolor__); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__schema__ = __webpack_require__(17); -var VectorTileFeature = __webpack_require__(1); - -module.exports = VectorTileLayer; - -function VectorTileLayer(pbf, end) { - // Public - this.version = 1; - this.name = null; - this.extent = 4096; - this.length = 0; - - // Private - this._pbf = pbf; - this._keys = []; - this._values = []; - this._features = []; - - pbf.readFields(readLayer, this, end); - - this.length = this._features.length; -} - -function readLayer(tag, layer, pbf) { - if (tag === 15) layer.version = pbf.readVarint(); - else if (tag === 1) layer.name = pbf.readString(); - else if (tag === 5) layer.extent = pbf.readVarint(); - else if (tag === 2) layer._features.push(pbf.pos); - else if (tag === 3) layer._keys.push(pbf.readString()); - else if (tag === 4) layer._values.push(readValueMessage(pbf)); -} - -function readValueMessage(pbf) { - var value = null, - end = pbf.readVarint() + pbf.pos; - - while (pbf.pos < end) { - var tag = pbf.readVarint() >> 3; - value = tag === 1 ? pbf.readString() : - tag === 2 ? pbf.readFloat() : - tag === 3 ? pbf.readDouble() : - tag === 4 ? pbf.readVarint64() : - tag === 5 ? pbf.readVarint() : - tag === 6 ? pbf.readSVarint() : - tag === 7 ? pbf.readBoolean() : null; +function implicitCast(value) { + if (Number.isFinite(value)) { + return Float(value); } - return value; } - -// return feature `i` from this layer as a `VectorTileFeature` -VectorTileLayer.prototype.feature = function(i) { - if (i < 0 || i >= this._features.length) throw new Error('feature index out of bounds'); - - this._pbf.pos = this._features[i]; - - var end = this._pbf.readVarint() + this._pbf.pos; - return new VectorTileFeature(this._pbf, end, this.extent, this._keys, this._values); -}; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +var gl = null; +function setGL(_gl) { + gl = _gl; +} -var Point = __webpack_require__(5); +const schemas = {}; +Object.keys(__WEBPACK_IMPORTED_MODULE_0_cartocolor__).map(name => { + const s = __WEBPACK_IMPORTED_MODULE_0_cartocolor__[name]; + var defaultFound = false; + for (let i = 20; i >= 0; i--) { + if (s[i]) { + if (!defaultFound) { + schemas[name.toLowerCase()] = () => s[i]; + defaultFound = true; + } + schemas[`${name.toLowerCase()}_${i}`] = () => s[i]; + } + } +}); -module.exports = VectorTileFeature; -function VectorTileFeature(pbf, end, extent, keys, values) { - // Public - this.properties = {}; - this.extent = extent; - this.type = 0; +/* + Each styling function should: + - Create their own objects, i.e.: be used without "new" + - Check input validity on user input (constructor and exposed functions). + - Have certain functions that never fail: + - _applyToShaderSource should use uniformIDMaker and propertyTIDMaker to get unique uniform IDs and property IDs as needed + - _postShaderCompile should get uniform location after program compilation as needed + - _preDraw should set any program's uniforms as needed + - isAnimated should return true if the function output could change depending on the timestamp + - Have a type property declaring the GLSL output type: 'float', 'color' +*/ - // Private - this._pbf = pbf; - this._geometry = -1; - this._keys = keys; - this._values = values; +/* + TODO + - Integrated color palettes + - Type checking for color palettes + - Allow multiplication, division and pow() to color expressions and color literals + - Add SetOpacity(colorExpr, opacityFloatOverride) + - HSV + - Think about uniform-only types / parameters + - Think about "Date" and "string" types. + - Heatmaps (renderer should be improved too to accommodate this) +*/ - pbf.readFields(readFeature, this, end); +function Property(name, schema) { + return new _Property(name, schema); } - -function readFeature(tag, feature, pbf) { - if (tag == 1) feature.id = pbf.readVarint(); - else if (tag == 2) readTag(pbf, feature); - else if (tag == 3) feature.type = pbf.readVarint(); - else if (tag == 4) feature._geometry = pbf.pos; +function _Property(name, schema) { + if (typeof name !== 'string' || name == '') { + throw new Error(`Invalid property name '${name}'`); + } + if (!schema[name]) { + throw new Error(`Property name not found`); + } + this.name = name; + this.type = 'float'; + this.schema = schema; +} +_Property.prototype._applyToShaderSource = function (uniformIDMaker, propertyTIDMaker) { + return { + preface: '', + inline: `p${propertyTIDMaker(this.name)}` + }; +} +_Property.prototype._postShaderCompile = function (program) { +} +_Property.prototype._preDraw = function () { +} +_Property.prototype.isAnimated = function () { + return false; } -function readTag(pbf, feature) { - var end = pbf.readVarint() + pbf.pos; - - while (pbf.pos < end) { - var key = feature._keys[pbf.readVarint()], - value = feature._values[pbf.readVarint()]; - feature.properties[key] = value; +function Now(speed) { + return new _Now(speed); +} +function _Now(speed) { + if (speed == undefined) { + speed = 1; + } + if (!Number.isFinite(Number(speed))) { + throw new Error('Now() only accepts number literals'); } + this.speed = Number(speed); + this.type = 'float'; + this.float = Float(0); +} +_Now.prototype._applyToShaderSource = function (uniformIDMaker) { + return this.float._applyToShaderSource(uniformIDMaker); +} +_Now.prototype._postShaderCompile = function (program) { + return this.float._postShaderCompile(program); +} +_Now.prototype._preDraw = function () { + this.float.expr = (Date.now() * this.speed / 1000.) % 1; + this.float._preDraw(); +} +_Now.prototype.isAnimated = function () { + return true; } -VectorTileFeature.types = ['Unknown', 'Point', 'LineString', 'Polygon']; - -VectorTileFeature.prototype.loadGeometry = function() { - var pbf = this._pbf; - pbf.pos = this._geometry; - - var end = pbf.readVarint() + pbf.pos, - cmd = 1, - length = 0, - x = 0, - y = 0, - lines = [], - line; +const FloatMul = genFloatBinaryOperation((x, y) => x * y, (x, y) => `(${x} * ${y})`); +const FloatDiv = genFloatBinaryOperation((x, y) => x / y, (x, y) => `(${x} / ${y})`); +const FloatAdd = genFloatBinaryOperation((x, y) => x + y, (x, y) => `(${x} + ${y})`); +const FloatSub = genFloatBinaryOperation((x, y) => x - y, (x, y) => `(${x} - ${y})`); +const FloatPow = genFloatBinaryOperation((x, y) => Math.pow(x, y), (x, y) => `pow(${x}, ${y})`); - while (pbf.pos < end) { - if (!length) { - var cmdLen = pbf.readVarint(); - cmd = cmdLen & 0x7; - length = cmdLen >> 3; +function genFloatBinaryOperation(jsFn, glsl) { + function BinaryOp(a, b) { + if (Number.isFinite(a) && Number.isFinite(b)) { + return Float(jsFn(a, b)); } - - length--; - - if (cmd === 1 || cmd === 2) { - x += pbf.readSVarint(); - y += pbf.readSVarint(); - - if (cmd === 1) { // moveTo - if (line) lines.push(line); - line = []; - } - - line.push(new Point(x, y)); - - } else if (cmd === 7) { - - // Workaround for https://github.com/mapbox/mapnik-vector-tile/issues/90 - if (line) { - line.push(line[0].clone()); // closePolygon - } - + if (Number.isFinite(a)) { + a = Float(a); + } + if (Number.isFinite(b)) { + b = Float(b); + } + if (a.type == 'float' && b.type == 'float') { + this.type = 'float'; } else { - throw new Error('unknown command ' + cmd); + console.warn(a, b); + throw new Error(`Binary operation cannot be performed between '${a}' and '${b}'`); } + return new _BinaryOp(a, b); } - - if (line) lines.push(line); - - return lines; -}; - -VectorTileFeature.prototype.bbox = function() { - var pbf = this._pbf; - pbf.pos = this._geometry; - - var end = pbf.readVarint() + pbf.pos, - cmd = 1, - length = 0, - x = 0, - y = 0, - x1 = Infinity, - x2 = -Infinity, - y1 = Infinity, - y2 = -Infinity; - - while (pbf.pos < end) { - if (!length) { - var cmdLen = pbf.readVarint(); - cmd = cmdLen & 0x7; - length = cmdLen >> 3; - } - - length--; - - if (cmd === 1 || cmd === 2) { - x += pbf.readSVarint(); - y += pbf.readSVarint(); - if (x < x1) x1 = x; - if (x > x2) x2 = x; - if (y < y1) y1 = y; - if (y > y2) y2 = y; - - } else if (cmd !== 7) { - throw new Error('unknown command ' + cmd); - } + function _BinaryOp(a, b) { + this.type = 'float'; + this.a = a; + this.b = b; + a.parent = this; + b.parent = this; } - - return [x1, y1, x2, y2]; -}; - -VectorTileFeature.prototype.toGeoJSON = function(x, y, z) { - var size = this.extent * Math.pow(2, z), - x0 = this.extent * x, - y0 = this.extent * y, - coords = this.loadGeometry(), - type = VectorTileFeature.types[this.type], - i, j; - - function project(line) { - for (var j = 0; j < line.length; j++) { - var p = line[j], y2 = 180 - (p.y + y0) * 360 / size; - line[j] = [ - (p.x + x0) * 360 / size - 180, - 360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90 - ]; - } + _BinaryOp.prototype._applyToShaderSource = function (uniformIDMaker, propertyTIDMaker) { + const a = this.a._applyToShaderSource(uniformIDMaker, propertyTIDMaker); + const b = this.b._applyToShaderSource(uniformIDMaker, propertyTIDMaker); + return { + preface: a.preface + b.preface, + inline: glsl(a.inline, b.inline) + }; } - - switch (this.type) { - case 1: - var points = []; - for (i = 0; i < coords.length; i++) { - points[i] = coords[i][0]; - } - coords = points; - project(coords); - break; - - case 2: - for (i = 0; i < coords.length; i++) { - project(coords[i]); - } - break; - - case 3: - coords = classifyRings(coords); - for (i = 0; i < coords.length; i++) { - for (j = 0; j < coords[i].length; j++) { - project(coords[i][j]); - } - } - break; + _BinaryOp.prototype._postShaderCompile = function (program) { + this.a._postShaderCompile(program); + this.b._postShaderCompile(program); } - - if (coords.length === 1) { - coords = coords[0]; - } else { - type = 'Multi' + type; + _BinaryOp.prototype._preDraw = function (l) { + this.a._preDraw(l); + this.b._preDraw(l); } - - var result = { - type: "Feature", - geometry: { - type: type, - coordinates: coords - }, - properties: this.properties - }; - - if ('id' in this) { - result.id = this.id; + _BinaryOp.prototype.isAnimated = function () { + return this.a.isAnimated() || this.b.isAnimated(); } - - return result; -}; - -// classifies an array of rings into polygons with outer rings and holes - -function classifyRings(rings) { - var len = rings.length; - - if (len <= 1) return [rings]; - - var polygons = [], - polygon, - ccw; - - for (var i = 0; i < len; i++) { - var area = signedArea(rings[i]); - if (area === 0) continue; - - if (ccw === undefined) ccw = area < 0; - - if (ccw === area < 0) { - if (polygon) polygons.push(polygon); - polygon = [rings[i]]; - + _BinaryOp.prototype.replaceChild = function (toReplace, replacer) { + if (this.a = toReplace) { + this.a = replacer; } else { - polygon.push(rings[i]); + this.b = replacer; } + replacer.parent = this; + replacer.notify = toReplace.notify; } - if (polygon) polygons.push(polygon); - - return polygons; -} - -function signedArea(ring) { - var sum = 0; - for (var i = 0, len = ring.length, j = len - 1, p1, p2; i < len; j = i++) { - p1 = ring[i]; - p2 = ring[j]; - sum += (p2.x - p1.x) * (p1.y + p2.y); + _BinaryOp.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { + genericBlend(this, finalValue, duration, blendFunc); } - return sum; + return BinaryOp; } - -/***/ }), -/* 2 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Renderer; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__shaders__ = __webpack_require__(12); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__style__ = __webpack_require__(20); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__scheme__ = __webpack_require__(25); -/* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "c", function() { return __WEBPACK_IMPORTED_MODULE_1__style__; }); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return __WEBPACK_IMPORTED_MODULE_2__scheme__["a"]; }); - - - - -// TODO remove -var gl; - -// The maximum number of features per tile is RTT_WIDTH^2, large RTT_WIDTH values can be unsupported by the hardware, -// they imply a small waste of resources too -const RTT_WIDTH = 1024; - -Renderer.prototype._initShaders = function () { - this.finalRendererProgram = __WEBPACK_IMPORTED_MODULE_0__shaders__["a" /* renderer */].createPointShader(gl); +function Animation(duration) { + return new _Animation(duration); } - -Renderer.prototype.refresh = refresh; -function refresh(timestamp) { - // Don't re-render more than once per animation frame - if (this.lastFrame == timestamp) { - return; +function _Animation(duration) { + if (!Number.isFinite(duration)) { + throw new Error("Animation only supports number literals"); } - this.lastFrame = timestamp; - var canvas = this.canvas; - var width = gl.canvas.clientWidth; - var height = gl.canvas.clientHeight; - if (gl.canvas.width != width || - gl.canvas.height != height) { - gl.canvas.width = width; - gl.canvas.height = height; + this.type = 'float'; + this.aTime = Date.now(); + this.bTime = this.aTime + Number(duration); +} +_Animation.prototype._applyToShaderSource = function (uniformIDMaker, propertyTIDMaker) { + this._uniformID = uniformIDMaker(); + return { + preface: `uniform float anim${this._uniformID};\n`, + inline: `anim${this._uniformID}` + }; +} +_Animation.prototype._postShaderCompile = function (program) { + this._uniformLocation = gl.getUniformLocation(program, `anim${this._uniformID}`); +} +_Animation.prototype._preDraw = function (l) { + const time = Date.now(); + this.mix = (time - this.aTime) / (this.bTime - this.aTime); + if (this.mix > 1.) { + gl.uniform1f(this._uniformLocation, 1); + } else { + gl.uniform1f(this._uniformLocation, this.mix); } - var aspect = canvas.clientWidth / canvas.clientHeight; - gl.clearColor(0., 0., 0., 0.);//TODO this should be a renderer property - gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); - - gl.enable(gl.CULL_FACE); - - //TODO refactor condition - gl.disable(gl.BLEND); - gl.disable(gl.DEPTH_TEST); +} +_Animation.prototype.isAnimated = function () { + return !this.mix || this.mix <= 1.; +} - if (!this.auxFB) { - this.auxFB = gl.createFramebuffer(); +function Near(property, center, threshold, falloff) { + const args = [property, center, threshold, falloff].map(implicitCast); + if (args.some(x => x === undefined || x === null)) { + throw new Error(`Invalid arguments to Near(): ${args}`); } - gl.bindFramebuffer(gl.FRAMEBUFFER, this.auxFB); - //console.log("Restyle", timestamp) - // Render To Texture - // COLOR - this.tiles.forEach(tile => { - gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tile.texColor, 0); - gl.viewport(0, 0, RTT_WIDTH, tile.height); - gl.clear(gl.COLOR_BUFFER_BIT); - - gl.useProgram(tile.style.colorShader.program); - var obj = { - freeTexUnit: 4 - } - tile.style._color._preDraw(obj); + return new _Near(...args); +} - Object.keys(tile.style.propertyColorTID).forEach((name, i) => { - gl.activeTexture(gl.TEXTURE0 + i); - gl.bindTexture(gl.TEXTURE_2D, tile.propertyTex[tile.propertyID[name]]); - gl.uniform1i(tile.style.colorShader.textureLocations[i], i); - }); - - gl.enableVertexAttribArray(this.colorShaderVertex); - gl.bindBuffer(gl.ARRAY_BUFFER, this.squareBuffer); - gl.vertexAttribPointer(tile.style.colorShader.vertexAttribute, 2, gl.FLOAT, false, 0, 0); - - gl.drawArrays(gl.TRIANGLES, 0, 3); - }); - - //WIDTH - this.tiles.forEach(tile => { - gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tile.texWidth, 0); - gl.useProgram(tile.style.widthShader.program); - gl.viewport(0, 0, RTT_WIDTH, tile.height); - gl.clear(gl.COLOR_BUFFER_BIT); - var obj = { - freeTexUnit: 4 - } - tile.style._width._preDraw(obj); - Object.keys(tile.style.propertyWidthTID).forEach((name, i) => { - gl.activeTexture(gl.TEXTURE0 + i); - gl.bindTexture(gl.TEXTURE_2D, tile.propertyTex[tile.propertyID[name]]); - gl.uniform1i(tile.style.widthShader.textureLocations[i], i); - }); - - gl.enableVertexAttribArray(tile.style.widthShader.vertexAttribute); - gl.bindBuffer(gl.ARRAY_BUFFER, this.squareBuffer); - gl.vertexAttribPointer(tile.style.widthShader.vertexAttribute, 2, gl.FLOAT, false, 0, 0); - - gl.drawArrays(gl.TRIANGLES, 0, 3); - - tile.style.updated = false; - tile.initialized = true; - }); - - - gl.enable(gl.DEPTH_TEST); - - gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); - gl.enable(gl.BLEND); - - gl.bindFramebuffer(gl.FRAMEBUFFER, null); - gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); - - gl.useProgram(this.finalRendererProgram.program); - var s = 1. / this._zoom; - - - this.tiles.forEach(tile => { - /*console.log((s / aspect) * tile.scale, - s * tile.scale, - (s / aspect) * this._center.x - tile.center.x, - s * this._center.y - tile.center.y - );*/ - gl.uniform2f(this.finalRendererProgram.vertexScaleUniformLocation, - (s / aspect) * tile.scale, - s * tile.scale); - gl.uniform2f(this.finalRendererProgram.vertexOffsetUniformLocation, - (s / aspect) * (this._center.x - tile.center.x), - s * (this._center.y - tile.center.y)); - - gl.enableVertexAttribArray(this.finalRendererProgram.vertexPositionAttribute); - gl.bindBuffer(gl.ARRAY_BUFFER, tile.vertexBuffer); - gl.vertexAttribPointer(this.finalRendererProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); +function _Near(input, center, threshold, falloff) { + if (input.type != 'float' || center.type != 'float' || threshold.type != 'float' || falloff.type != 'float') { + throw new Error('Near(): invalid parameter type'); + } + this.type = 'float'; + this.input = input; + this.center = center; + this.threshold = threshold; + this.falloff = falloff; +} +_Near.prototype._applyToShaderSource = function (uniformIDMaker, propertyTIDMaker) { + this._UID = uniformIDMaker(); + const tid = propertyTIDMaker(this.property); + const input = this.input._applyToShaderSource(uniformIDMaker, propertyTIDMaker); + const center = this.center._applyToShaderSource(uniformIDMaker, propertyTIDMaker); + const threshold = this.threshold._applyToShaderSource(uniformIDMaker, propertyTIDMaker); + const falloff = this.falloff._applyToShaderSource(uniformIDMaker, propertyTIDMaker); + return { + preface: + input.preface + center.preface + threshold.preface + falloff.preface, + inline: `1.-clamp((abs(${input.inline}-${center.inline})-${threshold.inline})/${falloff.inline}, + 0., 1.)` + }; +} +_Near.prototype._postShaderCompile = function (program) { + this.center._postShaderCompile(program); + this.threshold._postShaderCompile(program); + this.falloff._postShaderCompile(program); + this.input._postShaderCompile(program); +} +_Near.prototype._preDraw = function () { + this.center._preDraw(); + this.threshold._preDraw(); + this.falloff._preDraw(); + this.input._preDraw(); +} +_Near.prototype.isAnimated = function () { + return this.center.isAnimated(); +} - gl.enableVertexAttribArray(this.finalRendererProgram.featureIdAttr); - gl.bindBuffer(gl.ARRAY_BUFFER, tile.featureIDBuffer); - gl.vertexAttribPointer(this.finalRendererProgram.featureIdAttr, 2, gl.FLOAT, false, 0, 0); - gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, tile.texColor); - gl.uniform1i(this.finalRendererProgram.colorTexture, 0); +function Blend(a, b, mix) { + const args = [a, b, mix].map(implicitCast); + if (args.some(x => x === undefined || x === null)) { + throw new Error(`Invalid arguments to Blend(): ${args}`); + } + return new _Blend(...args); +} +function _Blend(a, b, mix) { + if (a.type == 'float' && b.type == 'float') { + this.type = 'float'; + } else if (a.type == 'color' && b.type == 'color') { + this.type = 'color'; + } else { + console.warn(a, b); + throw new Error(`Blending cannot be performed between types '${a.type}' and '${b.type}'`); + } + if (__WEBPACK_IMPORTED_MODULE_1__schema__["b" /* checkschemaMatch */](a.schema, b.schema)) { + throw new Error('Blend parameters schemas mismatch'); + } + this.schema = a.schema; + this.a = a; + this.b = b; + this.mix = mix; + a.parent = this; + b.parent = this; + mix.parent = this; +} +_Blend.prototype._applyToShaderSource = function (uniformIDMaker, propertyTIDMaker) { + const a = this.a._applyToShaderSource(uniformIDMaker, propertyTIDMaker); + const b = this.b._applyToShaderSource(uniformIDMaker, propertyTIDMaker); + const mix = this.mix._applyToShaderSource(uniformIDMaker, propertyTIDMaker); + return { + preface: `${a.preface}${b.preface}${mix.preface}`, + inline: `mix(${a.inline}, ${b.inline}, ${mix.inline})` + }; +} +_Blend.prototype._postShaderCompile = function (program) { + this.a._postShaderCompile(program); + this.b._postShaderCompile(program); + this.mix._postShaderCompile(program); +} +_Blend.prototype._preDraw = function (l) { + this.a._preDraw(l); + this.b._preDraw(l); + this.mix._preDraw(l); + if (this.mix instanceof _Animation && !this.mix.isAnimated()) { + this.parent.replaceChild(this, this.b); + } +} +_Blend.prototype.isAnimated = function () { + return this.a.isAnimated() || this.b.isAnimated() || this.mix.isAnimated(); +} +_Blend.prototype.replaceChild = function (toReplace, replacer) { + if (this.a = toReplace) { + this.a = replacer; + } else { + this.b = replacer; + } + replacer.parent = this; + replacer.notify = toReplace.notify; +} - gl.activeTexture(gl.TEXTURE1); - gl.bindTexture(gl.TEXTURE_2D, tile.texWidth); - gl.uniform1i(this.finalRendererProgram.widthTexture, 1); +function genericBlend(initial, final, duration, blendFunc) { + const parent = initial.parent; + const blend = Blend(initial, final, Animation(duration)); + parent.replaceChild(initial, blend); + blend.notify(); +} +UniformColor.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { + genericBlend(this, finalValue, duration, blendFunc); +} +_RampColor.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { + genericBlend(this, finalValue, duration, blendFunc); +} - gl.drawArrays(gl.POINTS, 0, tile.numVertex); +_Near.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { + genericBlend(this, finalValue, duration, blendFunc); +} +UniformFloat.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { + genericBlend(this, finalValue, duration, blendFunc); +} +_Blend.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { + genericBlend(this, finalValue, duration, blendFunc); +} +_Property.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { + genericBlend(this, finalValue, duration, blendFunc); +} - }); - this.tiles.forEach(t => { - if (t.style._color.isAnimated() || t.style._width.isAnimated()) { - window.requestAnimationFrame(refresh.bind(this)); +function Color(color) { + if (Array.isArray(color)) { + color = color.filter(x => true); + if (color.length != 4 || !color.every(Number.isFinite)) { + throw new Error(`Invalid arguments to Color(): ${args}`); } + return new UniformColor(color); + } + throw new Error(`Invalid arguments to Color(): ${args}`); +} +function UniformColor(color) { + this.type = 'color'; + this.color = color; +} +UniformColor.prototype._applyToShaderSource = function (uniformIDMaker) { + this._uniformID = uniformIDMaker(); + return { + preface: `uniform vec4 color${this._uniformID};\n`, + inline: `color${this._uniformID}` + }; +} +UniformColor.prototype._postShaderCompile = function (program) { + this._uniformLocation = gl.getUniformLocation(program, `color${this._uniformID}`); +} +function evalColor(color, time) { + if (Array.isArray(color)) { + return color; + } + var a = evalColor(color.a, time); + var b = evalColor(color.b, time); + var m = (time - color.aTime) / (color.bTime - color.aTime); + return a.map((va, index) => { + return (1 - m) * va + m * b[index];//TODO non linear functions }); } - -Renderer.prototype.removeTile = function (tile) { - this.tiles = this.tiles.filter(t => t !== tile); - tile.propertyTex.map(tex => gl.deleteTexture(tex)); - gl.deleteTexture(tile.texColor); - gl.deleteTexture(tile.texWidth); - gl.deleteBuffer(tile.vertexBuffer); - gl.deleteBuffer(tile.featureIDBuffer); +function simplifyColorExpr(color, time) { + if (Array.isArray(color)) { + return color; + } + var m = (time - color.aTime) / (color.bTime - color.aTime); + if (m >= 1) { + return color.b; + } + return color; +} +UniformColor.prototype._preDraw = function () { + const t = Date.now(); + this.color = simplifyColorExpr(this.color, t); + const color = evalColor(this.color, t); + gl.uniform4f(this._uniformLocation, color[0], color[1], color[2], color[3]); +} +UniformColor.prototype.isAnimated = function () { + return false; } -Renderer.prototype.addTile = function (tile) { - this.tiles.push(tile); - tile.propertyTex = []; - - var points = tile.geom; - const level = 0; - const width = RTT_WIDTH; - tile.numVertex = points.length / 2; - const height = Math.ceil(tile.numVertex / width); - const border = 0; - const srcFormat = gl.RED; - const srcType = gl.FLOAT; - tile.height = height; - tile.propertyID = {}; //Name => PID - tile.propertyCount = 0; - - - for (var k in tile.properties) { - if (tile.properties.hasOwnProperty(k) && tile.properties[k].length > 0) { - const isCategory = !Number.isFinite(tile.properties[k][0]); - const property = tile.properties[k]; - var propertyID = tile.propertyID[k]; - if (propertyID === undefined) { - propertyID = tile.propertyCount; - tile.propertyCount++; - tile.propertyID[k] = propertyID; - } - tile.propertyTex[propertyID] = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, tile.propertyTex[propertyID]); - const pixel = new Float32Array(width * height); - for (var i = 0; i < property.length; i++) { - pixel[i] = property[i]; - } - gl.texImage2D(gl.TEXTURE_2D, level, gl.ALPHA, - width, height, 0, gl.ALPHA, srcType, - pixel); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); - } +function Float(x) { + if (!Number.isFinite(x)) { + throw new Error(`Invalid arguments to Float(): ${args}`); } + return new UniformFloat(x); +} - tile.setStyle = function (style) { - __WEBPACK_IMPORTED_MODULE_2__scheme__["b" /* checkSchemeMatch */](style.scheme, tile.scheme); - this.style = style; +function UniformFloat(size) { + this.type = 'float'; + this.expr = size; +} +UniformFloat.prototype._applyToShaderSource = function (uniformIDMaker) { + this._uniformID = uniformIDMaker(); + return { + preface: `uniform float float${this._uniformID};\n`, + inline: `float${this._uniformID}` + }; +} +UniformFloat.prototype._postShaderCompile = function (program) { + this._uniformLocation = gl.getUniformLocation(program, `float${this._uniformID}`); +} +function evalFloatExpr(expr, time) { + if (Number.isFinite(expr)) { + return expr; } - tile.style = null; - - tile.vertexBuffer = gl.createBuffer(); - tile.featureIDBuffer = gl.createBuffer(); - - - tile.texColor = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, tile.texColor); - gl.texImage2D(gl.TEXTURE_2D, level, gl.RGBA, - width, height, border, gl.RGBA, gl.UNSIGNED_BYTE, - new Uint8Array(4 * width * height).fill(255)); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); - - tile.texWidth = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, tile.texWidth); - gl.texImage2D(gl.TEXTURE_2D, level, gl.RGBA, - width, height, border, gl.RGBA, gl.UNSIGNED_BYTE, - new Uint8Array(4 * width * height).fill(100)); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); - - - - var ids = new Float32Array(points.length); - for (var i = 0; i < points.length; i += 2) { - ids[i + 0] = ((i / 2) % width) / width; - ids[i + 1] = Math.floor((i / 2) / width) / height; + if (typeof expr === "function") { + return x(time); } - - gl.bindBuffer(gl.ARRAY_BUFFER, tile.vertexBuffer); - gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW); - - gl.bindBuffer(gl.ARRAY_BUFFER, tile.featureIDBuffer); - gl.bufferData(gl.ARRAY_BUFFER, ids, gl.STATIC_DRAW); - - gl.bindBuffer(gl.ARRAY_BUFFER, null); - - window.requestAnimationFrame(refresh.bind(this)); - - return tile; + return expr.eval(); } - -/** - * THIS IS A RENDERER. - * @constructor - * @param {HTMLElement} canvas - */ -function Renderer(canvas) { - this.canvas = canvas; - this.tiles = []; - if (!gl) { - gl = canvas.getContext('webgl'); - __WEBPACK_IMPORTED_MODULE_1__style__["setGL"](gl); - var ext = gl.getExtension("OES_texture_float"); - if (!ext) { - console.error("this machine or browser does not support OES_texture_float"); - } - if (!gl) { - console.warn('Unable to initialize WebGL2. Your browser may not support it.'); - return null - } - this._initShaders(); - this._center = { x: 0, y: 0 }; - this._zoom = 1; +function simplifyFloatExpr(expr, time) { + if (Number.isFinite(expr)) { + return expr; } - this.squareBuffer = gl.createBuffer(); - gl.bindBuffer(gl.ARRAY_BUFFER, this.squareBuffer); - var vertices = [ - 10.0, -10.0, - 0.0, 10.0, - -10.0, -10.0, - ]; - gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); + return expr.simplify(); +} +UniformFloat.prototype._preDraw = function (time) { + this.expr = simplifyFloatExpr(this.expr, time); + const v = evalFloatExpr(this.expr, time); + gl.uniform1f(this._uniformLocation, v); +} +UniformFloat.prototype.isAnimated = function () { + return !Number.isFinite(this.expr); } -/** - * Wadus qwuasdfdasfasd fsadfads - * @api Get Renderer center in Renderer coordinates - * @param {fff} - * @name Renderer#getCenter - */ -Renderer.prototype.getCenter = function () { - return { x: this._center.x, y: this._center.y }; -}; +function hexToRgb(hex) { + var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); + return result ? { + r: parseInt(result[1], 16), + g: parseInt(result[2], 16), + b: parseInt(result[3], 16) + } : null; +} -Renderer.prototype.setCenter = function (x, y) { - this._center.x = x; - this._center.y = y; - window.requestAnimationFrame(refresh.bind(this)); -}; -Renderer.prototype.getZoom = function () { - return this._zoom; -} -Renderer.prototype.setZoom = function (zoom) { - this._zoom = zoom; - window.requestAnimationFrame(refresh.bind(this)); +function RampColor(input, minKey, maxKey, values) { + //TODO contiunuos vs discrete should be decided based on input type => cartegory vs float + const args = [input, minKey, maxKey, values].map(implicitCast); + if (args.some(x => x === undefined || x === null)) { + throw new Error(`Invalid arguments to RampColor(): ${args}`); + } + return new _RampColor(...args); } +//Palette => used by Ramp, Ramp gets texture2D from palette by asking for number of buckets (0/interpolated palette, 2,3,4,5,6...) +function _RampColor(input, minKey, maxKey, values) { + this.type = 'color'; + this.input = input; + this.minKey = minKey.expr; + this.maxKey = maxKey.expr; + this.values = values; + this.texture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, this.texture); + const level = 0; + const internalFormat = gl.RGBA; + const width = 256; + const height = 1; + const border = 0; + const srcFormat = gl.RGBA; + const srcType = gl.UNSIGNED_BYTE; + const pixel = new Uint8Array(4 * width); + for (var i = 0; i < width; i++) { + const vlowRaw = values[Math.floor(i / width * (values.length - 1))]; + const vhighRaw = values[Math.ceil(i / width * (values.length - 1))]; + const vlow = [hexToRgb(vlowRaw).r, hexToRgb(vlowRaw).g, hexToRgb(vlowRaw).b, 255]; + const vhigh = [hexToRgb(vhighRaw).r, hexToRgb(vhighRaw).g, hexToRgb(vhighRaw).b, 255]; + const m = i / width * (values.length - 1) - Math.floor(i / width * (values.length - 1)); + const v = vlow.map((low, index) => low * (1. - m) + vhigh[index] * m); + pixel[4 * i + 0] = v[0]; + pixel[4 * i + 1] = v[1]; + pixel[4 * i + 2] = v[2]; + pixel[4 * i + 3] = v[3]; + } -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { + gl.texImage2D(gl.TEXTURE_2D, level, internalFormat, + width, height, border, srcFormat, srcType, + pixel); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); +} -module.exports.VectorTile = __webpack_require__(4); -module.exports.VectorTileFeature = __webpack_require__(1); -module.exports.VectorTileLayer = __webpack_require__(0); +_RampColor.prototype._free = function () { + gl.deleteTexture(this.texture); +} +_RampColor.prototype._applyToShaderSource = function (uniformIDMaker, propertyTIDMaker) { + this._UID = uniformIDMaker(); + const input = this.input._applyToShaderSource(uniformIDMaker, propertyTIDMaker); + return { + preface: input.preface + ` + uniform sampler2D texRamp${this._UID}; + uniform float keyMin${this._UID}; + uniform float keyWidth${this._UID}; + `, + inline: `texture2D(texRamp${this._UID}, vec2((${input.inline}-keyMin${this._UID})/keyWidth${this._UID}, 0.5)).rgba` + }; +} +_RampColor.prototype._postShaderCompile = function (program) { + this.input._postShaderCompile(program); + this._texLoc = gl.getUniformLocation(program, `texRamp${this._UID}`); + this._keyMinLoc = gl.getUniformLocation(program, `keyMin${this._UID}`); + this._keyWidthLoc = gl.getUniformLocation(program, `keyWidth${this._UID}`); +} +_RampColor.prototype._preDraw = function (l) { + this.input._preDraw(l); + gl.activeTexture(gl.TEXTURE0 + l.freeTexUnit);//TODO remove hardcode + gl.bindTexture(gl.TEXTURE_2D, this.texture); + gl.uniform1i(this._texLoc, l.freeTexUnit); + gl.uniform1f(this._keyMinLoc, evalFloatExpr(this.minKey)); + gl.uniform1f(this._keyWidthLoc, evalFloatExpr(this.maxKey) - evalFloatExpr(this.minKey)); + l.freeTexUnit++; +} +_RampColor.prototype.isAnimated = function () { + return false; +} /***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { +/* 1 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return renderer; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return styler; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__renderer__ = __webpack_require__(7); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__styler__ = __webpack_require__(9); -var VectorTileLayer = __webpack_require__(0); -module.exports = VectorTile; +const NUM_TEXTURE_LOCATIONS = 4; -function VectorTile(pbf, end) { - this.layers = pbf.readFields(readTile, {}, end); +function compileShader(gl, sourceCode, type) { + const shader = gl.createShader(type); + gl.shaderSource(shader, sourceCode); + gl.compileShader(shader); + if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { + const log = gl.getShaderInfoLog(shader); + gl.deleteShader(shader); + throw new Error('An error occurred compiling the shaders: ' + log + '\nSource:\n' + sourceCode); + } + return shader; } -function readTile(tag, layers, pbf) { - if (tag === 3) { - var layer = new VectorTileLayer(pbf, pbf.readVarint() + pbf.pos); - if (layer.length) layers[layer.name] = layer; +function compileProgram(gl, glslVS, glslFS) { + const VS = compileShader(gl, glslVS, gl.VERTEX_SHADER); + const FS = compileShader(gl, glslFS, gl.FRAGMENT_SHADER); + this.program = gl.createProgram(); + gl.attachShader(this.program, VS); + gl.attachShader(this.program, FS); + gl.linkProgram(this.program); + gl.deleteShader(VS); + gl.deleteShader(FS); + if (!gl.getProgramParameter(this.program, gl.LINK_STATUS)) { + throw new Error('Unable to link the shader program: ' + gl.getProgramInfoLog(this.program)); } } - - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -module.exports = Point; - -/** - * A standalone point geometry with useful accessor, comparison, and - * modification methods. - * - * @class Point - * @param {Number} x the x-coordinate. this could be longitude or screen - * pixels, or any other sort of unit. - * @param {Number} y the y-coordinate. this could be latitude or screen - * pixels, or any other sort of unit. - * @example - * var point = new Point(-77, 38); - */ -function Point(x, y) { - this.x = x; - this.y = y; +function Point(gl) { + compileProgram.call(this, gl, __WEBPACK_IMPORTED_MODULE_0__renderer__["a" /* point */].VS, __WEBPACK_IMPORTED_MODULE_0__renderer__["a" /* point */].FS); + this.vertexPositionAttribute = gl.getAttribLocation(this.program, 'vertexPosition'); + this.featureIdAttr = gl.getAttribLocation(this.program, 'featureID'); + this.vertexScaleUniformLocation = gl.getUniformLocation(this.program, 'vertexScale'); + this.vertexOffsetUniformLocation = gl.getUniformLocation(this.program, 'vertexOffset'); + this.colorTexture = gl.getUniformLocation(this.program, 'colorTex'); + this.widthTexture = gl.getUniformLocation(this.program, 'widthTex'); +} +function GenericStyler(gl, glsl, preface, inline) { + const VS = glsl.VS; + let FS = glsl.FS; + FS = FS.replace('$PREFACE', preface); + FS = FS.replace('$INLINE', inline); + //console.log(FS) + compileProgram.call(this, gl, VS, FS); + this.vertexAttribute = gl.getAttribLocation(this.program, 'vertex'); + this.textureLocations = []; + for (let i = 0; i < NUM_TEXTURE_LOCATIONS; i++) { + this.textureLocations[i] = gl.getUniformLocation(this.program, `property${i}`); + } +} +function Color(gl, preface, inline) { + GenericStyler.call(this, gl, __WEBPACK_IMPORTED_MODULE_1__styler__["a" /* color */], preface, inline); +} +function Width(gl, preface, inline) { + GenericStyler.call(this, gl, __WEBPACK_IMPORTED_MODULE_1__styler__["b" /* width */], preface, inline); } -Point.prototype = { - - /** - * Clone this point, returning a new point that can be modified - * without affecting the old one. - * @return {Point} the clone - */ - clone: function() { return new Point(this.x, this.y); }, - - /** - * Add this point's x & y coordinates to another point, - * yielding a new point. - * @param {Point} p the other point - * @return {Point} output point - */ - add: function(p) { return this.clone()._add(p); }, - - /** - * Subtract this point's x & y coordinates to from point, - * yielding a new point. - * @param {Point} p the other point - * @return {Point} output point - */ - sub: function(p) { return this.clone()._sub(p); }, - - /** - * Multiply this point's x & y coordinates by point, - * yielding a new point. - * @param {Point} p the other point - * @return {Point} output point - */ - multByPoint: function(p) { return this.clone()._multByPoint(p); }, - - /** - * Divide this point's x & y coordinates by point, - * yielding a new point. - * @param {Point} p the other point - * @return {Point} output point - */ - divByPoint: function(p) { return this.clone()._divByPoint(p); }, - - /** - * Multiply this point's x & y coordinates by a factor, - * yielding a new point. - * @param {Point} k factor - * @return {Point} output point - */ - mult: function(k) { return this.clone()._mult(k); }, - - /** - * Divide this point's x & y coordinates by a factor, - * yielding a new point. - * @param {Point} k factor - * @return {Point} output point - */ - div: function(k) { return this.clone()._div(k); }, - - /** - * Rotate this point around the 0, 0 origin by an angle a, - * given in radians - * @param {Number} a angle to rotate around, in radians - * @return {Point} output point - */ - rotate: function(a) { return this.clone()._rotate(a); }, - - /** - * Rotate this point around p point by an angle a, - * given in radians - * @param {Number} a angle to rotate around, in radians - * @param {Point} p Point to rotate around - * @return {Point} output point - */ - rotateAround: function(a,p) { return this.clone()._rotateAround(a,p); }, - - /** - * Multiply this point by a 4x1 transformation matrix - * @param {Array} m transformation matrix - * @return {Point} output point - */ - matMult: function(m) { return this.clone()._matMult(m); }, - - /** - * Calculate this point but as a unit vector from 0, 0, meaning - * that the distance from the resulting point to the 0, 0 - * coordinate will be equal to 1 and the angle from the resulting - * point to the 0, 0 coordinate will be the same as before. - * @return {Point} unit vector point - */ - unit: function() { return this.clone()._unit(); }, - - /** - * Compute a perpendicular point, where the new y coordinate - * is the old x coordinate and the new x coordinate is the old y - * coordinate multiplied by -1 - * @return {Point} perpendicular point - */ - perp: function() { return this.clone()._perp(); }, - - /** - * Return a version of this point with the x & y coordinates - * rounded to integers. - * @return {Point} rounded point - */ - round: function() { return this.clone()._round(); }, - - /** - * Return the magitude of this point: this is the Euclidean - * distance from the 0, 0 coordinate to this point's x and y - * coordinates. - * @return {Number} magnitude - */ - mag: function() { - return Math.sqrt(this.x * this.x + this.y * this.y); - }, +const renderer = { + createPointShader: function (gl) { + return new Point(gl); + } +}; - /** - * Judge whether this point is equal to another point, returning - * true or false. - * @param {Point} other the other point - * @return {boolean} whether the points are equal - */ - equals: function(other) { - return this.x === other.x && - this.y === other.y; +const styler = { + createColorShader: function (gl, preface, inline) { + return new Color(gl, preface, inline); }, + createWidthShader: function (gl, preface, inline) { + return new Width(gl, preface, inline); + } +}; - /** - * Calculate the distance from this point to another point - * @param {Point} p the other point - * @return {Number} distance - */ - dist: function(p) { - return Math.sqrt(this.distSqr(p)); - }, - /** - * Calculate the distance from this point to another point, - * without the square root step. Useful if you're comparing - * relative distances. - * @param {Point} p the other point - * @return {Number} distance - */ - distSqr: function(p) { - var dx = p.x - this.x, - dy = p.y - this.y; - return dx * dx + dy * dy; - }, - /** - * Get the angle from the 0, 0 coordinate to this point, in radians - * coordinates. - * @return {Number} angle - */ - angle: function() { - return Math.atan2(this.y, this.x); - }, - /** - * Get the angle from this point to another point, in radians - * @param {Point} b the other point - * @return {Number} angle - */ - angleTo: function(b) { - return Math.atan2(this.y - b.y, this.x - b.x); - }, - - /** - * Get the angle between this point and another point, in radians - * @param {Point} b the other point - * @return {Number} angle - */ - angleWith: function(b) { - return this.angleWithSep(b.x, b.y); - }, - - /* - * Find the angle of the two vectors, solving the formula for - * the cross product a x b = |a||b|sin(θ) for θ. - * @param {Number} x the x-coordinate - * @param {Number} y the y-coordinate - * @return {Number} the angle in radians - */ - angleWithSep: function(x, y) { - return Math.atan2( - this.x * y - this.y * x, - this.x * x + this.y * y); - }, - - _matMult: function(m) { - var x = m[0] * this.x + m[1] * this.y, - y = m[2] * this.x + m[3] * this.y; - this.x = x; - this.y = y; - return this; - }, - - _add: function(p) { - this.x += p.x; - this.y += p.y; - return this; - }, - - _sub: function(p) { - this.x -= p.x; - this.y -= p.y; - return this; - }, - - _mult: function(k) { - this.x *= k; - this.y *= k; - return this; - }, - - _div: function(k) { - this.x /= k; - this.y /= k; - return this; - }, - - _multByPoint: function(p) { - this.x *= p.x; - this.y *= p.y; - return this; - }, - - _divByPoint: function(p) { - this.x /= p.x; - this.y /= p.y; - return this; - }, - - _unit: function() { - this._div(this.mag()); - return this; - }, - - _perp: function() { - var y = this.y; - this.y = this.x; - this.x = -y; - return this; - }, - - _rotate: function(angle) { - var cos = Math.cos(angle), - sin = Math.sin(angle), - x = cos * this.x - sin * this.y, - y = sin * this.x + cos * this.y; - this.x = x; - this.y = y; - return this; - }, - - _rotateAround: function(angle, p) { - var cos = Math.cos(angle), - sin = Math.sin(angle), - x = p.x + cos * (this.x - p.x) - sin * (this.y - p.y), - y = p.y + sin * (this.x - p.x) + cos * (this.y - p.y); - this.x = x; - this.y = y; - return this; - }, - - _round: function() { - this.x = Math.round(this.x); - this.y = Math.round(this.y); - return this; - } -}; - -/** - * Construct a point from an array if necessary, otherwise if the input - * is already a Point, or an unknown type, return it unchanged - * @param {Array|Point|*} a any kind of input value - * @return {Point} constructed point, or passed-through value. - * @example - * // this - * var point = Point.convert([0, 1]); - * // is equivalent to - * var point = new Point(0, 1); - */ -Point.convert = function (a) { - if (a instanceof Point) { - return a; - } - if (Array.isArray(a)) { - return new Point(a[0], a[1]); - } - return a; -}; - - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -module.exports = Pbf; - -var ieee754 = __webpack_require__(7); - -function Pbf(buf) { - this.buf = ArrayBuffer.isView && ArrayBuffer.isView(buf) ? buf : new Uint8Array(buf || 0); - this.pos = 0; - this.type = 0; - this.length = this.buf.length; -} - -Pbf.Varint = 0; // varint: int32, int64, uint32, uint64, sint32, sint64, bool, enum -Pbf.Fixed64 = 1; // 64-bit: double, fixed64, sfixed64 -Pbf.Bytes = 2; // length-delimited: string, bytes, embedded messages, packed repeated fields -Pbf.Fixed32 = 5; // 32-bit: float, fixed32, sfixed32 - -var SHIFT_LEFT_32 = (1 << 16) * (1 << 16), - SHIFT_RIGHT_32 = 1 / SHIFT_LEFT_32; - -Pbf.prototype = { - - destroy: function() { - this.buf = null; - }, - - // === READING ================================================================= - - readFields: function(readField, result, end) { - end = end || this.length; - - while (this.pos < end) { - var val = this.readVarint(), - tag = val >> 3, - startPos = this.pos; - - this.type = val & 0x7; - readField(tag, result, this); - - if (this.pos === startPos) this.skip(val); - } - return result; - }, - - readMessage: function(readField, result) { - return this.readFields(readField, result, this.readVarint() + this.pos); - }, - - readFixed32: function() { - var val = readUInt32(this.buf, this.pos); - this.pos += 4; - return val; - }, - - readSFixed32: function() { - var val = readInt32(this.buf, this.pos); - this.pos += 4; - return val; - }, - - // 64-bit int handling is based on github.com/dpw/node-buffer-more-ints (MIT-licensed) - - readFixed64: function() { - var val = readUInt32(this.buf, this.pos) + readUInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32; - this.pos += 8; - return val; - }, - - readSFixed64: function() { - var val = readUInt32(this.buf, this.pos) + readInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32; - this.pos += 8; - return val; - }, - - readFloat: function() { - var val = ieee754.read(this.buf, this.pos, true, 23, 4); - this.pos += 4; - return val; - }, - - readDouble: function() { - var val = ieee754.read(this.buf, this.pos, true, 52, 8); - this.pos += 8; - return val; - }, - - readVarint: function(isSigned) { - var buf = this.buf, - val, b; - - b = buf[this.pos++]; val = b & 0x7f; if (b < 0x80) return val; - b = buf[this.pos++]; val |= (b & 0x7f) << 7; if (b < 0x80) return val; - b = buf[this.pos++]; val |= (b & 0x7f) << 14; if (b < 0x80) return val; - b = buf[this.pos++]; val |= (b & 0x7f) << 21; if (b < 0x80) return val; - b = buf[this.pos]; val |= (b & 0x0f) << 28; - - return readVarintRemainder(val, isSigned, this); - }, - - readVarint64: function() { // for compatibility with v2.0.1 - return this.readVarint(true); - }, - - readSVarint: function() { - var num = this.readVarint(); - return num % 2 === 1 ? (num + 1) / -2 : num / 2; // zigzag encoding - }, - - readBoolean: function() { - return Boolean(this.readVarint()); - }, - - readString: function() { - var end = this.readVarint() + this.pos, - str = readUtf8(this.buf, this.pos, end); - this.pos = end; - return str; - }, - - readBytes: function() { - var end = this.readVarint() + this.pos, - buffer = this.buf.subarray(this.pos, end); - this.pos = end; - return buffer; - }, - - // verbose for performance reasons; doesn't affect gzipped size - - readPackedVarint: function(arr, isSigned) { - var end = readPackedEnd(this); - arr = arr || []; - while (this.pos < end) arr.push(this.readVarint(isSigned)); - return arr; - }, - readPackedSVarint: function(arr) { - var end = readPackedEnd(this); - arr = arr || []; - while (this.pos < end) arr.push(this.readSVarint()); - return arr; - }, - readPackedBoolean: function(arr) { - var end = readPackedEnd(this); - arr = arr || []; - while (this.pos < end) arr.push(this.readBoolean()); - return arr; - }, - readPackedFloat: function(arr) { - var end = readPackedEnd(this); - arr = arr || []; - while (this.pos < end) arr.push(this.readFloat()); - return arr; - }, - readPackedDouble: function(arr) { - var end = readPackedEnd(this); - arr = arr || []; - while (this.pos < end) arr.push(this.readDouble()); - return arr; - }, - readPackedFixed32: function(arr) { - var end = readPackedEnd(this); - arr = arr || []; - while (this.pos < end) arr.push(this.readFixed32()); - return arr; - }, - readPackedSFixed32: function(arr) { - var end = readPackedEnd(this); - arr = arr || []; - while (this.pos < end) arr.push(this.readSFixed32()); - return arr; - }, - readPackedFixed64: function(arr) { - var end = readPackedEnd(this); - arr = arr || []; - while (this.pos < end) arr.push(this.readFixed64()); - return arr; - }, - readPackedSFixed64: function(arr) { - var end = readPackedEnd(this); - arr = arr || []; - while (this.pos < end) arr.push(this.readSFixed64()); - return arr; - }, - - skip: function(val) { - var type = val & 0x7; - if (type === Pbf.Varint) while (this.buf[this.pos++] > 0x7f) {} - else if (type === Pbf.Bytes) this.pos = this.readVarint() + this.pos; - else if (type === Pbf.Fixed32) this.pos += 4; - else if (type === Pbf.Fixed64) this.pos += 8; - else throw new Error('Unimplemented type: ' + type); - }, - - // === WRITING ================================================================= - - writeTag: function(tag, type) { - this.writeVarint((tag << 3) | type); - }, - - realloc: function(min) { - var length = this.length || 16; - - while (length < this.pos + min) length *= 2; - - if (length !== this.length) { - var buf = new Uint8Array(length); - buf.set(this.buf); - this.buf = buf; - this.length = length; - } - }, - - finish: function() { - this.length = this.pos; - this.pos = 0; - return this.buf.subarray(0, this.length); - }, - - writeFixed32: function(val) { - this.realloc(4); - writeInt32(this.buf, val, this.pos); - this.pos += 4; - }, - - writeSFixed32: function(val) { - this.realloc(4); - writeInt32(this.buf, val, this.pos); - this.pos += 4; - }, - - writeFixed64: function(val) { - this.realloc(8); - writeInt32(this.buf, val & -1, this.pos); - writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4); - this.pos += 8; - }, - - writeSFixed64: function(val) { - this.realloc(8); - writeInt32(this.buf, val & -1, this.pos); - writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4); - this.pos += 8; - }, - - writeVarint: function(val) { - val = +val || 0; - - if (val > 0xfffffff || val < 0) { - writeBigVarint(val, this); - return; - } - - this.realloc(4); - - this.buf[this.pos++] = val & 0x7f | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return; - this.buf[this.pos++] = ((val >>>= 7) & 0x7f) | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return; - this.buf[this.pos++] = ((val >>>= 7) & 0x7f) | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return; - this.buf[this.pos++] = (val >>> 7) & 0x7f; - }, - - writeSVarint: function(val) { - this.writeVarint(val < 0 ? -val * 2 - 1 : val * 2); - }, - - writeBoolean: function(val) { - this.writeVarint(Boolean(val)); - }, - - writeString: function(str) { - str = String(str); - this.realloc(str.length * 4); - - this.pos++; // reserve 1 byte for short string length - - var startPos = this.pos; - // write the string directly to the buffer and see how much was written - this.pos = writeUtf8(this.buf, str, this.pos); - var len = this.pos - startPos; - - if (len >= 0x80) makeRoomForExtraLength(startPos, len, this); - - // finally, write the message length in the reserved place and restore the position - this.pos = startPos - 1; - this.writeVarint(len); - this.pos += len; - }, - - writeFloat: function(val) { - this.realloc(4); - ieee754.write(this.buf, val, this.pos, true, 23, 4); - this.pos += 4; - }, - - writeDouble: function(val) { - this.realloc(8); - ieee754.write(this.buf, val, this.pos, true, 52, 8); - this.pos += 8; - }, - - writeBytes: function(buffer) { - var len = buffer.length; - this.writeVarint(len); - this.realloc(len); - for (var i = 0; i < len; i++) this.buf[this.pos++] = buffer[i]; - }, - - writeRawMessage: function(fn, obj) { - this.pos++; // reserve 1 byte for short message length - - // write the message directly to the buffer and see how much was written - var startPos = this.pos; - fn(obj, this); - var len = this.pos - startPos; - - if (len >= 0x80) makeRoomForExtraLength(startPos, len, this); - - // finally, write the message length in the reserved place and restore the position - this.pos = startPos - 1; - this.writeVarint(len); - this.pos += len; - }, - - writeMessage: function(tag, fn, obj) { - this.writeTag(tag, Pbf.Bytes); - this.writeRawMessage(fn, obj); - }, - - writePackedVarint: function(tag, arr) { this.writeMessage(tag, writePackedVarint, arr); }, - writePackedSVarint: function(tag, arr) { this.writeMessage(tag, writePackedSVarint, arr); }, - writePackedBoolean: function(tag, arr) { this.writeMessage(tag, writePackedBoolean, arr); }, - writePackedFloat: function(tag, arr) { this.writeMessage(tag, writePackedFloat, arr); }, - writePackedDouble: function(tag, arr) { this.writeMessage(tag, writePackedDouble, arr); }, - writePackedFixed32: function(tag, arr) { this.writeMessage(tag, writePackedFixed32, arr); }, - writePackedSFixed32: function(tag, arr) { this.writeMessage(tag, writePackedSFixed32, arr); }, - writePackedFixed64: function(tag, arr) { this.writeMessage(tag, writePackedFixed64, arr); }, - writePackedSFixed64: function(tag, arr) { this.writeMessage(tag, writePackedSFixed64, arr); }, - - writeBytesField: function(tag, buffer) { - this.writeTag(tag, Pbf.Bytes); - this.writeBytes(buffer); - }, - writeFixed32Field: function(tag, val) { - this.writeTag(tag, Pbf.Fixed32); - this.writeFixed32(val); - }, - writeSFixed32Field: function(tag, val) { - this.writeTag(tag, Pbf.Fixed32); - this.writeSFixed32(val); - }, - writeFixed64Field: function(tag, val) { - this.writeTag(tag, Pbf.Fixed64); - this.writeFixed64(val); - }, - writeSFixed64Field: function(tag, val) { - this.writeTag(tag, Pbf.Fixed64); - this.writeSFixed64(val); - }, - writeVarintField: function(tag, val) { - this.writeTag(tag, Pbf.Varint); - this.writeVarint(val); - }, - writeSVarintField: function(tag, val) { - this.writeTag(tag, Pbf.Varint); - this.writeSVarint(val); - }, - writeStringField: function(tag, str) { - this.writeTag(tag, Pbf.Bytes); - this.writeString(str); - }, - writeFloatField: function(tag, val) { - this.writeTag(tag, Pbf.Fixed32); - this.writeFloat(val); - }, - writeDoubleField: function(tag, val) { - this.writeTag(tag, Pbf.Fixed64); - this.writeDouble(val); - }, - writeBooleanField: function(tag, val) { - this.writeVarintField(tag, Boolean(val)); - } -}; - -function readVarintRemainder(l, s, p) { - var buf = p.buf, - h, b; - - b = buf[p.pos++]; h = (b & 0x70) >> 4; if (b < 0x80) return toNum(l, h, s); - b = buf[p.pos++]; h |= (b & 0x7f) << 3; if (b < 0x80) return toNum(l, h, s); - b = buf[p.pos++]; h |= (b & 0x7f) << 10; if (b < 0x80) return toNum(l, h, s); - b = buf[p.pos++]; h |= (b & 0x7f) << 17; if (b < 0x80) return toNum(l, h, s); - b = buf[p.pos++]; h |= (b & 0x7f) << 24; if (b < 0x80) return toNum(l, h, s); - b = buf[p.pos++]; h |= (b & 0x01) << 31; if (b < 0x80) return toNum(l, h, s); - - throw new Error('Expected varint not more than 10 bytes'); -} - -function readPackedEnd(pbf) { - return pbf.type === Pbf.Bytes ? - pbf.readVarint() + pbf.pos : pbf.pos + 1; -} - -function toNum(low, high, isSigned) { - if (isSigned) { - return high * 0x100000000 + (low >>> 0); - } - - return ((high >>> 0) * 0x100000000) + (low >>> 0); -} - -function writeBigVarint(val, pbf) { - var low, high; - - if (val >= 0) { - low = (val % 0x100000000) | 0; - high = (val / 0x100000000) | 0; - } else { - low = ~(-val % 0x100000000); - high = ~(-val / 0x100000000); - - if (low ^ 0xffffffff) { - low = (low + 1) | 0; - } else { - low = 0; - high = (high + 1) | 0; - } - } - - if (val >= 0x10000000000000000 || val < -0x10000000000000000) { - throw new Error('Given varint doesn\'t fit into 10 bytes'); - } - - pbf.realloc(10); - - writeBigVarintLow(low, high, pbf); - writeBigVarintHigh(high, pbf); -} - -function writeBigVarintLow(low, high, pbf) { - pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7; - pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7; - pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7; - pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7; - pbf.buf[pbf.pos] = low & 0x7f; -} - -function writeBigVarintHigh(high, pbf) { - var lsb = (high & 0x07) << 4; - - pbf.buf[pbf.pos++] |= lsb | ((high >>>= 3) ? 0x80 : 0); if (!high) return; - pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return; - pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return; - pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return; - pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return; - pbf.buf[pbf.pos++] = high & 0x7f; -} - -function makeRoomForExtraLength(startPos, len, pbf) { - var extraLen = - len <= 0x3fff ? 1 : - len <= 0x1fffff ? 2 : - len <= 0xfffffff ? 3 : Math.ceil(Math.log(len) / (Math.LN2 * 7)); - - // if 1 byte isn't enough for encoding message length, shift the data to the right - pbf.realloc(extraLen); - for (var i = pbf.pos - 1; i >= startPos; i--) pbf.buf[i + extraLen] = pbf.buf[i]; -} - -function writePackedVarint(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeVarint(arr[i]); } -function writePackedSVarint(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSVarint(arr[i]); } -function writePackedFloat(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFloat(arr[i]); } -function writePackedDouble(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeDouble(arr[i]); } -function writePackedBoolean(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeBoolean(arr[i]); } -function writePackedFixed32(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFixed32(arr[i]); } -function writePackedSFixed32(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSFixed32(arr[i]); } -function writePackedFixed64(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFixed64(arr[i]); } -function writePackedSFixed64(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSFixed64(arr[i]); } - -// Buffer code below from https://github.com/feross/buffer, MIT-licensed - -function readUInt32(buf, pos) { - return ((buf[pos]) | - (buf[pos + 1] << 8) | - (buf[pos + 2] << 16)) + - (buf[pos + 3] * 0x1000000); -} - -function writeInt32(buf, val, pos) { - buf[pos] = val; - buf[pos + 1] = (val >>> 8); - buf[pos + 2] = (val >>> 16); - buf[pos + 3] = (val >>> 24); -} - -function readInt32(buf, pos) { - return ((buf[pos]) | - (buf[pos + 1] << 8) | - (buf[pos + 2] << 16)) + - (buf[pos + 3] << 24); -} - -function readUtf8(buf, pos, end) { - var str = ''; - var i = pos; - - while (i < end) { - var b0 = buf[i]; - var c = null; // codepoint - var bytesPerSequence = - b0 > 0xEF ? 4 : - b0 > 0xDF ? 3 : - b0 > 0xBF ? 2 : 1; - - if (i + bytesPerSequence > end) break; - - var b1, b2, b3; - - if (bytesPerSequence === 1) { - if (b0 < 0x80) { - c = b0; - } - } else if (bytesPerSequence === 2) { - b1 = buf[i + 1]; - if ((b1 & 0xC0) === 0x80) { - c = (b0 & 0x1F) << 0x6 | (b1 & 0x3F); - if (c <= 0x7F) { - c = null; - } - } - } else if (bytesPerSequence === 3) { - b1 = buf[i + 1]; - b2 = buf[i + 2]; - if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80) { - c = (b0 & 0xF) << 0xC | (b1 & 0x3F) << 0x6 | (b2 & 0x3F); - if (c <= 0x7FF || (c >= 0xD800 && c <= 0xDFFF)) { - c = null; - } - } - } else if (bytesPerSequence === 4) { - b1 = buf[i + 1]; - b2 = buf[i + 2]; - b3 = buf[i + 3]; - if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80 && (b3 & 0xC0) === 0x80) { - c = (b0 & 0xF) << 0x12 | (b1 & 0x3F) << 0xC | (b2 & 0x3F) << 0x6 | (b3 & 0x3F); - if (c <= 0xFFFF || c >= 0x110000) { - c = null; - } - } - } - - if (c === null) { - c = 0xFFFD; - bytesPerSequence = 1; - - } else if (c > 0xFFFF) { - c -= 0x10000; - str += String.fromCharCode(c >>> 10 & 0x3FF | 0xD800); - c = 0xDC00 | c & 0x3FF; - } - - str += String.fromCharCode(c); - i += bytesPerSequence; - } - - return str; -} - -function writeUtf8(buf, str, pos) { - for (var i = 0, c, lead; i < str.length; i++) { - c = str.charCodeAt(i); // code point - - if (c > 0xD7FF && c < 0xE000) { - if (lead) { - if (c < 0xDC00) { - buf[pos++] = 0xEF; - buf[pos++] = 0xBF; - buf[pos++] = 0xBD; - lead = c; - continue; - } else { - c = lead - 0xD800 << 10 | c - 0xDC00 | 0x10000; - lead = null; - } - } else { - if (c > 0xDBFF || (i + 1 === str.length)) { - buf[pos++] = 0xEF; - buf[pos++] = 0xBF; - buf[pos++] = 0xBD; - } else { - lead = c; - } - continue; - } - } else if (lead) { - buf[pos++] = 0xEF; - buf[pos++] = 0xBF; - buf[pos++] = 0xBD; - lead = null; - } - - if (c < 0x80) { - buf[pos++] = c; - } else { - if (c < 0x800) { - buf[pos++] = c >> 0x6 | 0xC0; - } else { - if (c < 0x10000) { - buf[pos++] = c >> 0xC | 0xE0; - } else { - buf[pos++] = c >> 0x12 | 0xF0; - buf[pos++] = c >> 0xC & 0x3F | 0x80; - } - buf[pos++] = c >> 0x6 & 0x3F | 0x80; - } - buf[pos++] = c & 0x3F | 0x80; - } - } - return pos; -} - - -/***/ }), -/* 7 */ -/***/ (function(module, exports) { - -exports.read = function (buffer, offset, isLE, mLen, nBytes) { - var e, m - var eLen = nBytes * 8 - mLen - 1 - var eMax = (1 << eLen) - 1 - var eBias = eMax >> 1 - var nBits = -7 - var i = isLE ? (nBytes - 1) : 0 - var d = isLE ? -1 : 1 - var s = buffer[offset + i] - - i += d - - e = s & ((1 << (-nBits)) - 1) - s >>= (-nBits) - nBits += eLen - for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {} - - m = e & ((1 << (-nBits)) - 1) - e >>= (-nBits) - nBits += mLen - for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {} - - if (e === 0) { - e = 1 - eBias - } else if (e === eMax) { - return m ? NaN : ((s ? -1 : 1) * Infinity) - } else { - m = m + Math.pow(2, mLen) - e = e - eBias - } - return (s ? -1 : 1) * m * Math.pow(2, e - mLen) -} - -exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { - var e, m, c - var eLen = nBytes * 8 - mLen - 1 - var eMax = (1 << eLen) - 1 - var eBias = eMax >> 1 - var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0) - var i = isLE ? 0 : (nBytes - 1) - var d = isLE ? 1 : -1 - var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0 - - value = Math.abs(value) - - if (isNaN(value) || value === Infinity) { - m = isNaN(value) ? 1 : 0 - e = eMax - } else { - e = Math.floor(Math.log(value) / Math.LN2) - if (value * (c = Math.pow(2, -e)) < 1) { - e-- - c *= 2 - } - if (e + eBias >= 1) { - value += rt / c - } else { - value += rt * Math.pow(2, 1 - eBias) - } - if (value * c >= 2) { - e++ - c /= 2 - } - - if (e + eBias >= eMax) { - m = 0 - e = eMax - } else if (e + eBias >= 1) { - m = (value * c - 1) * Math.pow(2, mLen) - e = e + eBias - } else { - m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen) - e = 0 - } - } - - for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} - - e = (e << mLen) | m - eLen += mLen - for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} - - buffer[offset + i - d] |= s * 128 -} - - -/***/ }), -/* 8 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__src_index__ = __webpack_require__(2); - - - -var VectorTile = __webpack_require__(3).VectorTile; -var Protobuf = __webpack_require__(6); - -var renderer; -var layer; -var oldtile; -var ajax; - -function styleWidth(e) { - const v = document.getElementById("widthStyleEntry").value; - const Near = __WEBPACK_IMPORTED_MODULE_0__src_index__["c" /* Style */].Near; - const Float = __WEBPACK_IMPORTED_MODULE_0__src_index__["c" /* Style */].Float; - const Color = __WEBPACK_IMPORTED_MODULE_0__src_index__["c" /* Style */].Color; - const RampColor = __WEBPACK_IMPORTED_MODULE_0__src_index__["c" /* Style */].RampColor; - const width = eval(v); - if (width) { - layer.style.getWidth().blendTo(width, 1000); - } -} -function styleColor(e) { - const v = document.getElementById("colorStyleEntry").value; - const Near = __WEBPACK_IMPORTED_MODULE_0__src_index__["c" /* Style */].Near; - const Float = __WEBPACK_IMPORTED_MODULE_0__src_index__["c" /* Style */].Float; - const Color = __WEBPACK_IMPORTED_MODULE_0__src_index__["c" /* Style */].Color; - const RampColor = __WEBPACK_IMPORTED_MODULE_0__src_index__["c" /* Style */].RampColor; - const color = eval(v); - if (color) { - layer.style.getColor().blendTo(color, 1000); - } -} - -function getData() { - if (ajax) { - ajax.abort(); - } - - var oReq = new XMLHttpRequest(); - oReq.open("GET", "https://dmanzanares.carto.com/api/v1/map/dmanzanares@789cad67@92456f0655aac0322b2572f4e05088e7:1509358508954/mapnik/0/0/0.mvt", true); - oReq.responseType = "arraybuffer"; - oReq.onload = function (oEvent) { - var arrayBuffer = oReq.response; - console.log("MVT1", arrayBuffer, oEvent, oReq); - if (arrayBuffer) { - var tile = new VectorTile(new Protobuf(arrayBuffer)); - console.log("MVT", tile); - const mvtLayer = tile.layers[Object.keys(tile.layers)[0]]; - - var fieldMap = { - temp: 0, - daten: 1 - }; - var properties = [[new Float32Array(mvtLayer.length)], [new Float32Array(mvtLayer.length)]]; - var points = new Float32Array(mvtLayer.length * 2); - for (var i = 0; i < mvtLayer.length; i++) { - const f = mvtLayer.feature(i); - const geom = f.loadGeometry(); - //console.log(mvtLayer.feature(i).toGeoJSON(0,0,0)) - points[2 * i + 0] = (geom[0][0].x) / 4096.0; - points[2 * i + 1] = 1. - (geom[0][0].y) / 4096.0; - - properties[0][i] = Number(f.properties.temp); - properties[1][i] = Number(f.properties.daten); - - /*Object.keys(f.properties).map(name => { - if (fieldMap[name] === undefined) { - fieldMap[name] = Object.keys(fieldMap).length; - } - var pid = fieldMap[name]; - if (properties[pid] === undefined) { - properties[pid] = new Float32Array(mvtLayer.length); - } - properties[pid][i] = Number(f.properties[name]); - });*/ - } - var tile = { - center: { x: 0, y: 0 }, - scale: 1 / 1., - count: mvtLayer.length, - geom: points, - properties: {} - }; - Object.keys(fieldMap).map((name, pid) => { - tile.properties[name] = properties[pid]; - }) - console.log("Tile", tile); - oldtile = layer.addTile(tile); - styleWidth(); - styleColor(); - } - }; - - oReq.send(null); - /* - ajax = $.getJSON("https://dmanzanares.carto.com/api/v2/sql?q=" + encodeURIComponent(document.getElementById("sqlEntry").value) + "&api_key=d9d686df65842a8fddbd186711255ce5d19aa9b8", function (data) { - if (oldtile) { - layer.removeTile(oldtile); - } - console.log("Downloaded", data); - const fields = Object.keys(data.fields).filter(name => name != 'st_asgeojson'); - var properties = fields.map(_ => new Float32Array(data.rows.length)); - var points = new Float32Array(data.rows.length * 2); - data.rows.forEach((e, index) => { - var point = $.parseJSON(e.st_asgeojson).coordinates; - points[2 * index + 0] = (point[0]) + Math.random() * 1000; - points[2 * index + 1] = (point[1]) + Math.random() * 1000; - fields.map((name, pid) => { - properties[pid][index] = Number(e[name]); - }); - }); - var tile = { - center: { x: 0, y: 0 }, - scale: 1 / 10000000., - count: data.rows.length, - geom: points, - properties: {} - }; - fields.map((name, pid) => { - tile.properties[name] = properties[pid]; - }) - console.log("Tile", tile); - oldtile = layer.addTile(tile); - styleWidth(); - styleColor(); - });*/ -} -function start() { - renderer = new __WEBPACK_IMPORTED_MODULE_0__src_index__["a" /* Renderer */](document.getElementById('glCanvas')); - layer = renderer.addLayer(); - - getData(); - $('#widthStyleEntry').on('input', styleWidth); - $('#colorStyleEntry').on('input', styleColor); - $('#sqlEntry').on('input', getData); - - // Pan and zoom - window.onresize = function () { renderer.refresh(); }; - $(window).bind('mousewheel DOMMouseScroll', function (event) { - if (event.originalEvent.wheelDelta > 0 || event.originalEvent.detail < 0) { - renderer.setZoom(renderer.getZoom() * 0.8); - } else { - renderer.setZoom(renderer.getZoom() / 0.8); - } - }); - var isDragging = false; - var draggOffset = { - x: 0., - y: 0. - }; - document.onmousedown = function (event) { - isDragging = true; - draggOffset = { - x: event.clientX, - y: event.clientY - }; - }; - document.onmousemove = function (event) { - if (isDragging) { - var c = renderer.getCenter(); - var k = renderer.getZoom() / document.body.clientHeight * 2.; - c.x += (draggOffset.x - event.clientX) * k; - c.y += -(draggOffset.y - event.clientY) * k; - renderer.setCenter(c.x, c.y); - draggOffset = { - x: event.clientX, - y: event.clientY - }; - } - }; - document.onmouseup = function () { - isDragging = false; - }; -} - -start(); - -/***/ }), -/* 9 */, -/* 10 */, -/* 11 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Property", function() { return Property; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Blend", function() { return Blend; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Now", function() { return Now; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Near", function() { return Near; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Color", function() { return Color; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Float", function() { return Float; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RampColor", function() { return RampColor; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FloatMul", function() { return FloatMul; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FloatDiv", function() { return FloatDiv; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FloatAdd", function() { return FloatAdd; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FloatSub", function() { return FloatSub; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FloatPow", function() { return FloatPow; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "setGL", function() { return setGL; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "schemes", function() { return schemes; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_cartocolor__ = __webpack_require__(21); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_cartocolor___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_cartocolor__); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__scheme__ = __webpack_require__(25); - - - -function implicitCast(value) { - if (Number.isFinite(value)) { - return Float(value); - } - return value; -} -var gl = null; -function setGL(_gl) { - gl = _gl; -} - - -const schemes = {}; -Object.keys(__WEBPACK_IMPORTED_MODULE_0_cartocolor__).map(name => { - const s = __WEBPACK_IMPORTED_MODULE_0_cartocolor__[name]; - var defaultFound = false; - for (let i = 20; i >= 0; i--) { - if (s[i]) { - if (!defaultFound) { - schemes[name.toLowerCase()] = () => s[i]; - defaultFound = true; - } - schemes[`${name.toLowerCase()}_${i}`] = () => s[i]; - } - } -}); - - -/* - Each styling function should: - - Create their own objects, i.e.: be used without "new" - - Check input validity on user input (constructor and exposed functions). - - Have certain functions that never fail: - - _applyToShaderSource should use uniformIDMaker and propertyTIDMaker to get unique uniform IDs and property IDs as needed - - _postShaderCompile should get uniform location after program compilation as needed - - _preDraw should set any program's uniforms as needed - - isAnimated should return true if the function output could change depending on the timestamp - - Have a type property declaring the GLSL output type: 'float', 'color' -*/ - -/* - TODO - - Integrated color palettes - - Type checking for color palettes - - Allow multiplication, division and pow() to color expressions and color literals - - Add SetOpacity(colorExpr, opacityFloatOverride) - - HSV - - Think about uniform-only types / parameters - - Think about "Date" and "string" types. - - Heatmaps (renderer should be improved too to accommodate this) -*/ - -function Property(name, scheme) { - return new _Property(name, scheme); -} -function _Property(name, scheme) { - if (typeof name !== 'string' || name == '') { - throw new Error(`Invalid property name '${name}'`); - } - if (!scheme[name]) { - throw new Error(`Property name not found`); - } - this.name = name; - this.type = 'float'; - this.scheme = scheme; -} -_Property.prototype._applyToShaderSource = function (uniformIDMaker, propertyTIDMaker) { - return { - preface: '', - inline: `p${propertyTIDMaker(this.name)}` - }; -} -_Property.prototype._postShaderCompile = function (program) { -} -_Property.prototype._preDraw = function () { -} -_Property.prototype.isAnimated = function () { - return false; -} - -function Now(speed) { - return new _Now(speed); -} -function _Now(speed) { - if (speed == undefined) { - speed = 1; - } - if (!Number.isFinite(Number(speed))) { - throw new Error('Now() only accepts number literals'); - } - this.speed = Number(speed); - this.type = 'float'; - this.float = Float(0); -} -_Now.prototype._applyToShaderSource = function (uniformIDMaker) { - return this.float._applyToShaderSource(uniformIDMaker); -} -_Now.prototype._postShaderCompile = function (program) { - return this.float._postShaderCompile(program); -} -_Now.prototype._preDraw = function () { - this.float.expr = (Date.now() * this.speed / 1000.) % 1; - this.float._preDraw(); -} -_Now.prototype.isAnimated = function () { - return true; -} - -const FloatMul = genFloatBinaryOperation((x, y) => x * y, (x, y) => `(${x} * ${y})`); -const FloatDiv = genFloatBinaryOperation((x, y) => x / y, (x, y) => `(${x} / ${y})`); -const FloatAdd = genFloatBinaryOperation((x, y) => x + y, (x, y) => `(${x} + ${y})`); -const FloatSub = genFloatBinaryOperation((x, y) => x - y, (x, y) => `(${x} - ${y})`); -const FloatPow = genFloatBinaryOperation((x, y) => Math.pow(x, y), (x, y) => `pow(${x}, ${y})`); - -function genFloatBinaryOperation(jsFn, glsl) { - function BinaryOp(a, b) { - if (Number.isFinite(a) && Number.isFinite(b)) { - return Float(jsFn(a, b)); - } - if (Number.isFinite(a)) { - a = Float(a); - } - if (Number.isFinite(b)) { - b = Float(b); - } - if (a.type == 'float' && b.type == 'float') { - this.type = 'float'; - } else { - console.warn(a, b); - throw new Error(`Binary operation cannot be performed between '${a}' and '${b}'`); - } - return new _BinaryOp(a, b); - } - function _BinaryOp(a, b) { - this.type = 'float'; - this.a = a; - this.b = b; - a.parent = this; - b.parent = this; - } - _BinaryOp.prototype._applyToShaderSource = function (uniformIDMaker, propertyTIDMaker) { - const a = this.a._applyToShaderSource(uniformIDMaker, propertyTIDMaker); - const b = this.b._applyToShaderSource(uniformIDMaker, propertyTIDMaker); - return { - preface: a.preface + b.preface, - inline: glsl(a.inline, b.inline) - }; - } - _BinaryOp.prototype._postShaderCompile = function (program) { - this.a._postShaderCompile(program); - this.b._postShaderCompile(program); - } - _BinaryOp.prototype._preDraw = function (l) { - this.a._preDraw(l); - this.b._preDraw(l); - } - _BinaryOp.prototype.isAnimated = function () { - return this.a.isAnimated() || this.b.isAnimated(); - } - _BinaryOp.prototype.replaceChild = function (toReplace, replacer) { - if (this.a = toReplace) { - this.a = replacer; - } else { - this.b = replacer; - } - replacer.parent = this; - replacer.notify = toReplace.notify; - } - _BinaryOp.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { - genericBlend(this, finalValue, duration, blendFunc); - } - return BinaryOp; -} - -function Animation(duration) { - return new _Animation(duration); -} -function _Animation(duration) { - if (!Number.isFinite(duration)) { - throw new Error("Animation only supports number literals"); - } - this.type = 'float'; - this.aTime = Date.now(); - this.bTime = this.aTime + Number(duration); -} -_Animation.prototype._applyToShaderSource = function (uniformIDMaker, propertyTIDMaker) { - this._uniformID = uniformIDMaker(); - return { - preface: `uniform float anim${this._uniformID};\n`, - inline: `anim${this._uniformID}` - }; -} -_Animation.prototype._postShaderCompile = function (program) { - this._uniformLocation = gl.getUniformLocation(program, `anim${this._uniformID}`); -} -_Animation.prototype._preDraw = function (l) { - const time = Date.now(); - this.mix = (time - this.aTime) / (this.bTime - this.aTime); - if (this.mix > 1.) { - gl.uniform1f(this._uniformLocation, 1); - } else { - gl.uniform1f(this._uniformLocation, this.mix); - } -} -_Animation.prototype.isAnimated = function () { - return !this.mix || this.mix <= 1.; -} - -function Near(property, center, threshold, falloff) { - const args = [property, center, threshold, falloff].map(implicitCast); - if (args.some(x => x === undefined || x === null)) { - throw new Error(`Invalid arguments to Near(): ${args}`); - } - return new _Near(...args); -} - -function _Near(input, center, threshold, falloff) { - if (input.type != 'float' || center.type != 'float' || threshold.type != 'float' || falloff.type != 'float') { - throw new Error('Near(): invalid parameter type'); - } - this.type = 'float'; - this.input = input; - this.center = center; - this.threshold = threshold; - this.falloff = falloff; -} -_Near.prototype._applyToShaderSource = function (uniformIDMaker, propertyTIDMaker) { - this._UID = uniformIDMaker(); - const tid = propertyTIDMaker(this.property); - const input = this.input._applyToShaderSource(uniformIDMaker, propertyTIDMaker); - const center = this.center._applyToShaderSource(uniformIDMaker, propertyTIDMaker); - const threshold = this.threshold._applyToShaderSource(uniformIDMaker, propertyTIDMaker); - const falloff = this.falloff._applyToShaderSource(uniformIDMaker, propertyTIDMaker); - return { - preface: - input.preface + center.preface + threshold.preface + falloff.preface, - inline: `1.-clamp((abs(${input.inline}-${center.inline})-${threshold.inline})/${falloff.inline}, - 0., 1.)` - }; -} -_Near.prototype._postShaderCompile = function (program) { - this.center._postShaderCompile(program); - this.threshold._postShaderCompile(program); - this.falloff._postShaderCompile(program); - this.input._postShaderCompile(program); -} -_Near.prototype._preDraw = function () { - this.center._preDraw(); - this.threshold._preDraw(); - this.falloff._preDraw(); - this.input._preDraw(); -} -_Near.prototype.isAnimated = function () { - return this.center.isAnimated(); -} - - - -function Blend(a, b, mix) { - const args = [a, b, mix].map(implicitCast); - if (args.some(x => x === undefined || x === null)) { - throw new Error(`Invalid arguments to Blend(): ${args}`); - } - return new _Blend(...args); -} -function _Blend(a, b, mix) { - if (a.type == 'float' && b.type == 'float') { - this.type = 'float'; - } else if (a.type == 'color' && b.type == 'color') { - this.type = 'color'; - } else { - console.warn(a, b); - throw new Error(`Blending cannot be performed between types '${a.type}' and '${b.type}'`); - } - if (__WEBPACK_IMPORTED_MODULE_1__scheme__["b" /* checkSchemeMatch */](a.scheme, b.scheme)) { - throw new Error('Blend parameters schemes mismatch'); - } - this.scheme = a.scheme; - this.a = a; - this.b = b; - this.mix = mix; - a.parent = this; - b.parent = this; - mix.parent = this; -} -_Blend.prototype._applyToShaderSource = function (uniformIDMaker, propertyTIDMaker) { - const a = this.a._applyToShaderSource(uniformIDMaker, propertyTIDMaker); - const b = this.b._applyToShaderSource(uniformIDMaker, propertyTIDMaker); - const mix = this.mix._applyToShaderSource(uniformIDMaker, propertyTIDMaker); - return { - preface: `${a.preface}${b.preface}${mix.preface}`, - inline: `mix(${a.inline}, ${b.inline}, ${mix.inline})` - }; -} -_Blend.prototype._postShaderCompile = function (program) { - this.a._postShaderCompile(program); - this.b._postShaderCompile(program); - this.mix._postShaderCompile(program); -} -_Blend.prototype._preDraw = function (l) { - this.a._preDraw(l); - this.b._preDraw(l); - this.mix._preDraw(l); - if (this.mix instanceof _Animation && !this.mix.isAnimated()) { - this.parent.replaceChild(this, this.b); - } -} -_Blend.prototype.isAnimated = function () { - return this.a.isAnimated() || this.b.isAnimated() || this.mix.isAnimated(); -} -_Blend.prototype.replaceChild = function (toReplace, replacer) { - if (this.a = toReplace) { - this.a = replacer; - } else { - this.b = replacer; - } - replacer.parent = this; - replacer.notify = toReplace.notify; -} - -function genericBlend(initial, final, duration, blendFunc) { - const parent = initial.parent; - const blend = Blend(initial, final, Animation(duration)); - parent.replaceChild(initial, blend); - blend.notify(); -} -UniformColor.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { - genericBlend(this, finalValue, duration, blendFunc); -} -_RampColor.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { - genericBlend(this, finalValue, duration, blendFunc); -} - -_Near.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { - genericBlend(this, finalValue, duration, blendFunc); -} -UniformFloat.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { - genericBlend(this, finalValue, duration, blendFunc); -} -_Blend.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { - genericBlend(this, finalValue, duration, blendFunc); -} -_Property.prototype.blendTo = function (finalValue, duration = 500, blendFunc = 'linear') { - genericBlend(this, finalValue, duration, blendFunc); -} - - -function Color(color) { - if (Array.isArray(color)) { - color = color.filter(x => true); - if (color.length != 4 || !color.every(Number.isFinite)) { - throw new Error(`Invalid arguments to Color(): ${args}`); - } - return new UniformColor(color); - } - throw new Error(`Invalid arguments to Color(): ${args}`); -} -function UniformColor(color) { - this.type = 'color'; - this.color = color; -} -UniformColor.prototype._applyToShaderSource = function (uniformIDMaker) { - this._uniformID = uniformIDMaker(); - return { - preface: `uniform vec4 color${this._uniformID};\n`, - inline: `color${this._uniformID}` - }; -} -UniformColor.prototype._postShaderCompile = function (program) { - this._uniformLocation = gl.getUniformLocation(program, `color${this._uniformID}`); -} -function evalColor(color, time) { - if (Array.isArray(color)) { - return color; - } - var a = evalColor(color.a, time); - var b = evalColor(color.b, time); - var m = (time - color.aTime) / (color.bTime - color.aTime); - return a.map((va, index) => { - return (1 - m) * va + m * b[index];//TODO non linear functions - }); -} -function simplifyColorExpr(color, time) { - if (Array.isArray(color)) { - return color; - } - var m = (time - color.aTime) / (color.bTime - color.aTime); - if (m >= 1) { - return color.b; - } - return color; -} -UniformColor.prototype._preDraw = function () { - const t = Date.now(); - this.color = simplifyColorExpr(this.color, t); - const color = evalColor(this.color, t); - gl.uniform4f(this._uniformLocation, color[0], color[1], color[2], color[3]); -} -UniformColor.prototype.isAnimated = function () { - return false; -} - -function Float(x) { - if (!Number.isFinite(x)) { - throw new Error(`Invalid arguments to Float(): ${args}`); - } - return new UniformFloat(x); -} - -function UniformFloat(size) { - this.type = 'float'; - this.expr = size; -} -UniformFloat.prototype._applyToShaderSource = function (uniformIDMaker) { - this._uniformID = uniformIDMaker(); - return { - preface: `uniform float float${this._uniformID};\n`, - inline: `float${this._uniformID}` - }; -} -UniformFloat.prototype._postShaderCompile = function (program) { - this._uniformLocation = gl.getUniformLocation(program, `float${this._uniformID}`); -} -function evalFloatExpr(expr, time) { - if (Number.isFinite(expr)) { - return expr; - } - if (typeof expr === "function") { - return x(time); - } - return expr.eval(); -} -function simplifyFloatExpr(expr, time) { - if (Number.isFinite(expr)) { - return expr; - } - return expr.simplify(); -} -UniformFloat.prototype._preDraw = function (time) { - this.expr = simplifyFloatExpr(this.expr, time); - const v = evalFloatExpr(this.expr, time); - gl.uniform1f(this._uniformLocation, v); -} -UniformFloat.prototype.isAnimated = function () { - return !Number.isFinite(this.expr); -} - -function hexToRgb(hex) { - var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); - return result ? { - r: parseInt(result[1], 16), - g: parseInt(result[2], 16), - b: parseInt(result[3], 16) - } : null; -} - - -function RampColor(input, minKey, maxKey, values) { - //TODO contiunuos vs discrete should be decided based on input type => cartegory vs float - const args = [input, minKey, maxKey, values].map(implicitCast); - if (args.some(x => x === undefined || x === null)) { - throw new Error(`Invalid arguments to RampColor(): ${args}`); - } - return new _RampColor(...args); -} - -//Palette => used by Ramp, Ramp gets texture2D from palette by asking for number of buckets (0/interpolated palette, 2,3,4,5,6...) -function _RampColor(input, minKey, maxKey, values) { - this.type = 'color'; - this.input = input; - this.minKey = minKey.expr; - this.maxKey = maxKey.expr; - this.values = values; - - this.texture = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, this.texture); - const level = 0; - const internalFormat = gl.RGBA; - const width = 256; - const height = 1; - const border = 0; - const srcFormat = gl.RGBA; - const srcType = gl.UNSIGNED_BYTE; - const pixel = new Uint8Array(4 * width); - for (var i = 0; i < width; i++) { - const vlowRaw = values[Math.floor(i / width * (values.length - 1))]; - const vhighRaw = values[Math.ceil(i / width * (values.length - 1))]; - const vlow = [hexToRgb(vlowRaw).r, hexToRgb(vlowRaw).g, hexToRgb(vlowRaw).b, 255]; - const vhigh = [hexToRgb(vhighRaw).r, hexToRgb(vhighRaw).g, hexToRgb(vhighRaw).b, 255]; - const m = i / width * (values.length - 1) - Math.floor(i / width * (values.length - 1)); - const v = vlow.map((low, index) => low * (1. - m) + vhigh[index] * m); - pixel[4 * i + 0] = v[0]; - pixel[4 * i + 1] = v[1]; - pixel[4 * i + 2] = v[2]; - pixel[4 * i + 3] = v[3]; - } - - - gl.texImage2D(gl.TEXTURE_2D, level, internalFormat, - width, height, border, srcFormat, srcType, - pixel); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); -} - -_RampColor.prototype._free = function () { - gl.deleteTexture(this.texture); -} -_RampColor.prototype._applyToShaderSource = function (uniformIDMaker, propertyTIDMaker) { - this._UID = uniformIDMaker(); - const input = this.input._applyToShaderSource(uniformIDMaker, propertyTIDMaker); - return { - preface: input.preface + ` - uniform sampler2D texRamp${this._UID}; - uniform float keyMin${this._UID}; - uniform float keyWidth${this._UID}; - `, - inline: `texture2D(texRamp${this._UID}, vec2((${input.inline}-keyMin${this._UID})/keyWidth${this._UID}, 0.5)).rgba` - }; -} -_RampColor.prototype._postShaderCompile = function (program) { - this.input._postShaderCompile(program); - this._texLoc = gl.getUniformLocation(program, `texRamp${this._UID}`); - this._keyMinLoc = gl.getUniformLocation(program, `keyMin${this._UID}`); - this._keyWidthLoc = gl.getUniformLocation(program, `keyWidth${this._UID}`); -} -_RampColor.prototype._preDraw = function (l) { - this.input._preDraw(l); - gl.activeTexture(gl.TEXTURE0 + l.freeTexUnit);//TODO remove hardcode - gl.bindTexture(gl.TEXTURE_2D, this.texture); - gl.uniform1i(this._texLoc, l.freeTexUnit); - gl.uniform1f(this._keyMinLoc, evalFloatExpr(this.minKey)); - gl.uniform1f(this._keyWidthLoc, evalFloatExpr(this.maxKey) - evalFloatExpr(this.minKey)); - l.freeTexUnit++; -} -_RampColor.prototype.isAnimated = function () { - return false; -} - - -/***/ }), -/* 12 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return renderer; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return styler; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__renderer__ = __webpack_require__(15); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__styler__ = __webpack_require__(17); - - - -const NUM_TEXTURE_LOCATIONS = 4; - -function compileShader(gl, sourceCode, type) { - const shader = gl.createShader(type); - gl.shaderSource(shader, sourceCode); - gl.compileShader(shader); - if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { - const log = gl.getShaderInfoLog(shader); - gl.deleteShader(shader); - throw new Error('An error occurred compiling the shaders: ' + log + '\nSource:\n' + sourceCode); - } - return shader; -} - -function compileProgram(gl, glslVS, glslFS) { - const VS = compileShader(gl, glslVS, gl.VERTEX_SHADER); - const FS = compileShader(gl, glslFS, gl.FRAGMENT_SHADER); - this.program = gl.createProgram(); - gl.attachShader(this.program, VS); - gl.attachShader(this.program, FS); - gl.linkProgram(this.program); - gl.deleteShader(VS); - gl.deleteShader(FS); - if (!gl.getProgramParameter(this.program, gl.LINK_STATUS)) { - throw new Error('Unable to link the shader program: ' + gl.getProgramInfoLog(this.program)); - } -} - -function Point(gl) { - compileProgram.call(this, gl, __WEBPACK_IMPORTED_MODULE_0__renderer__["a" /* point */].VS, __WEBPACK_IMPORTED_MODULE_0__renderer__["a" /* point */].FS); - this.vertexPositionAttribute = gl.getAttribLocation(this.program, 'vertexPosition'); - this.featureIdAttr = gl.getAttribLocation(this.program, 'featureID'); - this.vertexScaleUniformLocation = gl.getUniformLocation(this.program, 'vertexScale'); - this.vertexOffsetUniformLocation = gl.getUniformLocation(this.program, 'vertexOffset'); - this.colorTexture = gl.getUniformLocation(this.program, 'colorTex'); - this.widthTexture = gl.getUniformLocation(this.program, 'widthTex'); -} -function GenericStyler(gl, glsl, preface, inline) { - const VS = glsl.VS; - let FS = glsl.FS; - FS = FS.replace('$PREFACE', preface); - FS = FS.replace('$INLINE', inline); - console.log(FS) - compileProgram.call(this, gl, VS, FS); - this.vertexAttribute = gl.getAttribLocation(this.program, 'vertex'); - this.textureLocations = []; - for (let i = 0; i < NUM_TEXTURE_LOCATIONS; i++) { - this.textureLocations[i] = gl.getUniformLocation(this.program, `property${i}`); - } -} -function Color(gl, preface, inline) { - GenericStyler.call(this, gl, __WEBPACK_IMPORTED_MODULE_1__styler__["a" /* color */], preface, inline); -} -function Width(gl, preface, inline) { - GenericStyler.call(this, gl, __WEBPACK_IMPORTED_MODULE_1__styler__["b" /* width */], preface, inline); -} - -const renderer = { - createPointShader: function (gl) { - return new Point(gl); - } -}; - -const styler = { - createColorShader: function (gl, preface, inline) { - return new Color(gl, preface, inline); - }, - createWidthShader: function (gl, preface, inline) { - return new Width(gl, preface, inline); - } -}; - - - - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { +/***/ }), +/* 2 */ +/***/ (function(module, exports, __webpack_require__) { // JavaScript Expression Parser (JSEP) 0.3.2 // JSEP may be freely distributed under the MIT License @@ -3290,100 +1403,806 @@ const styler = { }(this)); -/***/ }), -/* 14 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +/***/ }), +/* 3 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (immutable) */ __webpack_exports__["a"] = parseStyleExpression; +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_jsep__ = __webpack_require__(2); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_jsep___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_jsep__); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__functions__ = __webpack_require__(0); + + + + +//TODO document style expressions +//TODO create complete style API, a way to define a color and a width style at the same time, we just have style expressions now +/* + Returns a valid style expression or throws an exception upon invalid inputs. +*/ +var lowerCaseFunctions = {}; +Object.keys(__WEBPACK_IMPORTED_MODULE_1__functions__).map(name => { + lowerCaseFunctions[name.toLocaleLowerCase()] = __WEBPACK_IMPORTED_MODULE_1__functions__[name]; +}); + +/** + * @api + * @param {*} str + * @param {*} schema + */ +function parseStyleExpression(str, schema) { + // jsep addBinaryOp pollutes its module scope, we need to remove the custom operators afterwards + __WEBPACK_IMPORTED_MODULE_0_jsep___default.a.addBinaryOp("^", 10); + const r = parseNode(__WEBPACK_IMPORTED_MODULE_0_jsep___default()(str), schema); + __WEBPACK_IMPORTED_MODULE_0_jsep___default.a.removeBinaryOp("^"); + return r; +} + +function parseNode(node, schema) { + if (node.type == 'CallExpression') { + const args = node.arguments.map(arg => parseNode(arg, schema)); + const name = node.callee.name.toLowerCase(); + if (lowerCaseFunctions[name]) { + return lowerCaseFunctions[name](...args, schema); + } + throw new Error(`Invalid function name '${node.callee.name}'`); + } else if (node.type == 'Literal') { + return node.value; + } else if (node.type == 'ArrayExpression') { + return node.elements.map(e => parseNode(e, schema)); + } else if (node.type == 'BinaryExpression') { + const left = parseNode(node.left, schema); + const right = parseNode(node.right, schema); + switch (node.operator) { + case "*": + return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatMul"](left, right, schema); + case "/": + return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatDiv"](left, right, schema); + case "+": + return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatAdd"](left, right, schema); + case "-": + return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatSub"](left, right, schema); + case "^": + return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatPow"](left, right, schema); + default: + throw new Error(`Invalid binary operator '${node.operator}'`); + } + } else if (node.type == 'UnaryExpression') { + switch (node.operator) { + case '-': + return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatMul"](-1, parseNode(node.argument, schema)); + case '+': + return parseNode(node.argument, schema); + default: + throw new Error(`Invalid unary operator '${node.operator}'`); + } + } else if (node.type == 'Identifier') { + if (node.name[0] == '$') { + return __WEBPACK_IMPORTED_MODULE_1__functions__["Property"](node.name.substring(1), schema); + } else if (__WEBPACK_IMPORTED_MODULE_1__functions__["schemas"][node.name.toLowerCase()]) { + return __WEBPACK_IMPORTED_MODULE_1__functions__["schemas"][node.name.toLowerCase()](); + } + } + throw new Error(`Invalid expression '${JSON.stringify(node)}'`); +} + + + + +/***/ }), +/* 4 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var VectorTileFeature = __webpack_require__(5); + +module.exports = VectorTileLayer; + +function VectorTileLayer(pbf, end) { + // Public + this.version = 1; + this.name = null; + this.extent = 4096; + this.length = 0; + + // Private + this._pbf = pbf; + this._keys = []; + this._values = []; + this._features = []; + + pbf.readFields(readLayer, this, end); + + this.length = this._features.length; +} + +function readLayer(tag, layer, pbf) { + if (tag === 15) layer.version = pbf.readVarint(); + else if (tag === 1) layer.name = pbf.readString(); + else if (tag === 5) layer.extent = pbf.readVarint(); + else if (tag === 2) layer._features.push(pbf.pos); + else if (tag === 3) layer._keys.push(pbf.readString()); + else if (tag === 4) layer._values.push(readValueMessage(pbf)); +} + +function readValueMessage(pbf) { + var value = null, + end = pbf.readVarint() + pbf.pos; + + while (pbf.pos < end) { + var tag = pbf.readVarint() >> 3; + + value = tag === 1 ? pbf.readString() : + tag === 2 ? pbf.readFloat() : + tag === 3 ? pbf.readDouble() : + tag === 4 ? pbf.readVarint64() : + tag === 5 ? pbf.readVarint() : + tag === 6 ? pbf.readSVarint() : + tag === 7 ? pbf.readBoolean() : null; + } + + return value; +} + +// return feature `i` from this layer as a `VectorTileFeature` +VectorTileLayer.prototype.feature = function(i) { + if (i < 0 || i >= this._features.length) throw new Error('feature index out of bounds'); + + this._pbf.pos = this._features[i]; + + var end = this._pbf.readVarint() + this._pbf.pos; + return new VectorTileFeature(this._pbf, end, this.extent, this._keys, this._values); +}; + + +/***/ }), +/* 5 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var Point = __webpack_require__(20); + +module.exports = VectorTileFeature; + +function VectorTileFeature(pbf, end, extent, keys, values) { + // Public + this.properties = {}; + this.extent = extent; + this.type = 0; + + // Private + this._pbf = pbf; + this._geometry = -1; + this._keys = keys; + this._values = values; + + pbf.readFields(readFeature, this, end); +} + +function readFeature(tag, feature, pbf) { + if (tag == 1) feature.id = pbf.readVarint(); + else if (tag == 2) readTag(pbf, feature); + else if (tag == 3) feature.type = pbf.readVarint(); + else if (tag == 4) feature._geometry = pbf.pos; +} + +function readTag(pbf, feature) { + var end = pbf.readVarint() + pbf.pos; + + while (pbf.pos < end) { + var key = feature._keys[pbf.readVarint()], + value = feature._values[pbf.readVarint()]; + feature.properties[key] = value; + } +} + +VectorTileFeature.types = ['Unknown', 'Point', 'LineString', 'Polygon']; + +VectorTileFeature.prototype.loadGeometry = function() { + var pbf = this._pbf; + pbf.pos = this._geometry; + + var end = pbf.readVarint() + pbf.pos, + cmd = 1, + length = 0, + x = 0, + y = 0, + lines = [], + line; + + while (pbf.pos < end) { + if (!length) { + var cmdLen = pbf.readVarint(); + cmd = cmdLen & 0x7; + length = cmdLen >> 3; + } + + length--; + + if (cmd === 1 || cmd === 2) { + x += pbf.readSVarint(); + y += pbf.readSVarint(); + + if (cmd === 1) { // moveTo + if (line) lines.push(line); + line = []; + } + + line.push(new Point(x, y)); + + } else if (cmd === 7) { + + // Workaround for https://github.com/mapbox/mapnik-vector-tile/issues/90 + if (line) { + line.push(line[0].clone()); // closePolygon + } + + } else { + throw new Error('unknown command ' + cmd); + } + } + + if (line) lines.push(line); + + return lines; +}; + +VectorTileFeature.prototype.bbox = function() { + var pbf = this._pbf; + pbf.pos = this._geometry; + + var end = pbf.readVarint() + pbf.pos, + cmd = 1, + length = 0, + x = 0, + y = 0, + x1 = Infinity, + x2 = -Infinity, + y1 = Infinity, + y2 = -Infinity; + + while (pbf.pos < end) { + if (!length) { + var cmdLen = pbf.readVarint(); + cmd = cmdLen & 0x7; + length = cmdLen >> 3; + } + + length--; + + if (cmd === 1 || cmd === 2) { + x += pbf.readSVarint(); + y += pbf.readSVarint(); + if (x < x1) x1 = x; + if (x > x2) x2 = x; + if (y < y1) y1 = y; + if (y > y2) y2 = y; + + } else if (cmd !== 7) { + throw new Error('unknown command ' + cmd); + } + } + + return [x1, y1, x2, y2]; +}; + +VectorTileFeature.prototype.toGeoJSON = function(x, y, z) { + var size = this.extent * Math.pow(2, z), + x0 = this.extent * x, + y0 = this.extent * y, + coords = this.loadGeometry(), + type = VectorTileFeature.types[this.type], + i, j; + + function project(line) { + for (var j = 0; j < line.length; j++) { + var p = line[j], y2 = 180 - (p.y + y0) * 360 / size; + line[j] = [ + (p.x + x0) * 360 / size - 180, + 360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90 + ]; + } + } + + switch (this.type) { + case 1: + var points = []; + for (i = 0; i < coords.length; i++) { + points[i] = coords[i][0]; + } + coords = points; + project(coords); + break; + + case 2: + for (i = 0; i < coords.length; i++) { + project(coords[i]); + } + break; + + case 3: + coords = classifyRings(coords); + for (i = 0; i < coords.length; i++) { + for (j = 0; j < coords[i].length; j++) { + project(coords[i][j]); + } + } + break; + } + + if (coords.length === 1) { + coords = coords[0]; + } else { + type = 'Multi' + type; + } + + var result = { + type: "Feature", + geometry: { + type: type, + coordinates: coords + }, + properties: this.properties + }; + + if ('id' in this) { + result.id = this.id; + } + + return result; +}; + +// classifies an array of rings into polygons with outer rings and holes + +function classifyRings(rings) { + var len = rings.length; + + if (len <= 1) return [rings]; + + var polygons = [], + polygon, + ccw; + + for (var i = 0; i < len; i++) { + var area = signedArea(rings[i]); + if (area === 0) continue; + + if (ccw === undefined) ccw = area < 0; + + if (ccw === area < 0) { + if (polygon) polygons.push(polygon); + polygon = [rings[i]]; + + } else { + polygon.push(rings[i]); + } + } + if (polygon) polygons.push(polygon); + + return polygons; +} + +function signedArea(ring) { + var sum = 0; + for (var i = 0, len = ring.length, j = len - 1, p1, p2; i < len; j = i++) { + p1 = ring[i]; + p2 = ring[j]; + sum += (p2.x - p1.x) * (p1.y + p2.y); + } + return sum; +} + + +/***/ }), +/* 6 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Renderer; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__shaders__ = __webpack_require__(1); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__style__ = __webpack_require__(12); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__schema__ = __webpack_require__(17); +/* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "c", function() { return __WEBPACK_IMPORTED_MODULE_1__style__; }); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return __WEBPACK_IMPORTED_MODULE_2__schema__["a"]; }); + + + + + + + +/** + * @api + * @typedef {object} RPoint - Point in renderer coordinates space + * @property {number} x + * @property {number} y + */ + + /** + * @api + * @typedef {object} Dataframe - Point in renderer coordinates space + * @property {RPoint} center + * @property {number} scale + * @property {geom} geometry + * @property {Properties} properties + */ + + +// TODO remove +var gl; + +/** + * @description The Render To Texture Width limits the maximum number of features per tile: *maxFeatureCount = RTT_WIDTH^2* + * + * Large RTT_WIDTH values are unsupported by hardware. Limits vary on each machine. + * Support starts to drop from 2048, with a drastic reduction in support for more than 4096 pixels. + * + * Large values imply a small overhead too. + */ +const RTT_WIDTH = 1024; + + +/** + * @description Renderer constructor. Use it to create a new renderer bound to the provided canvas. + * Initialization will be done synchronously. + * The function will fail in case that a WebGL context cannot be created this can happen because of the following reasons: + * * The provided canvas element is invalid + * * The browser or the machine doesn't support WebGL or the required WebGL extension and minimum parameter values + * @api + * @memberOf renderer + * @constructor + * @param {HTMLElement} canvas - the WebGL context will be created on this element + */ +function Renderer(canvas) { + this.canvas = canvas; + this.tiles = []; + if (!gl) { //TODO remove hack: remove global context + gl = canvas.getContext('webgl'); + if (!gl) { + throw new Error("WebGL extension OES_texture_float is unsupported"); + } + var ext = gl.getExtension("OES_texture_float"); + if (!ext) { + throw new Error("WebGL extension OES_texture_float is unsupported"); + } + const supportedRTT = gl.getParameter(gl.MAX_RENDERBUFFER_SIZE); + if (supportedRTT < RTT_WIDTH) { + throw new Error(`WebGL parameter 'gl.MAX_RENDERBUFFER_SIZE' is below the requirement: ${supportedRTT} < ${RTT_WIDTH}`); + } + __WEBPACK_IMPORTED_MODULE_1__style__["setGL"](gl); + this._initShaders(); + this._center = { x: 0, y: 0 }; + this._zoom = 1; + } + this.squareBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, this.squareBuffer); + var vertices = [ + 10.0, -10.0, + 0.0, 10.0, + -10.0, -10.0, + ]; + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); +} + +/** + * Get Renderer visualization center + * @api + * @return {RPoint} + */ +Renderer.prototype.getCenter = function () { + return { x: this._center.x, y: this._center.y }; +}; +/** + * Set Renderer visualization center + * @api + * @param {number} x + * @param {number} y + */ +Renderer.prototype.setCenter = function (x, y) { + this._center.x = x; + this._center.y = y; + window.requestAnimationFrame(refresh.bind(this)); +}; +/** + * Get Renderer visualization zoom + * @api + * @return {number} + */ +Renderer.prototype.getZoom = function () { + return this._zoom; +}; +/** + * Set Renderer visualization zoom + * @api + * @param {number} zoom + */ +Renderer.prototype.setZoom = function (zoom) { + this._zoom = zoom; + window.requestAnimationFrame(refresh.bind(this)); +}; + +/** + * Removes a dataframe for the renderer. Freeing its resources. + * @api + * @param {*} tile + */ +Renderer.prototype.removeDataframe = function (dataframe) { + this.tiles = this.tiles.filter(t => t !== dataframe); + dataframe.propertyTex.map(tex => gl.deleteTexture(tex)); + gl.deleteTexture(dataframe.texColor); + gl.deleteTexture(dataframe.texWidth); + gl.deleteBuffer(dataframe.vertexBuffer); + gl.deleteBuffer(dataframe.featureIDBuffer); +}; + +/** + * @api + * @description Adds a new dataframe to the renderer. + * + * Performance-intensive. The required allocation and copy of resources will happen synchronously. + * To achieve good performance, avoid multiple calls within the same event, particularly with large dataframes. + * @param {Dataframe} dataframe + */ +Renderer.prototype.addDataframe = function (tile) { + this.tiles.push(tile); + tile.propertyTex = []; + + var points = tile.geom; + const level = 0; + const width = RTT_WIDTH; + tile.numVertex = points.length / 2; + const height = Math.ceil(tile.numVertex / width); + const border = 0; + const srcFormat = gl.RED; + const srcType = gl.FLOAT; + tile.height = height; + tile.propertyID = {}; //Name => PID + tile.propertyCount = 0; + + + for (var k in tile.properties) { + if (tile.properties.hasOwnProperty(k) && tile.properties[k].length > 0) { + const isCategory = !Number.isFinite(tile.properties[k][0]); + const property = tile.properties[k]; + var propertyID = tile.propertyID[k]; + if (propertyID === undefined) { + propertyID = tile.propertyCount; + tile.propertyCount++; + tile.propertyID[k] = propertyID; + } + tile.propertyTex[propertyID] = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tile.propertyTex[propertyID]); + const pixel = new Float32Array(width * height); + for (var i = 0; i < property.length; i++) { + pixel[i] = property[i]; + } + gl.texImage2D(gl.TEXTURE_2D, level, gl.ALPHA, + width, height, 0, gl.ALPHA, srcType, + pixel); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + } + } + + tile.setStyle = function (style) { + __WEBPACK_IMPORTED_MODULE_2__schema__["b" /* checkschemaMatch */](style.schema, tile.schema); + this.style = style; + } + tile.style = null; + + tile.vertexBuffer = gl.createBuffer(); + tile.featureIDBuffer = gl.createBuffer(); + + + tile.texColor = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tile.texColor); + gl.texImage2D(gl.TEXTURE_2D, level, gl.RGBA, + width, height, border, gl.RGBA, gl.UNSIGNED_BYTE, + new Uint8Array(4 * width * height).fill(255)); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); -"use strict"; -/* harmony export (immutable) */ __webpack_exports__["a"] = parseStyleExpression; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_jsep__ = __webpack_require__(13); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_jsep___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_jsep__); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__functions__ = __webpack_require__(11); + tile.texWidth = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tile.texWidth); + gl.texImage2D(gl.TEXTURE_2D, level, gl.RGBA, + width, height, border, gl.RGBA, gl.UNSIGNED_BYTE, + new Uint8Array(4 * width * height).fill(100)); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + var ids = new Float32Array(points.length); + for (var i = 0; i < points.length; i += 2) { + ids[i + 0] = ((i / 2) % width) / width; + ids[i + 1] = Math.floor((i / 2) / width) / height; + } -//TODO document style expressions -//TODO create complete style API, a way to define a color and a width style at the same time, we just have style expressions now -/* - Returns a valid style expression or throws an exception upon invalid inputs. -*/ -var lowerCaseFunctions = {}; -Object.keys(__WEBPACK_IMPORTED_MODULE_1__functions__).map(name => { - lowerCaseFunctions[name.toLocaleLowerCase()] = __WEBPACK_IMPORTED_MODULE_1__functions__[name]; -}); + gl.bindBuffer(gl.ARRAY_BUFFER, tile.vertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW); -function parseStyleExpression(str, scheme) { - // jsep addBinaryOp pollutes its module scope, we need to remove the custom operators afterwards - __WEBPACK_IMPORTED_MODULE_0_jsep___default.a.addBinaryOp("^", 10); - const r = parseNode(__WEBPACK_IMPORTED_MODULE_0_jsep___default()(str), scheme); - __WEBPACK_IMPORTED_MODULE_0_jsep___default.a.removeBinaryOp("^"); - return r; -} + gl.bindBuffer(gl.ARRAY_BUFFER, tile.featureIDBuffer); + gl.bufferData(gl.ARRAY_BUFFER, ids, gl.STATIC_DRAW); -function parseNode(node, scheme) { - if (node.type == 'CallExpression') { - const args = node.arguments.map(arg => parseNode(arg, scheme)); - const name = node.callee.name.toLowerCase(); - if (lowerCaseFunctions[name]) { - return lowerCaseFunctions[name](...args, scheme); - } - throw new Error(`Invalid function name '${node.callee.name}'`); - } else if (node.type == 'Literal') { - return node.value; - } else if (node.type == 'ArrayExpression') { - return node.elements.map(e => parseNode(e, scheme)); - } else if (node.type == 'BinaryExpression') { - const left = parseNode(node.left, scheme); - const right = parseNode(node.right, scheme); - switch (node.operator) { - case "*": - return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatMul"](left, right, scheme); - case "/": - return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatDiv"](left, right, scheme); - case "+": - return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatAdd"](left, right, scheme); - case "-": - return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatSub"](left, right, scheme); - case "^": - return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatPow"](left, right, scheme); - default: - throw new Error(`Invalid binary operator '${node.operator}'`); + gl.bindBuffer(gl.ARRAY_BUFFER, null); + + window.requestAnimationFrame(refresh.bind(this)); + + return tile; +}; + +/** + * Refresh the canvas by redrawing everything needed. + * Should only be called by requestAnimationFrame + * @param timestamp - timestamp of the animation provided by requestAnimationFrame + */ +Renderer.prototype.refresh = refresh; +function refresh(timestamp) { + // Don't re-render more than once per animation frame + if (this.lastFrame == timestamp) { + return; + } + this.lastFrame = timestamp; + var canvas = this.canvas; + var width = gl.canvas.clientWidth; + var height = gl.canvas.clientHeight; + if (gl.canvas.width != width || + gl.canvas.height != height) { + gl.canvas.width = width; + gl.canvas.height = height; + } + var aspect = canvas.clientWidth / canvas.clientHeight; + gl.clearColor(0., 0., 0., 0.);//TODO this should be a renderer property + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + + gl.enable(gl.CULL_FACE); + + //TODO refactor condition + gl.disable(gl.BLEND); + gl.disable(gl.DEPTH_TEST); + + if (!this.auxFB) { + this.auxFB = gl.createFramebuffer(); + } + gl.bindFramebuffer(gl.FRAMEBUFFER, this.auxFB); + //console.log("Restyle", timestamp) + // Render To Texture + // COLOR + this.tiles.forEach(tile => { + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tile.texColor, 0); + gl.viewport(0, 0, RTT_WIDTH, tile.height); + gl.clear(gl.COLOR_BUFFER_BIT); + + gl.useProgram(tile.style.colorShader.program); + var obj = { + freeTexUnit: 4 } - } else if (node.type == 'UnaryExpression') { - switch (node.operator) { - case '-': - return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatMul"](-1, parseNode(node.argument, scheme)); - case '+': - return parseNode(node.argument, scheme); - default: - throw new Error(`Invalid unary operator '${node.operator}'`); + tile.style._color._preDraw(obj); + + Object.keys(tile.style.propertyColorTID).forEach((name, i) => { + gl.activeTexture(gl.TEXTURE0 + i); + gl.bindTexture(gl.TEXTURE_2D, tile.propertyTex[tile.propertyID[name]]); + gl.uniform1i(tile.style.colorShader.textureLocations[i], i); + }); + + gl.enableVertexAttribArray(this.colorShaderVertex); + gl.bindBuffer(gl.ARRAY_BUFFER, this.squareBuffer); + gl.vertexAttribPointer(tile.style.colorShader.vertexAttribute, 2, gl.FLOAT, false, 0, 0); + + gl.drawArrays(gl.TRIANGLES, 0, 3); + }); + + //WIDTH + this.tiles.forEach(tile => { + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tile.texWidth, 0); + gl.useProgram(tile.style.widthShader.program); + gl.viewport(0, 0, RTT_WIDTH, tile.height); + gl.clear(gl.COLOR_BUFFER_BIT); + var obj = { + freeTexUnit: 4 } - } else if (node.type == 'Identifier') { - if (node.name[0] == '$') { - return __WEBPACK_IMPORTED_MODULE_1__functions__["Property"](node.name.substring(1), scheme); - } else if (__WEBPACK_IMPORTED_MODULE_1__functions__["schemes"][node.name.toLowerCase()]) { - return __WEBPACK_IMPORTED_MODULE_1__functions__["schemes"][node.name.toLowerCase()](); + tile.style._width._preDraw(obj); + Object.keys(tile.style.propertyWidthTID).forEach((name, i) => { + gl.activeTexture(gl.TEXTURE0 + i); + gl.bindTexture(gl.TEXTURE_2D, tile.propertyTex[tile.propertyID[name]]); + gl.uniform1i(tile.style.widthShader.textureLocations[i], i); + }); + + gl.enableVertexAttribArray(tile.style.widthShader.vertexAttribute); + gl.bindBuffer(gl.ARRAY_BUFFER, this.squareBuffer); + gl.vertexAttribPointer(tile.style.widthShader.vertexAttribute, 2, gl.FLOAT, false, 0, 0); + + gl.drawArrays(gl.TRIANGLES, 0, 3); + + tile.style.updated = false; + tile.initialized = true; + }); + + + gl.enable(gl.DEPTH_TEST); + + gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); + gl.enable(gl.BLEND); + + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); + + gl.useProgram(this.finalRendererProgram.program); + var s = 1. / this._zoom; + + + this.tiles.forEach(tile => { + /*console.log((s / aspect) * tile.scale, + s * tile.scale, + (s / aspect) * this._center.x - tile.center.x, + s * this._center.y - tile.center.y + );*/ + gl.uniform2f(this.finalRendererProgram.vertexScaleUniformLocation, + (s / aspect) * tile.scale, + s * tile.scale); + gl.uniform2f(this.finalRendererProgram.vertexOffsetUniformLocation, + (s / aspect) * (this._center.x - tile.center.x), + s * (this._center.y - tile.center.y)); + + gl.enableVertexAttribArray(this.finalRendererProgram.vertexPositionAttribute); + gl.bindBuffer(gl.ARRAY_BUFFER, tile.vertexBuffer); + gl.vertexAttribPointer(this.finalRendererProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); + + + gl.enableVertexAttribArray(this.finalRendererProgram.featureIdAttr); + gl.bindBuffer(gl.ARRAY_BUFFER, tile.featureIDBuffer); + gl.vertexAttribPointer(this.finalRendererProgram.featureIdAttr, 2, gl.FLOAT, false, 0, 0); + + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, tile.texColor); + gl.uniform1i(this.finalRendererProgram.colorTexture, 0); + + gl.activeTexture(gl.TEXTURE1); + gl.bindTexture(gl.TEXTURE_2D, tile.texWidth); + gl.uniform1i(this.finalRendererProgram.widthTexture, 1); + + gl.drawArrays(gl.POINTS, 0, tile.numVertex); + + }); + + this.tiles.forEach(t => { + if (t.style._color.isAnimated() || t.style._width.isAnimated()) { + window.requestAnimationFrame(refresh.bind(this)); } - } - throw new Error(`Invalid expression '${JSON.stringify(node)}'`); + }); } - +/** + * Initialize static shaders + */ +Renderer.prototype._initShaders = function () { + this.finalRendererProgram = __WEBPACK_IMPORTED_MODULE_0__shaders__["a" /* renderer */].createPointShader(gl); +} /***/ }), -/* 15 */ +/* 7 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__point__ = __webpack_require__(16); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__point__ = __webpack_require__(8); /* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "a", function() { return __WEBPACK_IMPORTED_MODULE_0__point__; }); /***/ }), -/* 16 */ +/* 8 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -3435,12 +2254,12 @@ void main(void) { /***/ }), -/* 17 */ +/* 9 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__color__ = __webpack_require__(18); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__width__ = __webpack_require__(19); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__color__ = __webpack_require__(10); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__width__ = __webpack_require__(11); /* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "a", function() { return __WEBPACK_IMPORTED_MODULE_0__color__; }); /* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "b", function() { return __WEBPACK_IMPORTED_MODULE_1__width__; }); @@ -3448,7 +2267,7 @@ void main(void) { /***/ }), -/* 18 */ +/* 10 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -3494,7 +2313,7 @@ void main(void) { /***/ }), -/* 19 */ +/* 11 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -3539,18 +2358,18 @@ void main(void) { /***/ }), -/* 20 */ +/* 12 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Style", function() { return Style; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "setGL", function() { return setGL; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_jsep__ = __webpack_require__(13); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_jsep__ = __webpack_require__(2); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_jsep___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_jsep__); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__functions__ = __webpack_require__(11); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__parser__ = __webpack_require__(14); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__shaders__ = __webpack_require__(12); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__functions__ = __webpack_require__(0); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__parser__ = __webpack_require__(3); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__shaders__ = __webpack_require__(1); /* harmony namespace reexport (by provided) */ __webpack_require__.d(__webpack_exports__, "Property", function() { return __WEBPACK_IMPORTED_MODULE_1__functions__["Property"]; }); /* harmony namespace reexport (by provided) */ __webpack_require__.d(__webpack_exports__, "Blend", function() { return __WEBPACK_IMPORTED_MODULE_1__functions__["Blend"]; }); /* harmony namespace reexport (by provided) */ __webpack_require__.d(__webpack_exports__, "Now", function() { return __WEBPACK_IMPORTED_MODULE_1__functions__["Now"]; }); @@ -3563,7 +2382,7 @@ Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); /* harmony namespace reexport (by provided) */ __webpack_require__.d(__webpack_exports__, "FloatAdd", function() { return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatAdd"]; }); /* harmony namespace reexport (by provided) */ __webpack_require__.d(__webpack_exports__, "FloatSub", function() { return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatSub"]; }); /* harmony namespace reexport (by provided) */ __webpack_require__.d(__webpack_exports__, "FloatPow", function() { return __WEBPACK_IMPORTED_MODULE_1__functions__["FloatPow"]; }); -/* harmony namespace reexport (by provided) */ __webpack_require__.d(__webpack_exports__, "schemes", function() { return __WEBPACK_IMPORTED_MODULE_1__functions__["schemes"]; }); +/* harmony namespace reexport (by provided) */ __webpack_require__.d(__webpack_exports__, "schemas", function() { return __WEBPACK_IMPORTED_MODULE_1__functions__["schemas"]; }); /* harmony namespace reexport (by provided) */ __webpack_require__.d(__webpack_exports__, "parseStyleExpression", function() { return __WEBPACK_IMPORTED_MODULE_2__parser__["a"]; }); var gl = null; @@ -3612,11 +2431,16 @@ Style.prototype._compileWidthShader = function () { this.widthShader = r.shader; } - -function Style(renderer, scheme) { +/** + * @api + * @constructor + * @param {*} renderer + * @param {*} schema + */ +function Style(renderer, schema) { this.renderer = renderer; this.updated = true; - this.scheme = scheme; + this.schema = schema; this._width = __WEBPACK_IMPORTED_MODULE_1__functions__["Float"](5); this._width.parent = this; @@ -3631,6 +2455,10 @@ function Style(renderer, scheme) { window.requestAnimationFrame(this.renderer.refresh.bind(this.renderer)); }; } +/** + * @api + * @param {*} float + */ Style.prototype.setWidth = function (float) { this._width = float; this.updated = true; @@ -3654,7 +2482,10 @@ Style.prototype.replaceChild = function (toReplace, replacer) { console.warn('No child found'); } } - +/** + * @api + * @param {*} color + */ Style.prototype.setColor = function (color) { this._color = color; this.updated = true; @@ -3665,22 +2496,28 @@ Style.prototype.setColor = function (color) { }; color.notify(); } +/** + * @api + */ Style.prototype.getWidth = function () { return this._width; } +/** + * @api + */ Style.prototype.getColor = function () { return this._color; } /***/ }), -/* 21 */ +/* 13 */ /***/ (function(module, exports, __webpack_require__) { -module.exports = __webpack_require__(22); +module.exports = __webpack_require__(14); /***/ }), -/* 22 */ +/* 14 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;!function() { @@ -5533,7 +4370,7 @@ var colorbrewer_tags = { "YlOrRd": { "tags": ["quantitative"] } } -var colorbrewer = __webpack_require__(23); +var colorbrewer = __webpack_require__(15); // augment colorbrewer with tags for (var r in colorbrewer) { @@ -5566,14 +4403,14 @@ if (true) { /***/ }), -/* 23 */ +/* 15 */ /***/ (function(module, exports, __webpack_require__) { -module.exports = __webpack_require__(24); +module.exports = __webpack_require__(16); /***/ }), -/* 24 */ +/* 16 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;// This product includes color specifications and designs developed by Cynthia Brewer (http://colorbrewer.org/). @@ -5882,44 +4719,1308 @@ var colorbrewer = {YlGn: { 12: ["#8dd3c7","#ffffb3","#bebada","#fb8072","#80b1d3","#fdb462","#b3de69","#fccde5","#d9d9d9","#bc80bd","#ccebc5","#ffed6f"] }}; -if (true) { - !(__WEBPACK_AMD_DEFINE_FACTORY__ = (colorbrewer), - __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? - (__WEBPACK_AMD_DEFINE_FACTORY__.call(exports, __webpack_require__, exports, module)) : - __WEBPACK_AMD_DEFINE_FACTORY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} else if (typeof module === "object" && module.exports) { - module.exports = colorbrewer; -} else { - this.colorbrewer = colorbrewer; +if (true) { + !(__WEBPACK_AMD_DEFINE_FACTORY__ = (colorbrewer), + __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? + (__WEBPACK_AMD_DEFINE_FACTORY__.call(exports, __webpack_require__, exports, module)) : + __WEBPACK_AMD_DEFINE_FACTORY__), + __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); +} else if (typeof module === "object" && module.exports) { + module.exports = colorbrewer; +} else { + this.colorbrewer = colorbrewer; +} + +}(); + + +/***/ }), +/* 17 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Schema; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return checkschemaMatch; }); +/** + * @api + * @constructor + * @param {*} propertyNames + * @param {*} propertyTypes + */ +function Schema(propertyNames, propertyTypes) { + if (propertyNames.length != propertyTypes.length) { + throw new Error("propertyNames and propertyTypes lengths mismatch"); + } + propertyNames.map((name, index) => this[name] = propertyTypes[index]); +} + +/** + * + * @param {*} schemaA + * @param {*} schemaB + */ +function checkschemaMatch(schemaA, schemaB) { + if (schemaA && schemaB) { + const equals = Object.keys(schemaA).map(name => schemaA[name] == schemaB[name]).reduce((a, b) => a && b); + if (!equals) { + throw new Error(`schema mismatch: ${JSON.stringify(schemaA)}, ${JSON.stringify(schemaB)}`); + } + } +} + + + +/***/ }), +/* 18 */ +/***/ (function(module, exports, __webpack_require__) { + +module.exports.VectorTile = __webpack_require__(19); +module.exports.VectorTileFeature = __webpack_require__(5); +module.exports.VectorTileLayer = __webpack_require__(4); + + +/***/ }), +/* 19 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var VectorTileLayer = __webpack_require__(4); + +module.exports = VectorTile; + +function VectorTile(pbf, end) { + this.layers = pbf.readFields(readTile, {}, end); +} + +function readTile(tag, layers, pbf) { + if (tag === 3) { + var layer = new VectorTileLayer(pbf, pbf.readVarint() + pbf.pos); + if (layer.length) layers[layer.name] = layer; + } +} + + + +/***/ }), +/* 20 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +module.exports = Point; + +/** + * A standalone point geometry with useful accessor, comparison, and + * modification methods. + * + * @class Point + * @param {Number} x the x-coordinate. this could be longitude or screen + * pixels, or any other sort of unit. + * @param {Number} y the y-coordinate. this could be latitude or screen + * pixels, or any other sort of unit. + * @example + * var point = new Point(-77, 38); + */ +function Point(x, y) { + this.x = x; + this.y = y; +} + +Point.prototype = { + + /** + * Clone this point, returning a new point that can be modified + * without affecting the old one. + * @return {Point} the clone + */ + clone: function() { return new Point(this.x, this.y); }, + + /** + * Add this point's x & y coordinates to another point, + * yielding a new point. + * @param {Point} p the other point + * @return {Point} output point + */ + add: function(p) { return this.clone()._add(p); }, + + /** + * Subtract this point's x & y coordinates to from point, + * yielding a new point. + * @param {Point} p the other point + * @return {Point} output point + */ + sub: function(p) { return this.clone()._sub(p); }, + + /** + * Multiply this point's x & y coordinates by point, + * yielding a new point. + * @param {Point} p the other point + * @return {Point} output point + */ + multByPoint: function(p) { return this.clone()._multByPoint(p); }, + + /** + * Divide this point's x & y coordinates by point, + * yielding a new point. + * @param {Point} p the other point + * @return {Point} output point + */ + divByPoint: function(p) { return this.clone()._divByPoint(p); }, + + /** + * Multiply this point's x & y coordinates by a factor, + * yielding a new point. + * @param {Point} k factor + * @return {Point} output point + */ + mult: function(k) { return this.clone()._mult(k); }, + + /** + * Divide this point's x & y coordinates by a factor, + * yielding a new point. + * @param {Point} k factor + * @return {Point} output point + */ + div: function(k) { return this.clone()._div(k); }, + + /** + * Rotate this point around the 0, 0 origin by an angle a, + * given in radians + * @param {Number} a angle to rotate around, in radians + * @return {Point} output point + */ + rotate: function(a) { return this.clone()._rotate(a); }, + + /** + * Rotate this point around p point by an angle a, + * given in radians + * @param {Number} a angle to rotate around, in radians + * @param {Point} p Point to rotate around + * @return {Point} output point + */ + rotateAround: function(a,p) { return this.clone()._rotateAround(a,p); }, + + /** + * Multiply this point by a 4x1 transformation matrix + * @param {Array} m transformation matrix + * @return {Point} output point + */ + matMult: function(m) { return this.clone()._matMult(m); }, + + /** + * Calculate this point but as a unit vector from 0, 0, meaning + * that the distance from the resulting point to the 0, 0 + * coordinate will be equal to 1 and the angle from the resulting + * point to the 0, 0 coordinate will be the same as before. + * @return {Point} unit vector point + */ + unit: function() { return this.clone()._unit(); }, + + /** + * Compute a perpendicular point, where the new y coordinate + * is the old x coordinate and the new x coordinate is the old y + * coordinate multiplied by -1 + * @return {Point} perpendicular point + */ + perp: function() { return this.clone()._perp(); }, + + /** + * Return a version of this point with the x & y coordinates + * rounded to integers. + * @return {Point} rounded point + */ + round: function() { return this.clone()._round(); }, + + /** + * Return the magitude of this point: this is the Euclidean + * distance from the 0, 0 coordinate to this point's x and y + * coordinates. + * @return {Number} magnitude + */ + mag: function() { + return Math.sqrt(this.x * this.x + this.y * this.y); + }, + + /** + * Judge whether this point is equal to another point, returning + * true or false. + * @param {Point} other the other point + * @return {boolean} whether the points are equal + */ + equals: function(other) { + return this.x === other.x && + this.y === other.y; + }, + + /** + * Calculate the distance from this point to another point + * @param {Point} p the other point + * @return {Number} distance + */ + dist: function(p) { + return Math.sqrt(this.distSqr(p)); + }, + + /** + * Calculate the distance from this point to another point, + * without the square root step. Useful if you're comparing + * relative distances. + * @param {Point} p the other point + * @return {Number} distance + */ + distSqr: function(p) { + var dx = p.x - this.x, + dy = p.y - this.y; + return dx * dx + dy * dy; + }, + + /** + * Get the angle from the 0, 0 coordinate to this point, in radians + * coordinates. + * @return {Number} angle + */ + angle: function() { + return Math.atan2(this.y, this.x); + }, + + /** + * Get the angle from this point to another point, in radians + * @param {Point} b the other point + * @return {Number} angle + */ + angleTo: function(b) { + return Math.atan2(this.y - b.y, this.x - b.x); + }, + + /** + * Get the angle between this point and another point, in radians + * @param {Point} b the other point + * @return {Number} angle + */ + angleWith: function(b) { + return this.angleWithSep(b.x, b.y); + }, + + /* + * Find the angle of the two vectors, solving the formula for + * the cross product a x b = |a||b|sin(θ) for θ. + * @param {Number} x the x-coordinate + * @param {Number} y the y-coordinate + * @return {Number} the angle in radians + */ + angleWithSep: function(x, y) { + return Math.atan2( + this.x * y - this.y * x, + this.x * x + this.y * y); + }, + + _matMult: function(m) { + var x = m[0] * this.x + m[1] * this.y, + y = m[2] * this.x + m[3] * this.y; + this.x = x; + this.y = y; + return this; + }, + + _add: function(p) { + this.x += p.x; + this.y += p.y; + return this; + }, + + _sub: function(p) { + this.x -= p.x; + this.y -= p.y; + return this; + }, + + _mult: function(k) { + this.x *= k; + this.y *= k; + return this; + }, + + _div: function(k) { + this.x /= k; + this.y /= k; + return this; + }, + + _multByPoint: function(p) { + this.x *= p.x; + this.y *= p.y; + return this; + }, + + _divByPoint: function(p) { + this.x /= p.x; + this.y /= p.y; + return this; + }, + + _unit: function() { + this._div(this.mag()); + return this; + }, + + _perp: function() { + var y = this.y; + this.y = this.x; + this.x = -y; + return this; + }, + + _rotate: function(angle) { + var cos = Math.cos(angle), + sin = Math.sin(angle), + x = cos * this.x - sin * this.y, + y = sin * this.x + cos * this.y; + this.x = x; + this.y = y; + return this; + }, + + _rotateAround: function(angle, p) { + var cos = Math.cos(angle), + sin = Math.sin(angle), + x = p.x + cos * (this.x - p.x) - sin * (this.y - p.y), + y = p.y + sin * (this.x - p.x) + cos * (this.y - p.y); + this.x = x; + this.y = y; + return this; + }, + + _round: function() { + this.x = Math.round(this.x); + this.y = Math.round(this.y); + return this; + } +}; + +/** + * Construct a point from an array if necessary, otherwise if the input + * is already a Point, or an unknown type, return it unchanged + * @param {Array|Point|*} a any kind of input value + * @return {Point} constructed point, or passed-through value. + * @example + * // this + * var point = Point.convert([0, 1]); + * // is equivalent to + * var point = new Point(0, 1); + */ +Point.convert = function (a) { + if (a instanceof Point) { + return a; + } + if (Array.isArray(a)) { + return new Point(a[0], a[1]); + } + return a; +}; + + +/***/ }), +/* 21 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +module.exports = Pbf; + +var ieee754 = __webpack_require__(22); + +function Pbf(buf) { + this.buf = ArrayBuffer.isView && ArrayBuffer.isView(buf) ? buf : new Uint8Array(buf || 0); + this.pos = 0; + this.type = 0; + this.length = this.buf.length; +} + +Pbf.Varint = 0; // varint: int32, int64, uint32, uint64, sint32, sint64, bool, enum +Pbf.Fixed64 = 1; // 64-bit: double, fixed64, sfixed64 +Pbf.Bytes = 2; // length-delimited: string, bytes, embedded messages, packed repeated fields +Pbf.Fixed32 = 5; // 32-bit: float, fixed32, sfixed32 + +var SHIFT_LEFT_32 = (1 << 16) * (1 << 16), + SHIFT_RIGHT_32 = 1 / SHIFT_LEFT_32; + +Pbf.prototype = { + + destroy: function() { + this.buf = null; + }, + + // === READING ================================================================= + + readFields: function(readField, result, end) { + end = end || this.length; + + while (this.pos < end) { + var val = this.readVarint(), + tag = val >> 3, + startPos = this.pos; + + this.type = val & 0x7; + readField(tag, result, this); + + if (this.pos === startPos) this.skip(val); + } + return result; + }, + + readMessage: function(readField, result) { + return this.readFields(readField, result, this.readVarint() + this.pos); + }, + + readFixed32: function() { + var val = readUInt32(this.buf, this.pos); + this.pos += 4; + return val; + }, + + readSFixed32: function() { + var val = readInt32(this.buf, this.pos); + this.pos += 4; + return val; + }, + + // 64-bit int handling is based on github.com/dpw/node-buffer-more-ints (MIT-licensed) + + readFixed64: function() { + var val = readUInt32(this.buf, this.pos) + readUInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32; + this.pos += 8; + return val; + }, + + readSFixed64: function() { + var val = readUInt32(this.buf, this.pos) + readInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32; + this.pos += 8; + return val; + }, + + readFloat: function() { + var val = ieee754.read(this.buf, this.pos, true, 23, 4); + this.pos += 4; + return val; + }, + + readDouble: function() { + var val = ieee754.read(this.buf, this.pos, true, 52, 8); + this.pos += 8; + return val; + }, + + readVarint: function(isSigned) { + var buf = this.buf, + val, b; + + b = buf[this.pos++]; val = b & 0x7f; if (b < 0x80) return val; + b = buf[this.pos++]; val |= (b & 0x7f) << 7; if (b < 0x80) return val; + b = buf[this.pos++]; val |= (b & 0x7f) << 14; if (b < 0x80) return val; + b = buf[this.pos++]; val |= (b & 0x7f) << 21; if (b < 0x80) return val; + b = buf[this.pos]; val |= (b & 0x0f) << 28; + + return readVarintRemainder(val, isSigned, this); + }, + + readVarint64: function() { // for compatibility with v2.0.1 + return this.readVarint(true); + }, + + readSVarint: function() { + var num = this.readVarint(); + return num % 2 === 1 ? (num + 1) / -2 : num / 2; // zigzag encoding + }, + + readBoolean: function() { + return Boolean(this.readVarint()); + }, + + readString: function() { + var end = this.readVarint() + this.pos, + str = readUtf8(this.buf, this.pos, end); + this.pos = end; + return str; + }, + + readBytes: function() { + var end = this.readVarint() + this.pos, + buffer = this.buf.subarray(this.pos, end); + this.pos = end; + return buffer; + }, + + // verbose for performance reasons; doesn't affect gzipped size + + readPackedVarint: function(arr, isSigned) { + var end = readPackedEnd(this); + arr = arr || []; + while (this.pos < end) arr.push(this.readVarint(isSigned)); + return arr; + }, + readPackedSVarint: function(arr) { + var end = readPackedEnd(this); + arr = arr || []; + while (this.pos < end) arr.push(this.readSVarint()); + return arr; + }, + readPackedBoolean: function(arr) { + var end = readPackedEnd(this); + arr = arr || []; + while (this.pos < end) arr.push(this.readBoolean()); + return arr; + }, + readPackedFloat: function(arr) { + var end = readPackedEnd(this); + arr = arr || []; + while (this.pos < end) arr.push(this.readFloat()); + return arr; + }, + readPackedDouble: function(arr) { + var end = readPackedEnd(this); + arr = arr || []; + while (this.pos < end) arr.push(this.readDouble()); + return arr; + }, + readPackedFixed32: function(arr) { + var end = readPackedEnd(this); + arr = arr || []; + while (this.pos < end) arr.push(this.readFixed32()); + return arr; + }, + readPackedSFixed32: function(arr) { + var end = readPackedEnd(this); + arr = arr || []; + while (this.pos < end) arr.push(this.readSFixed32()); + return arr; + }, + readPackedFixed64: function(arr) { + var end = readPackedEnd(this); + arr = arr || []; + while (this.pos < end) arr.push(this.readFixed64()); + return arr; + }, + readPackedSFixed64: function(arr) { + var end = readPackedEnd(this); + arr = arr || []; + while (this.pos < end) arr.push(this.readSFixed64()); + return arr; + }, + + skip: function(val) { + var type = val & 0x7; + if (type === Pbf.Varint) while (this.buf[this.pos++] > 0x7f) {} + else if (type === Pbf.Bytes) this.pos = this.readVarint() + this.pos; + else if (type === Pbf.Fixed32) this.pos += 4; + else if (type === Pbf.Fixed64) this.pos += 8; + else throw new Error('Unimplemented type: ' + type); + }, + + // === WRITING ================================================================= + + writeTag: function(tag, type) { + this.writeVarint((tag << 3) | type); + }, + + realloc: function(min) { + var length = this.length || 16; + + while (length < this.pos + min) length *= 2; + + if (length !== this.length) { + var buf = new Uint8Array(length); + buf.set(this.buf); + this.buf = buf; + this.length = length; + } + }, + + finish: function() { + this.length = this.pos; + this.pos = 0; + return this.buf.subarray(0, this.length); + }, + + writeFixed32: function(val) { + this.realloc(4); + writeInt32(this.buf, val, this.pos); + this.pos += 4; + }, + + writeSFixed32: function(val) { + this.realloc(4); + writeInt32(this.buf, val, this.pos); + this.pos += 4; + }, + + writeFixed64: function(val) { + this.realloc(8); + writeInt32(this.buf, val & -1, this.pos); + writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4); + this.pos += 8; + }, + + writeSFixed64: function(val) { + this.realloc(8); + writeInt32(this.buf, val & -1, this.pos); + writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4); + this.pos += 8; + }, + + writeVarint: function(val) { + val = +val || 0; + + if (val > 0xfffffff || val < 0) { + writeBigVarint(val, this); + return; + } + + this.realloc(4); + + this.buf[this.pos++] = val & 0x7f | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return; + this.buf[this.pos++] = ((val >>>= 7) & 0x7f) | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return; + this.buf[this.pos++] = ((val >>>= 7) & 0x7f) | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return; + this.buf[this.pos++] = (val >>> 7) & 0x7f; + }, + + writeSVarint: function(val) { + this.writeVarint(val < 0 ? -val * 2 - 1 : val * 2); + }, + + writeBoolean: function(val) { + this.writeVarint(Boolean(val)); + }, + + writeString: function(str) { + str = String(str); + this.realloc(str.length * 4); + + this.pos++; // reserve 1 byte for short string length + + var startPos = this.pos; + // write the string directly to the buffer and see how much was written + this.pos = writeUtf8(this.buf, str, this.pos); + var len = this.pos - startPos; + + if (len >= 0x80) makeRoomForExtraLength(startPos, len, this); + + // finally, write the message length in the reserved place and restore the position + this.pos = startPos - 1; + this.writeVarint(len); + this.pos += len; + }, + + writeFloat: function(val) { + this.realloc(4); + ieee754.write(this.buf, val, this.pos, true, 23, 4); + this.pos += 4; + }, + + writeDouble: function(val) { + this.realloc(8); + ieee754.write(this.buf, val, this.pos, true, 52, 8); + this.pos += 8; + }, + + writeBytes: function(buffer) { + var len = buffer.length; + this.writeVarint(len); + this.realloc(len); + for (var i = 0; i < len; i++) this.buf[this.pos++] = buffer[i]; + }, + + writeRawMessage: function(fn, obj) { + this.pos++; // reserve 1 byte for short message length + + // write the message directly to the buffer and see how much was written + var startPos = this.pos; + fn(obj, this); + var len = this.pos - startPos; + + if (len >= 0x80) makeRoomForExtraLength(startPos, len, this); + + // finally, write the message length in the reserved place and restore the position + this.pos = startPos - 1; + this.writeVarint(len); + this.pos += len; + }, + + writeMessage: function(tag, fn, obj) { + this.writeTag(tag, Pbf.Bytes); + this.writeRawMessage(fn, obj); + }, + + writePackedVarint: function(tag, arr) { this.writeMessage(tag, writePackedVarint, arr); }, + writePackedSVarint: function(tag, arr) { this.writeMessage(tag, writePackedSVarint, arr); }, + writePackedBoolean: function(tag, arr) { this.writeMessage(tag, writePackedBoolean, arr); }, + writePackedFloat: function(tag, arr) { this.writeMessage(tag, writePackedFloat, arr); }, + writePackedDouble: function(tag, arr) { this.writeMessage(tag, writePackedDouble, arr); }, + writePackedFixed32: function(tag, arr) { this.writeMessage(tag, writePackedFixed32, arr); }, + writePackedSFixed32: function(tag, arr) { this.writeMessage(tag, writePackedSFixed32, arr); }, + writePackedFixed64: function(tag, arr) { this.writeMessage(tag, writePackedFixed64, arr); }, + writePackedSFixed64: function(tag, arr) { this.writeMessage(tag, writePackedSFixed64, arr); }, + + writeBytesField: function(tag, buffer) { + this.writeTag(tag, Pbf.Bytes); + this.writeBytes(buffer); + }, + writeFixed32Field: function(tag, val) { + this.writeTag(tag, Pbf.Fixed32); + this.writeFixed32(val); + }, + writeSFixed32Field: function(tag, val) { + this.writeTag(tag, Pbf.Fixed32); + this.writeSFixed32(val); + }, + writeFixed64Field: function(tag, val) { + this.writeTag(tag, Pbf.Fixed64); + this.writeFixed64(val); + }, + writeSFixed64Field: function(tag, val) { + this.writeTag(tag, Pbf.Fixed64); + this.writeSFixed64(val); + }, + writeVarintField: function(tag, val) { + this.writeTag(tag, Pbf.Varint); + this.writeVarint(val); + }, + writeSVarintField: function(tag, val) { + this.writeTag(tag, Pbf.Varint); + this.writeSVarint(val); + }, + writeStringField: function(tag, str) { + this.writeTag(tag, Pbf.Bytes); + this.writeString(str); + }, + writeFloatField: function(tag, val) { + this.writeTag(tag, Pbf.Fixed32); + this.writeFloat(val); + }, + writeDoubleField: function(tag, val) { + this.writeTag(tag, Pbf.Fixed64); + this.writeDouble(val); + }, + writeBooleanField: function(tag, val) { + this.writeVarintField(tag, Boolean(val)); + } +}; + +function readVarintRemainder(l, s, p) { + var buf = p.buf, + h, b; + + b = buf[p.pos++]; h = (b & 0x70) >> 4; if (b < 0x80) return toNum(l, h, s); + b = buf[p.pos++]; h |= (b & 0x7f) << 3; if (b < 0x80) return toNum(l, h, s); + b = buf[p.pos++]; h |= (b & 0x7f) << 10; if (b < 0x80) return toNum(l, h, s); + b = buf[p.pos++]; h |= (b & 0x7f) << 17; if (b < 0x80) return toNum(l, h, s); + b = buf[p.pos++]; h |= (b & 0x7f) << 24; if (b < 0x80) return toNum(l, h, s); + b = buf[p.pos++]; h |= (b & 0x01) << 31; if (b < 0x80) return toNum(l, h, s); + + throw new Error('Expected varint not more than 10 bytes'); +} + +function readPackedEnd(pbf) { + return pbf.type === Pbf.Bytes ? + pbf.readVarint() + pbf.pos : pbf.pos + 1; +} + +function toNum(low, high, isSigned) { + if (isSigned) { + return high * 0x100000000 + (low >>> 0); + } + + return ((high >>> 0) * 0x100000000) + (low >>> 0); +} + +function writeBigVarint(val, pbf) { + var low, high; + + if (val >= 0) { + low = (val % 0x100000000) | 0; + high = (val / 0x100000000) | 0; + } else { + low = ~(-val % 0x100000000); + high = ~(-val / 0x100000000); + + if (low ^ 0xffffffff) { + low = (low + 1) | 0; + } else { + low = 0; + high = (high + 1) | 0; + } + } + + if (val >= 0x10000000000000000 || val < -0x10000000000000000) { + throw new Error('Given varint doesn\'t fit into 10 bytes'); + } + + pbf.realloc(10); + + writeBigVarintLow(low, high, pbf); + writeBigVarintHigh(high, pbf); +} + +function writeBigVarintLow(low, high, pbf) { + pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7; + pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7; + pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7; + pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7; + pbf.buf[pbf.pos] = low & 0x7f; +} + +function writeBigVarintHigh(high, pbf) { + var lsb = (high & 0x07) << 4; + + pbf.buf[pbf.pos++] |= lsb | ((high >>>= 3) ? 0x80 : 0); if (!high) return; + pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return; + pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return; + pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return; + pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return; + pbf.buf[pbf.pos++] = high & 0x7f; +} + +function makeRoomForExtraLength(startPos, len, pbf) { + var extraLen = + len <= 0x3fff ? 1 : + len <= 0x1fffff ? 2 : + len <= 0xfffffff ? 3 : Math.ceil(Math.log(len) / (Math.LN2 * 7)); + + // if 1 byte isn't enough for encoding message length, shift the data to the right + pbf.realloc(extraLen); + for (var i = pbf.pos - 1; i >= startPos; i--) pbf.buf[i + extraLen] = pbf.buf[i]; +} + +function writePackedVarint(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeVarint(arr[i]); } +function writePackedSVarint(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSVarint(arr[i]); } +function writePackedFloat(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFloat(arr[i]); } +function writePackedDouble(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeDouble(arr[i]); } +function writePackedBoolean(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeBoolean(arr[i]); } +function writePackedFixed32(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFixed32(arr[i]); } +function writePackedSFixed32(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSFixed32(arr[i]); } +function writePackedFixed64(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFixed64(arr[i]); } +function writePackedSFixed64(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSFixed64(arr[i]); } + +// Buffer code below from https://github.com/feross/buffer, MIT-licensed + +function readUInt32(buf, pos) { + return ((buf[pos]) | + (buf[pos + 1] << 8) | + (buf[pos + 2] << 16)) + + (buf[pos + 3] * 0x1000000); +} + +function writeInt32(buf, val, pos) { + buf[pos] = val; + buf[pos + 1] = (val >>> 8); + buf[pos + 2] = (val >>> 16); + buf[pos + 3] = (val >>> 24); +} + +function readInt32(buf, pos) { + return ((buf[pos]) | + (buf[pos + 1] << 8) | + (buf[pos + 2] << 16)) + + (buf[pos + 3] << 24); +} + +function readUtf8(buf, pos, end) { + var str = ''; + var i = pos; + + while (i < end) { + var b0 = buf[i]; + var c = null; // codepoint + var bytesPerSequence = + b0 > 0xEF ? 4 : + b0 > 0xDF ? 3 : + b0 > 0xBF ? 2 : 1; + + if (i + bytesPerSequence > end) break; + + var b1, b2, b3; + + if (bytesPerSequence === 1) { + if (b0 < 0x80) { + c = b0; + } + } else if (bytesPerSequence === 2) { + b1 = buf[i + 1]; + if ((b1 & 0xC0) === 0x80) { + c = (b0 & 0x1F) << 0x6 | (b1 & 0x3F); + if (c <= 0x7F) { + c = null; + } + } + } else if (bytesPerSequence === 3) { + b1 = buf[i + 1]; + b2 = buf[i + 2]; + if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80) { + c = (b0 & 0xF) << 0xC | (b1 & 0x3F) << 0x6 | (b2 & 0x3F); + if (c <= 0x7FF || (c >= 0xD800 && c <= 0xDFFF)) { + c = null; + } + } + } else if (bytesPerSequence === 4) { + b1 = buf[i + 1]; + b2 = buf[i + 2]; + b3 = buf[i + 3]; + if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80 && (b3 & 0xC0) === 0x80) { + c = (b0 & 0xF) << 0x12 | (b1 & 0x3F) << 0xC | (b2 & 0x3F) << 0x6 | (b3 & 0x3F); + if (c <= 0xFFFF || c >= 0x110000) { + c = null; + } + } + } + + if (c === null) { + c = 0xFFFD; + bytesPerSequence = 1; + + } else if (c > 0xFFFF) { + c -= 0x10000; + str += String.fromCharCode(c >>> 10 & 0x3FF | 0xD800); + c = 0xDC00 | c & 0x3FF; + } + + str += String.fromCharCode(c); + i += bytesPerSequence; + } + + return str; +} + +function writeUtf8(buf, str, pos) { + for (var i = 0, c, lead; i < str.length; i++) { + c = str.charCodeAt(i); // code point + + if (c > 0xD7FF && c < 0xE000) { + if (lead) { + if (c < 0xDC00) { + buf[pos++] = 0xEF; + buf[pos++] = 0xBF; + buf[pos++] = 0xBD; + lead = c; + continue; + } else { + c = lead - 0xD800 << 10 | c - 0xDC00 | 0x10000; + lead = null; + } + } else { + if (c > 0xDBFF || (i + 1 === str.length)) { + buf[pos++] = 0xEF; + buf[pos++] = 0xBF; + buf[pos++] = 0xBD; + } else { + lead = c; + } + continue; + } + } else if (lead) { + buf[pos++] = 0xEF; + buf[pos++] = 0xBF; + buf[pos++] = 0xBD; + lead = null; + } + + if (c < 0x80) { + buf[pos++] = c; + } else { + if (c < 0x800) { + buf[pos++] = c >> 0x6 | 0xC0; + } else { + if (c < 0x10000) { + buf[pos++] = c >> 0xC | 0xE0; + } else { + buf[pos++] = c >> 0x12 | 0xF0; + buf[pos++] = c >> 0xC & 0x3F | 0x80; + } + buf[pos++] = c >> 0x6 & 0x3F | 0x80; + } + buf[pos++] = c & 0x3F | 0x80; + } + } + return pos; +} + + +/***/ }), +/* 22 */ +/***/ (function(module, exports) { + +exports.read = function (buffer, offset, isLE, mLen, nBytes) { + var e, m + var eLen = nBytes * 8 - mLen - 1 + var eMax = (1 << eLen) - 1 + var eBias = eMax >> 1 + var nBits = -7 + var i = isLE ? (nBytes - 1) : 0 + var d = isLE ? -1 : 1 + var s = buffer[offset + i] + + i += d + + e = s & ((1 << (-nBits)) - 1) + s >>= (-nBits) + nBits += eLen + for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {} + + m = e & ((1 << (-nBits)) - 1) + e >>= (-nBits) + nBits += mLen + for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {} + + if (e === 0) { + e = 1 - eBias + } else if (e === eMax) { + return m ? NaN : ((s ? -1 : 1) * Infinity) + } else { + m = m + Math.pow(2, mLen) + e = e - eBias + } + return (s ? -1 : 1) * m * Math.pow(2, e - mLen) } -}(); +exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { + var e, m, c + var eLen = nBytes * 8 - mLen - 1 + var eMax = (1 << eLen) - 1 + var eBias = eMax >> 1 + var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0) + var i = isLE ? 0 : (nBytes - 1) + var d = isLE ? 1 : -1 + var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0 + + value = Math.abs(value) + + if (isNaN(value) || value === Infinity) { + m = isNaN(value) ? 1 : 0 + e = eMax + } else { + e = Math.floor(Math.log(value) / Math.LN2) + if (value * (c = Math.pow(2, -e)) < 1) { + e-- + c *= 2 + } + if (e + eBias >= 1) { + value += rt / c + } else { + value += rt * Math.pow(2, 1 - eBias) + } + if (value * c >= 2) { + e++ + c /= 2 + } + + if (e + eBias >= eMax) { + m = 0 + e = eMax + } else if (e + eBias >= 1) { + m = (value * c - 1) * Math.pow(2, mLen) + e = e + eBias + } else { + m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen) + e = 0 + } + } + + for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} + + e = (e << mLen) | m + eLen += mLen + for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} + + buffer[offset + i - d] |= s * 128 +} /***/ }), -/* 25 */ +/* 23 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Scheme; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return checkSchemeMatch; }); -function Scheme(propertyNames, propertyTypes) { - if (propertyNames.length != propertyTypes.length) { - throw new Error("propertyNames and propertyTypes lengths mismatch"); +Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__src_index__ = __webpack_require__(6); + + + +var VectorTile = __webpack_require__(18).VectorTile; +var Protobuf = __webpack_require__(21); + +var renderer; +var layer; +var oldtile; +var ajax; + +function styleWidth(e) { + const v = document.getElementById("widthStyleEntry").value; + const Near = __WEBPACK_IMPORTED_MODULE_0__src_index__["c" /* Style */].Near; + const Float = __WEBPACK_IMPORTED_MODULE_0__src_index__["c" /* Style */].Float; + const Color = __WEBPACK_IMPORTED_MODULE_0__src_index__["c" /* Style */].Color; + const RampColor = __WEBPACK_IMPORTED_MODULE_0__src_index__["c" /* Style */].RampColor; + const width = eval(v); + if (width) { + layer.style.getWidth().blendTo(width, 1000); } - propertyNames.map((name, index) => this[name] = propertyTypes[index]); } -function checkSchemeMatch(schemeA, schemeB) { - if (schemeA && schemeB) { - const equals = Object.keys(schemeA).map(name => schemeA[name] == schemeB[name]).reduce((a, b) => a && b); - if (!equals) { - throw new Error(`Scheme mismatch: ${JSON.stringify(schemeA)}, ${JSON.stringify(schemeB)}`); - } +function styleColor(e) { + const v = document.getElementById("colorStyleEntry").value; + const Near = __WEBPACK_IMPORTED_MODULE_0__src_index__["c" /* Style */].Near; + const Float = __WEBPACK_IMPORTED_MODULE_0__src_index__["c" /* Style */].Float; + const Color = __WEBPACK_IMPORTED_MODULE_0__src_index__["c" /* Style */].Color; + const RampColor = __WEBPACK_IMPORTED_MODULE_0__src_index__["c" /* Style */].RampColor; + const color = eval(v); + if (color) { + layer.style.getColor().blendTo(color, 1000); + } +} + +function getData() { + if (ajax) { + ajax.abort(); } + + var oReq = new XMLHttpRequest(); + oReq.open("GET", "https://dmanzanares.carto.com/api/v1/map/dmanzanares@789cad67@92456f0655aac0322b2572f4e05088e7:1509358508954/mapnik/0/0/0.mvt", true); + oReq.responseType = "arraybuffer"; + oReq.onload = function (oEvent) { + var arrayBuffer = oReq.response; + console.log("MVT1", arrayBuffer, oEvent, oReq); + if (arrayBuffer) { + var tile = new VectorTile(new Protobuf(arrayBuffer)); + console.log("MVT", tile); + const mvtLayer = tile.layers[Object.keys(tile.layers)[0]]; + + var fieldMap = { + temp: 0, + daten: 1 + }; + var properties = [[new Float32Array(mvtLayer.length)], [new Float32Array(mvtLayer.length)]]; + var points = new Float32Array(mvtLayer.length * 2); + for (var i = 0; i < mvtLayer.length; i++) { + const f = mvtLayer.feature(i); + const geom = f.loadGeometry(); + //console.log(mvtLayer.feature(i).toGeoJSON(0,0,0)) + points[2 * i + 0] = (geom[0][0].x) / 4096.0; + points[2 * i + 1] = 1. - (geom[0][0].y) / 4096.0; + + properties[0][i] = Number(f.properties.temp); + properties[1][i] = Number(f.properties.daten); + + /*Object.keys(f.properties).map(name => { + if (fieldMap[name] === undefined) { + fieldMap[name] = Object.keys(fieldMap).length; + } + var pid = fieldMap[name]; + if (properties[pid] === undefined) { + properties[pid] = new Float32Array(mvtLayer.length); + } + properties[pid][i] = Number(f.properties[name]); + });*/ + } + var tile = { + center: { x: 0, y: 0 }, + scale: 1 / 1., + count: mvtLayer.length, + geom: points, + properties: {} + }; + Object.keys(fieldMap).map((name, pid) => { + tile.properties[name] = properties[pid]; + }) + console.log("Tile", tile); + oldtile = layer.addTile(tile); + styleWidth(); + styleColor(); + } + }; + + oReq.send(null); + /* + ajax = $.getJSON("https://dmanzanares.carto.com/api/v2/sql?q=" + encodeURIComponent(document.getElementById("sqlEntry").value) + "&api_key=d9d686df65842a8fddbd186711255ce5d19aa9b8", function (data) { + if (oldtile) { + layer.removeTile(oldtile); + } + console.log("Downloaded", data); + const fields = Object.keys(data.fields).filter(name => name != 'st_asgeojson'); + var properties = fields.map(_ => new Float32Array(data.rows.length)); + var points = new Float32Array(data.rows.length * 2); + data.rows.forEach((e, index) => { + var point = $.parseJSON(e.st_asgeojson).coordinates; + points[2 * index + 0] = (point[0]) + Math.random() * 1000; + points[2 * index + 1] = (point[1]) + Math.random() * 1000; + fields.map((name, pid) => { + properties[pid][index] = Number(e[name]); + }); + }); + var tile = { + center: { x: 0, y: 0 }, + scale: 1 / 10000000., + count: data.rows.length, + geom: points, + properties: {} + }; + fields.map((name, pid) => { + tile.properties[name] = properties[pid]; + }) + console.log("Tile", tile); + oldtile = layer.addTile(tile); + styleWidth(); + styleColor(); + });*/ } +function start() { + renderer = new __WEBPACK_IMPORTED_MODULE_0__src_index__["a" /* Renderer */](document.getElementById('glCanvas')); + layer = renderer.addLayer(); + + getData(); + $('#widthStyleEntry').on('input', styleWidth); + $('#colorStyleEntry').on('input', styleColor); + $('#sqlEntry').on('input', getData); + // Pan and zoom + window.onresize = function () { renderer.refresh(); }; + $(window).bind('mousewheel DOMMouseScroll', function (event) { + if (event.originalEvent.wheelDelta > 0 || event.originalEvent.detail < 0) { + renderer.setZoom(renderer.getZoom() * 0.8); + } else { + renderer.setZoom(renderer.getZoom() / 0.8); + } + }); + var isDragging = false; + var draggOffset = { + x: 0., + y: 0. + }; + document.onmousedown = function (event) { + isDragging = true; + draggOffset = { + x: event.clientX, + y: event.clientY + }; + }; + document.onmousemove = function (event) { + if (isDragging) { + var c = renderer.getCenter(); + var k = renderer.getZoom() / document.body.clientHeight * 2.; + c.x += (draggOffset.x - event.clientX) * k; + c.y += -(draggOffset.y - event.clientY) * k; + renderer.setCenter(c.x, c.y); + draggOffset = { + x: event.clientX, + y: event.clientY + }; + } + }; + document.onmouseup = function () { + isDragging = false; + }; +} +start(); /***/ }) /******/ ]); \ No newline at end of file diff --git a/example/mapbox.js b/example/mapbox.js index f7561ea2a..0c3ca0968 100644 --- a/example/mapbox.js +++ b/example/mapbox.js @@ -8,13 +8,13 @@ var oldtiles = []; var ajax; var style; -var scheme; +var schema; function styleWidth(e) { const v = document.getElementById("widthStyleEntry").value; try { - style.getWidth().blendTo(R.Style.parseStyleExpression(v, scheme), 1000); + style.getWidth().blendTo(R.Style.parseStyleExpression(v, schema), 1000); document.getElementById("feedback").value = 'ok'; } catch (error) { const err = `Invalid width expression: ${error}:${error.stack}`; @@ -25,7 +25,7 @@ function styleWidth(e) { function styleColor(e) { const v = document.getElementById("colorStyleEntry").value; try { - style.getColor().blendTo(R.Style.parseStyleExpression(v, scheme), 1000); + style.getColor().blendTo(R.Style.parseStyleExpression(v, schema), 1000); document.getElementById("feedback").value = 'ok'; } catch (error) { const err = `Invalid color expression: ${error}:${error.stack}`; @@ -87,6 +87,13 @@ function getData(aspect) { const json = JSON.parse(oReq.response); if (json.rows[0].st_asmvt.data.length == 0) { needToComplete--; + if (completedTiles.length == needToComplete) { + oldtiles.forEach(t => renderer.removeDataframe(t)); + completedTiles.forEach(f => renderer.addDataframe(f).setStyle(style)); + oldtiles = completedTiles; + styleWidth(); + styleColor(); + } return; } var tile = new VectorTile(new Protobuf(new Uint8Array(json.rows[0].st_asmvt.data))); @@ -106,22 +113,22 @@ function getData(aspect) { properties[0][i] = Number(r); properties[1][i] = Number(Math.random()); } - var tile = { + console.log(`dataframe feature count: ${mvtLayer.length}`); + var dataframe = { center: { x: ((x + 0.5) / Math.pow(2, z)) * 2. - 1, y: (1. - (y + 0.5) / Math.pow(2, z)) * 2. - 1. }, scale: 1 / Math.pow(2, z), - count: mvtLayer.length, geom: points, properties: {}, }; Object.keys(fieldMap).map((name, pid) => { - tile.properties[name] = properties[pid]; + dataframe.properties[name] = properties[pid]; }); - tile.scheme = new R.Scheme(Object.keys(tile.properties), Object.keys(tile.properties).map(() => 'float')); - console.log(Object.keys(tile.properties), Object.keys(tile.properties).map(() => 'float'), tile.scheme); - completedTiles.push(tile); + dataframe.schema = new R.Schema(Object.keys(dataframe.properties), Object.keys(dataframe.properties).map(() => 'float')); + console.log(Object.keys(dataframe.properties), Object.keys(dataframe.properties).map(() => 'float'), dataframe.schema); + completedTiles.push(dataframe); if (completedTiles.length == needToComplete) { - oldtiles.forEach(t => renderer.removeTile(t)); - completedTiles.forEach(t => renderer.addTile(t).setStyle(style)); + oldtiles.forEach(t => renderer.removeDataframe(t)); + completedTiles.forEach(f => renderer.addDataframe(f).setStyle(style)); oldtiles = completedTiles; styleWidth(); styleColor(); @@ -193,8 +200,8 @@ map.on('load', _ => { } renderer = new R.Renderer(canvas); - scheme = new R.Scheme(['temp', 'daten'], ['float', 'float']); - style = new R.Style.Style(renderer, scheme); + schema = new R.Schema(['temp', 'daten'], ['float', 'float']); + style = new R.Style.Style(renderer, schema); const aspect = canvas.clientWidth / canvas.clientHeight; getData(aspect); $('#widthStyleEntry').on('input', styleWidth); diff --git a/src/index.js b/src/index.js index 5d41c747a..c0b5d97ce 100644 --- a/src/index.js +++ b/src/index.js @@ -1,14 +1,241 @@ import * as shaders from './shaders'; import * as Style from './style'; -import * as scheme from './scheme'; +import * as schema from './schema'; + +export { Renderer, Style }; +export { Schema } from './schema'; + +/** + * @api + * @typedef {object} RPoint - Point in renderer coordinates space + * @property {number} x + * @property {number} y + */ + + /** + * @api + * @typedef {object} Dataframe - Point in renderer coordinates space + * @property {RPoint} center + * @property {number} scale + * @property {geom} geometry + * @property {Properties} properties + */ + // TODO remove var gl; -// The maximum number of features per tile is RTT_WIDTH^2, large RTT_WIDTH values can be unsupported by the hardware, -// they imply a small waste of resources too +/** + * @description The Render To Texture Width limits the maximum number of features per tile: *maxFeatureCount = RTT_WIDTH^2* + * + * Large RTT_WIDTH values are unsupported by hardware. Limits vary on each machine. + * Support starts to drop from 2048, with a drastic reduction in support for more than 4096 pixels. + * + * Large values imply a small overhead too. + */ const RTT_WIDTH = 1024; + +/** + * @description Renderer constructor. Use it to create a new renderer bound to the provided canvas. + * Initialization will be done synchronously. + * The function will fail in case that a WebGL context cannot be created this can happen because of the following reasons: + * * The provided canvas element is invalid + * * The browser or the machine doesn't support WebGL or the required WebGL extension and minimum parameter values + * @api + * @memberOf renderer + * @constructor + * @param {HTMLElement} canvas - the WebGL context will be created on this element + */ +function Renderer(canvas) { + this.canvas = canvas; + this.tiles = []; + if (!gl) { //TODO remove hack: remove global context + gl = canvas.getContext('webgl'); + if (!gl) { + throw new Error("WebGL extension OES_texture_float is unsupported"); + } + var ext = gl.getExtension("OES_texture_float"); + if (!ext) { + throw new Error("WebGL extension OES_texture_float is unsupported"); + } + const supportedRTT = gl.getParameter(gl.MAX_RENDERBUFFER_SIZE); + if (supportedRTT < RTT_WIDTH) { + throw new Error(`WebGL parameter 'gl.MAX_RENDERBUFFER_SIZE' is below the requirement: ${supportedRTT} < ${RTT_WIDTH}`); + } + Style.setGL(gl); + this._initShaders(); + this._center = { x: 0, y: 0 }; + this._zoom = 1; + } + this.squareBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, this.squareBuffer); + var vertices = [ + 10.0, -10.0, + 0.0, 10.0, + -10.0, -10.0, + ]; + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); +} + +/** + * Get Renderer visualization center + * @api + * @return {RPoint} + */ +Renderer.prototype.getCenter = function () { + return { x: this._center.x, y: this._center.y }; +}; +/** + * Set Renderer visualization center + * @api + * @param {number} x + * @param {number} y + */ +Renderer.prototype.setCenter = function (x, y) { + this._center.x = x; + this._center.y = y; + window.requestAnimationFrame(refresh.bind(this)); +}; +/** + * Get Renderer visualization zoom + * @api + * @return {number} + */ +Renderer.prototype.getZoom = function () { + return this._zoom; +}; +/** + * Set Renderer visualization zoom + * @api + * @param {number} zoom + */ +Renderer.prototype.setZoom = function (zoom) { + this._zoom = zoom; + window.requestAnimationFrame(refresh.bind(this)); +}; + +/** + * Removes a dataframe for the renderer. Freeing its resources. + * @api + * @param {*} tile + */ +Renderer.prototype.removeDataframe = function (dataframe) { + this.tiles = this.tiles.filter(t => t !== dataframe); + dataframe.propertyTex.map(tex => gl.deleteTexture(tex)); + gl.deleteTexture(dataframe.texColor); + gl.deleteTexture(dataframe.texWidth); + gl.deleteBuffer(dataframe.vertexBuffer); + gl.deleteBuffer(dataframe.featureIDBuffer); +}; + +/** + * @api + * @description Adds a new dataframe to the renderer. + * + * Performance-intensive. The required allocation and copy of resources will happen synchronously. + * To achieve good performance, avoid multiple calls within the same event, particularly with large dataframes. + * @param {Dataframe} dataframe + */ +Renderer.prototype.addDataframe = function (tile) { + this.tiles.push(tile); + tile.propertyTex = []; + + var points = tile.geom; + const level = 0; + const width = RTT_WIDTH; + tile.numVertex = points.length / 2; + const height = Math.ceil(tile.numVertex / width); + const border = 0; + const srcFormat = gl.RED; + const srcType = gl.FLOAT; + tile.height = height; + tile.propertyID = {}; //Name => PID + tile.propertyCount = 0; + + + for (var k in tile.properties) { + if (tile.properties.hasOwnProperty(k) && tile.properties[k].length > 0) { + const isCategory = !Number.isFinite(tile.properties[k][0]); + const property = tile.properties[k]; + var propertyID = tile.propertyID[k]; + if (propertyID === undefined) { + propertyID = tile.propertyCount; + tile.propertyCount++; + tile.propertyID[k] = propertyID; + } + tile.propertyTex[propertyID] = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tile.propertyTex[propertyID]); + const pixel = new Float32Array(width * height); + for (var i = 0; i < property.length; i++) { + pixel[i] = property[i]; + } + gl.texImage2D(gl.TEXTURE_2D, level, gl.ALPHA, + width, height, 0, gl.ALPHA, srcType, + pixel); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + } + } + + tile.setStyle = function (style) { + schema.checkschemaMatch(style.schema, tile.schema); + this.style = style; + } + tile.style = null; + + tile.vertexBuffer = gl.createBuffer(); + tile.featureIDBuffer = gl.createBuffer(); + + + tile.texColor = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tile.texColor); + gl.texImage2D(gl.TEXTURE_2D, level, gl.RGBA, + width, height, border, gl.RGBA, gl.UNSIGNED_BYTE, + new Uint8Array(4 * width * height).fill(255)); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + + tile.texWidth = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tile.texWidth); + gl.texImage2D(gl.TEXTURE_2D, level, gl.RGBA, + width, height, border, gl.RGBA, gl.UNSIGNED_BYTE, + new Uint8Array(4 * width * height).fill(100)); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + + + + var ids = new Float32Array(points.length); + for (var i = 0; i < points.length; i += 2) { + ids[i + 0] = ((i / 2) % width) / width; + ids[i + 1] = Math.floor((i / 2) / width) / height; + } + + gl.bindBuffer(gl.ARRAY_BUFFER, tile.vertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW); + + gl.bindBuffer(gl.ARRAY_BUFFER, tile.featureIDBuffer); + gl.bufferData(gl.ARRAY_BUFFER, ids, gl.STATIC_DRAW); + + gl.bindBuffer(gl.ARRAY_BUFFER, null); + + window.requestAnimationFrame(refresh.bind(this)); + + return tile; +}; + +/** + * Refresh the canvas by redrawing everything needed. + * Should only be called by requestAnimationFrame + * @param timestamp - timestamp of the animation provided by requestAnimationFrame + */ Renderer.prototype.refresh = refresh; function refresh(timestamp) { // Don't re-render more than once per animation frame @@ -145,186 +372,9 @@ function refresh(timestamp) { }); } -Renderer.prototype.removeTile = function (tile) { - this.tiles = this.tiles.filter(t => t !== tile); - tile.propertyTex.map(tex => gl.deleteTexture(tex)); - gl.deleteTexture(tile.texColor); - gl.deleteTexture(tile.texWidth); - gl.deleteBuffer(tile.vertexBuffer); - gl.deleteBuffer(tile.featureIDBuffer); -} - -Renderer.prototype.addTile = function (tile) { - this.tiles.push(tile); - tile.propertyTex = []; - - var points = tile.geom; - const level = 0; - const width = RTT_WIDTH; - tile.numVertex = points.length / 2; - const height = Math.ceil(tile.numVertex / width); - const border = 0; - const srcFormat = gl.RED; - const srcType = gl.FLOAT; - tile.height = height; - tile.propertyID = {}; //Name => PID - tile.propertyCount = 0; - - - for (var k in tile.properties) { - if (tile.properties.hasOwnProperty(k) && tile.properties[k].length > 0) { - const isCategory = !Number.isFinite(tile.properties[k][0]); - const property = tile.properties[k]; - var propertyID = tile.propertyID[k]; - if (propertyID === undefined) { - propertyID = tile.propertyCount; - tile.propertyCount++; - tile.propertyID[k] = propertyID; - } - tile.propertyTex[propertyID] = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, tile.propertyTex[propertyID]); - const pixel = new Float32Array(width * height); - for (var i = 0; i < property.length; i++) { - pixel[i] = property[i]; - } - gl.texImage2D(gl.TEXTURE_2D, level, gl.ALPHA, - width, height, 0, gl.ALPHA, srcType, - pixel); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); - } - } - - tile.setStyle = function (style) { - scheme.checkSchemeMatch(style.scheme, tile.scheme); - this.style = style; - } - tile.style = null; - - tile.vertexBuffer = gl.createBuffer(); - tile.featureIDBuffer = gl.createBuffer(); - - - tile.texColor = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, tile.texColor); - gl.texImage2D(gl.TEXTURE_2D, level, gl.RGBA, - width, height, border, gl.RGBA, gl.UNSIGNED_BYTE, - new Uint8Array(4 * width * height).fill(255)); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); - - tile.texWidth = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, tile.texWidth); - gl.texImage2D(gl.TEXTURE_2D, level, gl.RGBA, - width, height, border, gl.RGBA, gl.UNSIGNED_BYTE, - new Uint8Array(4 * width * height).fill(100)); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); - - - - var ids = new Float32Array(points.length); - for (var i = 0; i < points.length; i += 2) { - ids[i + 0] = ((i / 2) % width) / width; - ids[i + 1] = Math.floor((i / 2) / width) / height; - } - - gl.bindBuffer(gl.ARRAY_BUFFER, tile.vertexBuffer); - gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW); - - gl.bindBuffer(gl.ARRAY_BUFFER, tile.featureIDBuffer); - gl.bufferData(gl.ARRAY_BUFFER, ids, gl.STATIC_DRAW); - - gl.bindBuffer(gl.ARRAY_BUFFER, null); - - window.requestAnimationFrame(refresh.bind(this)); - - return tile; -} - -/** - * THIS IS A RENDERER. - * @api - * @memberOf renderer - * @constructor - * @param {HTMLElement} canvas - adlfkajdsf - */ -function Renderer(canvas) { - this.canvas = canvas; - this.tiles = []; - if (!gl) { - gl = canvas.getContext('webgl'); - Style.setGL(gl); - var ext = gl.getExtension("OES_texture_float"); - if (!ext) { - console.error("this machine or browser does not support OES_texture_float"); - } - if (!gl) { - console.warn('Unable to initialize WebGL2. Your browser may not support it.'); - return null - } - this._initShaders(); - this._center = { x: 0, y: 0 }; - this._zoom = 1; - } - this.squareBuffer = gl.createBuffer(); - gl.bindBuffer(gl.ARRAY_BUFFER, this.squareBuffer); - var vertices = [ - 10.0, -10.0, - 0.0, 10.0, - -10.0, -10.0, - ]; - gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); -} - /** * Initialize static shaders */ Renderer.prototype._initShaders = function () { this.finalRendererProgram = shaders.renderer.createPointShader(gl); } - - -/** - * @api - * @typedef {object} RPoint - * @property {number} x - * @property {number} y - */ - -/** - * Get Renderer visualization center - * @api - * @return {RPoint} - */ -Renderer.prototype.getCenter = function () { - return { x: this._center.x, y: this._center.y }; -}; -/** - * Set Renderer visualization center - * @api - * @param {number} x - * @param {number} y - */ -Renderer.prototype.setCenter = function (x, y) { - this._center.x = x; - this._center.y = y; - window.requestAnimationFrame(refresh.bind(this)); -}; - -Renderer.prototype.getZoom = function () { - return this._zoom; -} -Renderer.prototype.setZoom = function (zoom) { - this._zoom = zoom; - window.requestAnimationFrame(refresh.bind(this)); -} - -export { Renderer, Style }; -export { Scheme } from './scheme'; \ No newline at end of file diff --git a/src/schema.js b/src/schema.js new file mode 100644 index 000000000..f36224010 --- /dev/null +++ b/src/schema.js @@ -0,0 +1,28 @@ +/** + * @api + * @constructor + * @param {*} propertyNames + * @param {*} propertyTypes + */ +function Schema(propertyNames, propertyTypes) { + if (propertyNames.length != propertyTypes.length) { + throw new Error("propertyNames and propertyTypes lengths mismatch"); + } + propertyNames.map((name, index) => this[name] = propertyTypes[index]); +} + +/** + * + * @param {*} schemaA + * @param {*} schemaB + */ +function checkschemaMatch(schemaA, schemaB) { + if (schemaA && schemaB) { + const equals = Object.keys(schemaA).map(name => schemaA[name] == schemaB[name]).reduce((a, b) => a && b); + if (!equals) { + throw new Error(`schema mismatch: ${JSON.stringify(schemaA)}, ${JSON.stringify(schemaB)}`); + } + } +} + +export {Schema, checkschemaMatch}; \ No newline at end of file diff --git a/src/scheme.js b/src/scheme.js deleted file mode 100644 index 8884de49f..000000000 --- a/src/scheme.js +++ /dev/null @@ -1,16 +0,0 @@ -function Scheme(propertyNames, propertyTypes) { - if (propertyNames.length != propertyTypes.length) { - throw new Error("propertyNames and propertyTypes lengths mismatch"); - } - propertyNames.map((name, index) => this[name] = propertyTypes[index]); -} -function checkSchemeMatch(schemeA, schemeB) { - if (schemeA && schemeB) { - const equals = Object.keys(schemeA).map(name => schemeA[name] == schemeB[name]).reduce((a, b) => a && b); - if (!equals) { - throw new Error(`Scheme mismatch: ${JSON.stringify(schemeA)}, ${JSON.stringify(schemeB)}`); - } - } -} - -export {Scheme, checkSchemeMatch}; \ No newline at end of file diff --git a/src/shaders/index.js b/src/shaders/index.js index 2824c6116..578c3f458 100644 --- a/src/shaders/index.js +++ b/src/shaders/index.js @@ -43,7 +43,7 @@ function GenericStyler(gl, glsl, preface, inline) { let FS = glsl.FS; FS = FS.replace('$PREFACE', preface); FS = FS.replace('$INLINE', inline); - console.log(FS) + //console.log(FS) compileProgram.call(this, gl, VS, FS); this.vertexAttribute = gl.getAttribLocation(this.program, 'vertex'); this.textureLocations = []; diff --git a/src/style/functions.js b/src/style/functions.js index 8a3725bbc..d38c06985 100644 --- a/src/style/functions.js +++ b/src/style/functions.js @@ -1,5 +1,5 @@ import * as cartocolor from 'cartocolor'; -import * as scheme from '../scheme'; +import * as schema from '../schema'; function implicitCast(value) { if (Number.isFinite(value)) { @@ -13,21 +13,21 @@ function setGL(_gl) { } export { Property, Blend, Now, Near, Color, Float, RampColor, FloatMul, FloatDiv, FloatAdd, FloatSub, FloatPow, setGL }; -const schemes = {}; +const schemas = {}; Object.keys(cartocolor).map(name => { const s = cartocolor[name]; var defaultFound = false; for (let i = 20; i >= 0; i--) { if (s[i]) { if (!defaultFound) { - schemes[name.toLowerCase()] = () => s[i]; + schemas[name.toLowerCase()] = () => s[i]; defaultFound = true; } - schemes[`${name.toLowerCase()}_${i}`] = () => s[i]; + schemas[`${name.toLowerCase()}_${i}`] = () => s[i]; } } }); -export { schemes }; +export { schemas }; /* Each styling function should: @@ -53,19 +53,19 @@ export { schemes }; - Heatmaps (renderer should be improved too to accommodate this) */ -function Property(name, scheme) { - return new _Property(name, scheme); +function Property(name, schema) { + return new _Property(name, schema); } -function _Property(name, scheme) { +function _Property(name, schema) { if (typeof name !== 'string' || name == '') { throw new Error(`Invalid property name '${name}'`); } - if (!scheme[name]) { + if (!schema[name]) { throw new Error(`Property name not found`); } this.name = name; this.type = 'float'; - this.scheme = scheme; + this.schema = schema; } _Property.prototype._applyToShaderSource = function (uniformIDMaker, propertyTIDMaker) { return { @@ -275,10 +275,10 @@ function _Blend(a, b, mix) { console.warn(a, b); throw new Error(`Blending cannot be performed between types '${a.type}' and '${b.type}'`); } - if (scheme.checkSchemeMatch(a.scheme, b.scheme)) { - throw new Error('Blend parameters schemes mismatch'); + if (schema.checkschemaMatch(a.schema, b.schema)) { + throw new Error('Blend parameters schemas mismatch'); } - this.scheme = a.scheme; + this.schema = a.schema; this.a = a; this.b = b; this.mix = mix; diff --git a/src/style/index.js b/src/style/index.js index cc1a64ec8..e0b648b5d 100644 --- a/src/style/index.js +++ b/src/style/index.js @@ -48,11 +48,16 @@ Style.prototype._compileWidthShader = function () { this.widthShader = r.shader; } - -function Style(renderer, scheme) { +/** + * @api + * @constructor + * @param {*} renderer + * @param {*} schema + */ +function Style(renderer, schema) { this.renderer = renderer; this.updated = true; - this.scheme = scheme; + this.schema = schema; this._width = functions.Float(5); this._width.parent = this; @@ -67,6 +72,10 @@ function Style(renderer, scheme) { window.requestAnimationFrame(this.renderer.refresh.bind(this.renderer)); }; } +/** + * @api + * @param {*} float + */ Style.prototype.setWidth = function (float) { this._width = float; this.updated = true; @@ -90,7 +99,10 @@ Style.prototype.replaceChild = function (toReplace, replacer) { console.warn('No child found'); } } - +/** + * @api + * @param {*} color + */ Style.prototype.setColor = function (color) { this._color = color; this.updated = true; @@ -101,9 +113,15 @@ Style.prototype.setColor = function (color) { }; color.notify(); } +/** + * @api + */ Style.prototype.getWidth = function () { return this._width; } +/** + * @api + */ Style.prototype.getColor = function () { return this._color; } \ No newline at end of file diff --git a/src/style/parser.js b/src/style/parser.js index 9072f6d1b..3e53fe67c 100644 --- a/src/style/parser.js +++ b/src/style/parser.js @@ -12,57 +12,62 @@ Object.keys(functions).map(name => { lowerCaseFunctions[name.toLocaleLowerCase()] = functions[name]; }); -export function parseStyleExpression(str, scheme) { +/** + * @api + * @param {*} str + * @param {*} schema + */ +export function parseStyleExpression(str, schema) { // jsep addBinaryOp pollutes its module scope, we need to remove the custom operators afterwards jsep.addBinaryOp("^", 10); - const r = parseNode(jsep(str), scheme); + const r = parseNode(jsep(str), schema); jsep.removeBinaryOp("^"); return r; } -function parseNode(node, scheme) { +function parseNode(node, schema) { if (node.type == 'CallExpression') { - const args = node.arguments.map(arg => parseNode(arg, scheme)); + const args = node.arguments.map(arg => parseNode(arg, schema)); const name = node.callee.name.toLowerCase(); if (lowerCaseFunctions[name]) { - return lowerCaseFunctions[name](...args, scheme); + return lowerCaseFunctions[name](...args, schema); } throw new Error(`Invalid function name '${node.callee.name}'`); } else if (node.type == 'Literal') { return node.value; } else if (node.type == 'ArrayExpression') { - return node.elements.map(e => parseNode(e, scheme)); + return node.elements.map(e => parseNode(e, schema)); } else if (node.type == 'BinaryExpression') { - const left = parseNode(node.left, scheme); - const right = parseNode(node.right, scheme); + const left = parseNode(node.left, schema); + const right = parseNode(node.right, schema); switch (node.operator) { case "*": - return functions.FloatMul(left, right, scheme); + return functions.FloatMul(left, right, schema); case "/": - return functions.FloatDiv(left, right, scheme); + return functions.FloatDiv(left, right, schema); case "+": - return functions.FloatAdd(left, right, scheme); + return functions.FloatAdd(left, right, schema); case "-": - return functions.FloatSub(left, right, scheme); + return functions.FloatSub(left, right, schema); case "^": - return functions.FloatPow(left, right, scheme); + return functions.FloatPow(left, right, schema); default: throw new Error(`Invalid binary operator '${node.operator}'`); } } else if (node.type == 'UnaryExpression') { switch (node.operator) { case '-': - return functions.FloatMul(-1, parseNode(node.argument, scheme)); + return functions.FloatMul(-1, parseNode(node.argument, schema)); case '+': - return parseNode(node.argument, scheme); + return parseNode(node.argument, schema); default: throw new Error(`Invalid unary operator '${node.operator}'`); } } else if (node.type == 'Identifier') { if (node.name[0] == '$') { - return functions.Property(node.name.substring(1), scheme); - } else if (functions.schemes[node.name.toLowerCase()]) { - return functions.schemes[node.name.toLowerCase()](); + return functions.Property(node.name.substring(1), schema); + } else if (functions.schemas[node.name.toLowerCase()]) { + return functions.schemas[node.name.toLowerCase()](); } } throw new Error(`Invalid expression '${JSON.stringify(node)}'`);