/** * The DataTableOverlayEx shows a table of labels and numbers */ var DataTableOverlayEx = function(r) { if ( !(this instanceof arguments.callee) ) { throw new Error("Constructor called as a function") } if (!r.Table || r.Table.length < 1) { throw new Error("Expected 'Table' property") } // Add resources this.fontMatRes_ = H3D.addResource(H3D.ResTypes.Material, "Materials/Font.material.xml", 0); this.panelMatRes_ = H3D.addResource(H3D.ResTypes.Material, "Materials/Panel.material.xml", 0); H3D.loadResourcesFromDisk(); // Variable to hold the channels that are displayed in the table this.channels = { names : [], values : [], } // Function to initialize cell properties from cell definition in boc file var mergeCellProperties = function(channels, p, r) { if (r.nDecimals !== undefined) { p.nDecimals = r.nDecimals } if (r.ValuePrefix) { p.valuePrefix = r.ValuePrefix } if (r.ValuePostfix) { p.valuePostfix = r.ValuePostfix } var iChannel; var iColorChannel; if (r.Channel !== undefined) { var i = channels.names.indexOf(r.Channel); if (i < 0) { i = channels.names.push(r.Channel) - 1 } p.fText = function() { return p.valuePrefix + channels.values[i].toFixed(p.nDecimals) + p.valuePostfix } iChannel = i; iColorChannel = i; } if (r.Label !== undefined) { if (iChannel === undefined) { p.fText = function() { return r.Label } } else { // If both Label and Channel are defined, we assume that the label is a javascript // expression depending on x var fText = eval("(function(x) { return " + r.Label + "; })"); p.fText = function() { return p.valuePrefix + fText(channels.values[iChannel]) + p.valuePostfix; } } } if (r.ColorChannel) { iColorChannel = channels.names.indexOf(r.ColorChannel); if (iColorChannel < 0) { iColorChannel = channels.names.push(r.ColorChannel) - 1 } } if (r.Alignment !== undefined) { p.alignment = H3D.TextAlignH[r.Alignment] } if (r.FontSize !== undefined) { p.fontSize = r.FontSize } if (r.FontColor !== undefined) { if (iColorChannel === undefined) { var fontColor = Color.fromConfig(r.FontColor) p.fFontColor = function() { return fontColor } } else { var fFontColor = Color.fFromConfig(r.FontColor) p.fFontColor = function() { return fFontColor(channels.values[iColorChannel]) } } } if (r.BackgroundColorFunc !== undefined) { p.fBkgndColor = function() { return eval(""+r.BackgroundColorFunc+"("+channels.values[iColorChannel]+")"); } } else if (r.BackgroundColor !== undefined) { if (iColorChannel === undefined) { var bkgndColor = Color.fromConfig(r.BackgroundColor) p.fBkgndColor = function() { return bkgndColor } } else { var fBkgndColor = Color.fFromConfig(r.BackgroundColor) p.fBkgndColor = function() { return fBkgndColor(channels.values[iColorChannel]) } } } } // Prepare the default properties for a cell var defaults = { nDecimals: 2, valuePrefix: "", valuePostfix: "", alignment: H3D.TextAlignH.Left, fontSize: 0.03, fFontColor: function() { return [1, 1, 1, 1] }, precision: 2, fBkgndColor: function() { return [0.2, 0.2, 0.2, 0.5] }, } mergeCellProperties(this.channels, defaults, r.Defaults) // Normalize column width var nCol if (r.RelWidthColumns) { nCol = r.RelWidthColumns.length var sum = r.RelWidthColumns.reduce(function(total, num) { return total + num }, 0) this.cRelW_ = r.RelWidthColumns.map(function(w) { return w / sum }) } else { nCol = r.Table.reduce(function(nCol, row) { return Math.max(nCol, row.length) }, 0) this.cRelW_ = new Array(nCol); for (var i = 0; i < nCol; i++) this.cRelW_[i] = 1/nCol; } // Initialize the table cells this.table_ = [] for (var iRow = 0; iRow < r.Table.length; iRow++) { if (iRow > 0 && nCol < r.Table[iRow].length) { throw new Error("Inconsistent length in 'Table' row " + iRow) } this.table_[iRow] = [] for (var iCol = 0; iCol < r.Table[iRow].length; iCol++) { this.table_[iRow][iCol] = clone(defaults) mergeCellProperties(this.channels, this.table_[iRow][iCol], r.Table[iRow][iCol]) } } // Call parent constructor Overlay.call(this, r.Layout); }; DataTableOverlayEx.prototype = Object.create(Overlay.prototype) DataTableOverlayEx.prototype.constructor = DataBoxOverlay DataTableOverlayEx.prototype.remove = function() { this.fontMatRes_.remove(); this.panelMatRes_.remove(); } DataTableOverlayEx.prototype.onResize = function() { var y = this.y_ for (var iRow = 0; iRow < this.table_.length; iRow++) { // Get row height var h = 0 for (var iCol = 0; iCol < this.table_[iRow].length; iCol++) { h = Math.max(h, this.table_[iRow][iCol].fontSize) } // Update the cell properties var x = this.x_ for (var iCol = 0; iCol < this.table_[iRow].length; iCol++) { var w = this.cRelW_[iCol] * this.width_ var cell = this.table_[iRow][iCol] // Compute the 4 corners of the quad [[x, y, u, v]...] cell.verts = [x, y , 0.0, 0.0, x, y + h, 0.0, 1.0, x + w, y + h, 1.0, 1.0, x + w, y , 1.0, 0.0] switch (cell.alignment) { case H3D.TextAlignH.Left: cell.xText = x + 0.2*cell.fontSize break case H3D.TextAlignH.Center: cell.xText = x + w/2 break case H3D.TextAlignH.Right: cell.xText = x + w - 0.2*cell.fontSize break } // Center align vertically cell.yText = y + (h - cell.fontSize) / 2 // Next column position x += w } y += h } } DataTableOverlayEx.prototype.update = function(time) { this.channels.values = OutputBuffer.values(time, this.channels.names) } DataTableOverlayEx.prototype.show = function() { for (var iRow = 0; iRow < this.table_.length; iRow++) { for (var iCol = 0; iCol < this.table_[iRow].length; iCol++) { var cell = this.table_[iRow][iCol]; if (cell !== undefined) { var c = cell.fBkgndColor() H3D.showOverlays(cell.verts, c[0], c[1], c[2], c[3], this.panelMatRes_); if (cell.fText !== undefined) { var c = cell.fFontColor() H3D.showText(cell.fText(), cell.xText, cell.yText, cell.fontSize, cell.alignment, c[0], c[1],c[2], this.fontMatRes_); } } } } } Overlay.types["DataTableEx"] = DataTableOverlayEx