diff --git a/lib/contourgl.js b/lib/contourgl.js new file mode 100644 index 00000000000..8ecab5b3ae3 --- /dev/null +++ b/lib/contourgl.js @@ -0,0 +1,9 @@ +/** +* Copyright 2012-2016, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + +module.exports = require('../src/traces/contourgl'); diff --git a/package.json b/package.json index eef6fca7c3a..21c66b5d0a9 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,7 @@ "delaunay-triangulate": "^1.1.6", "es6-promise": "^3.0.2", "fast-isnumeric": "^1.1.1", + "gl-contour2d": "^1.0.1", "gl-error2d": "^1.0.0", "gl-error3d": "^1.0.0", "gl-heatmap2d": "^1.0.2", diff --git a/src/traces/contourgl/convert.js b/src/traces/contourgl/convert.js new file mode 100644 index 00000000000..52bb3f25a7d --- /dev/null +++ b/src/traces/contourgl/convert.js @@ -0,0 +1,161 @@ +/** +* Copyright 2012-2016, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + + +'use strict'; + +var createContour2D = require('gl-contour2d'); +var createHeatmap2D = require('gl-heatmap2d'); + +var makeColorMap = require('../contour/make_color_map'); +var str2RGBArray = require('../../lib/str2rgbarray'); + + +function Contour(scene, uid) { + this.scene = scene; + this.uid = uid; + + this.name = ''; + this.hoverinfo = 'all'; + + this.xData = []; + this.yData = []; + this.zData = []; + this.textLabels = []; + + this.idToIndex = []; + this.bounds = [0, 0, 0, 0]; + + this.contourOptions = { + z: new Float32Array(), + x: [], + y: [], + shape: [0, 0], + levels: [0], + levelColors: [0, 0, 0, 1], + lineWidth: 1 + }; + this.contour = createContour2D(scene.glplot, this.contourOptions); + this.contour._trace = this; + + this.heatmapOptions = { + z: new Float32Array(), + x: [], + y: [], + shape: [0, 0], + colorLevels: [0], + colorValues: [0, 0, 0, 0] + }; + this.heatmap = createHeatmap2D(scene.glplot, this.heatmapOptions); + this.heatmap._trace = this; +} + +var proto = Contour.prototype; + +proto.handlePick = function(pickResult) { + var index = pickResult.pointId, + options = this.heatmapOptions, + shape = options.shape; + + return { + trace: this, + dataCoord: pickResult.dataCoord, + traceCoord: [ + options.x[index % shape[0]], + options.y[Math.floor(index / shape[0])], + options.z[index] + ], + textLabel: this.textLabels[index], + name: this.name, + hoverinfo: this.hoverinfo + }; +}; + +proto.update = function(fullTrace, calcTrace) { + var calcPt = calcTrace[0]; + + this.name = fullTrace.name; + this.hoverinfo = fullTrace.hoverinfo; + + // convert z from 2D -> 1D + var z = calcPt.z, + rowLen = z[0].length, + colLen = z.length; + + this.contourOptions.z = flattenZ(z, rowLen, colLen); + this.heatmapOptions.z = [].concat.apply([], z); + + this.contourOptions.shape = this.heatmapOptions.shape = [rowLen, colLen]; + + this.contourOptions.x = this.heatmapOptions.x = calcPt.x; + this.contourOptions.y = this.heatmapOptions.y = calcPt.y; + + var colorOptions = convertColorscale(fullTrace); + this.contourOptions.levels = colorOptions.levels; + this.contourOptions.levelColors = colorOptions.levelColors; + + // convert text from 2D -> 1D + this.textLabels = [].concat.apply([], fullTrace.text); + + this.contour.update(this.contourOptions); + this.heatmap.update(this.heatmapOptions); +}; + +proto.dispose = function() { + this.contour.dispose(); + this.heatmap.dispose(); +}; + +function flattenZ(zIn, rowLen, colLen) { + var zOut = new Float32Array(rowLen * colLen); + var pt = 0; + + for(var i = 0; i < rowLen; i++) { + for(var j = 0; j < colLen; j++) { + zOut[pt++] = zIn[j][i]; + } + } + + return zOut; +} + +function convertColorscale(fullTrace) { + var contours = fullTrace.contours, + start = contours.start, + end = contours.end, + cs = contours.size || 1; + + var colorMap = makeColorMap(fullTrace); + + var N = Math.floor((end - start) / cs) + 1, + levels = new Array(N), + levelColors = new Array(4 * N); + + for(var i = 0; i < N; i++) { + var level = levels[i] = start + cs * (i); + var color = str2RGBArray(colorMap(level)); + + for(var j = 0; j < 4; j++) { + levelColors[(4 * i) + j] = color[j]; + } + } + + return { + levels: levels, + levelColors: levelColors + }; +} + +function createContour(scene, fullTrace, calcTrace) { + var plot = new Contour(scene, fullTrace.uid); + plot.update(fullTrace, calcTrace); + + return plot; +} + +module.exports = createContour; diff --git a/src/traces/contourgl/index.js b/src/traces/contourgl/index.js new file mode 100644 index 00000000000..af1309dc886 --- /dev/null +++ b/src/traces/contourgl/index.js @@ -0,0 +1,31 @@ +/** +* Copyright 2012-2016, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + + +'use strict'; + +var ContourGl = {}; + +ContourGl.attributes = require('../contour/attributes'); +ContourGl.supplyDefaults = require('../contour/defaults'); +ContourGl.colorbar = require('../contour/colorbar'); + +ContourGl.calc = require('../contour/calc'); +ContourGl.plot = require('./convert'); + +ContourGl.moduleType = 'trace'; +ContourGl.name = 'contourgl'; +ContourGl.basePlotModule = require('../../plots/gl2d'); +ContourGl.categories = ['gl2d', '2dMap']; +ContourGl.meta = { + description: [ + 'WebGL contour (beta)' + ].join(' ') +}; + +module.exports = ContourGl;