@thewtex/vtk.js-esm
Version:
Visualization Toolkit for the Web
740 lines (609 loc) • 29.9 kB
JavaScript
import _defineProperty from '@babel/runtime/helpers/defineProperty';
import _toConsumableArray from '@babel/runtime/helpers/toConsumableArray';
import { J as nearestPowerOfTwo } from '../../Common/Core/Math/index.js';
import macro from '../../macro.js';
import vtkActor from './Actor.js';
import vtkDataArray from '../../Common/Core/DataArray.js';
import vtkScalarsToColors from '../../Common/Core/ScalarsToColors.js';
import vtkMapper from './Mapper.js';
import vtkPixelSpaceCallbackMapper from './PixelSpaceCallbackMapper.js';
import vtkPolyData from '../../Common/DataModel/PolyData.js';
import vtkTexture from './Texture.js';
import { l as linear } from '../../vendor/d3-scale/src/linear.js';
import { b as scale, j as add, a as subtract, t as transformMat4 } from '../../vendor/gl-matrix/esm/vec3.js';
import { j as transpose, g as invert } from '../../vendor/gl-matrix/esm/mat4.js';
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
var VectorMode = vtkScalarsToColors.VectorMode; // ----------------------------------------------------------------------------
// vtkScalarBarActor
//
// Note log scales are currently not supported
// ----------------------------------------------------------------------------
// some shared temp variables to reduce heap allocs
var ptv3 = new Float64Array(3);
var pt2v3 = new Float64Array(3);
var tmpv3 = new Float64Array(3);
var tmp2v3 = new Float64Array(3);
var xDir = new Float64Array(3);
var yDir = new Float64Array(3);
var invmat = new Float64Array(16);
function applyTextStyle(ctx, style) {
ctx.strokeStyle = style.strokeColor;
ctx.lineWidth = style.strokeSize;
ctx.fillStyle = style.fontColor;
ctx.font = "".concat(style.fontStyle, " ").concat(style.fontSize, "px ").concat(style.fontFamily);
}
function vtkScalarBarActor(publicAPI, model) {
// Set our className
model.classHierarchy.push('vtkScalarBarActor'); // compute good values to use based on window size etc
// a bunch of heuristics here with hand tuned constants
// These values worked for me but really this method
// could be redically changed. The basic gist is
// 1) compute a resonable font size
// 2) render the text atlas using those font sizes
// 3) pick horizontal or vertical bsed on window size
// 4) based on the size of the title and tick labels rendered
// compute the box size and position such that
// the text will all fit nicely and the bar will be a resonable size
// 5) compute the bar segments based on the above settings
publicAPI.computeAndApplyAutomatedSettings = function () {
// we don't do a linear scale, the proportions for
// a 700 pixel window differ from a 1400
var xAxisAdjust = Math.pow(model.lastSize[0] / 700, 0.8);
var yAxisAdjust = Math.pow(model.lastSize[1] / 700, 0.8);
var minAdjust = Math.min(xAxisAdjust, yAxisAdjust); // compute a reasonable font size first
model.axisTextStyle.fontSize = Math.max(24 * minAdjust, 12);
if (model.lastAspectRatio > 1.0) {
model.tickTextStyle.fontSize = Math.max(20 * minAdjust, 10);
} else {
model.tickTextStyle.fontSize = Math.max(16 * minAdjust, 10);
} // rebuild the text atlas
var textSizes = publicAPI.updateTextureAtlas(); // now compute the boxSize and pixel offsets, different algorithm
// for horizonal versus vertical
model.topTitle = false; // if vertical
if (model.lastAspectRatio > 1.0) {
model.tickLabelPixelOffset = 0.4 * model.tickTextStyle.fontSize;
var tickWidth = 2.0 * (textSizes.tickWidth + model.tickLabelPixelOffset) / model.lastSize[0];
model.axisTitlePixelOffset = 0.8 * model.axisTextStyle.fontSize; // width required if the title is vertical
var titleWidth = 2.0 * (textSizes.titleHeight + model.axisTitlePixelOffset) / model.lastSize[0]; // if the title will fit within the width of the bar then that looks
// nicer to put it at the top (model.topTitle), otherwise rotate it
// and place it sideways
if (tickWidth + 0.4 * titleWidth > 2.0 * textSizes.titleWidth / model.lastSize[0]) {
model.topTitle = true;
model.boxSize[0] = tickWidth + 0.4 * titleWidth;
model.boxPosition = [0.98 - model.boxSize[0], -0.92];
} else {
model.boxSize[0] = tickWidth + 1.4 * titleWidth;
model.boxPosition = [0.99 - model.boxSize[0], -0.92];
}
model.boxSize[1] = Math.max(1.2, Math.min(1.84 / yAxisAdjust, 1.84));
} else {
// horizontal
model.axisTitlePixelOffset = 2.0 * model.tickTextStyle.fontSize;
model.tickLabelPixelOffset = 0.5 * model.tickTextStyle.fontSize;
var tickHeight = 2.0 * (textSizes.tickHeight + model.tickLabelPixelOffset) / model.lastSize[1];
var titleHeight = 2.0 * (textSizes.titleHeight + model.axisTitlePixelOffset) / model.lastSize[1];
var _tickWidth = 2.0 * textSizes.tickWidth / model.lastSize[0];
model.boxSize[0] = Math.min(1.9, Math.max(1.4, 1.4 * _tickWidth * (model.ticks.length + 3)));
model.boxSize[1] = tickHeight + titleHeight;
model.boxPosition = [-0.5 * model.boxSize[0], -0.97];
} // recomute bar segments based on positioning
publicAPI.recomputeBarSegments(textSizes);
}; // main method to rebuild the scalarBar when something has changed
// tracks modified times
publicAPI.update = function () {
if (!model.scalarsToColors || !model.visibility) {
return;
} // make sure the lut is assigned to our mapper
model.barMapper.setLookupTable(model.scalarsToColors); // did something significant change? If so rebuild a lot of things
if (model.forceUpdate || Math.max(model.scalarsToColors.getMTime(), publicAPI.getMTime()) > model.lastRebuildTime.getMTime()) {
var range = model.scalarsToColors.getMappingRange();
model.lastTickBounds = _toConsumableArray(range);
model.barMapper.setScalarRange(model.lastTickBounds); // compute tick marks for axes (update for log scale)
var scale = linear().domain([model.lastTickBounds[0], model.lastTickBounds[1]]);
model.ticks = scale.ticks(5);
var format = scale.tickFormat(5);
model.tickStrings = model.ticks.map(format);
if (model.automated) {
publicAPI.computeAndApplyAutomatedSettings();
} else {
// rebuild the texture only when force or changed bounds, face
// visibility changes do to change the atlas
var textSizes = publicAPI.updateTextureAtlas(); // recompute bar segments based on positioning
publicAPI.recomputeBarSegments(textSizes);
}
model.forceViewUpdate = true;
model.lastRebuildTime.modified();
model.forceUpdate = false;
} // compute bounds for label quads whenever the camera changes or forced
// the polydata mapper could be modified to accept NDC coords then this
// would be called far less often
if (model.forceViewUpdate || model.camera.getMTime() > model.lastRedrawTime.getMTime()) {
publicAPI.updatePolyDataForLabels();
publicAPI.updatePolyDataForBarSegments();
model.lastRedrawTime.modified();
model.forceViewUpdate = false;
}
}; // The text atlas is an image and as loading images is async we call this when
// the promise resolves. The old texture is used until then
publicAPI.completedImage = function (doUpdate) {
if (model.nextImage && model.nextImage.complete) {
model.tmTexture.setImage(model.nextImage);
model.nextImage = null;
model._tmAtlas = model._nextAtlas;
model._nextAtlas = null;
if (doUpdate) {
model.forceViewUpdate = true;
publicAPI.update();
}
}
}; // create the texture map atlas that contains the rendering of
// all the text strings. Only needs to be called when the text strings
// have changed (labels and ticks)
publicAPI.updateTextureAtlas = function () {
// set the text properties
model.tmContext.textBaseline = 'bottom';
model.tmContext.textAlign = 'left'; // return some factors about the text atlas
var results = {}; // first the axislabel
var newTmAtlas = new Map();
var maxWidth = 0;
var totalHeight = 1; // start one pixel in so we have a border
applyTextStyle(model.tmContext, model.axisTextStyle);
var metrics = model.tmContext.measureText(model.axisLabel);
var entry = {
height: metrics.actualBoundingBoxAscent + 2,
startingHeight: totalHeight,
width: metrics.width + 2,
textStyle: model.axisTextStyle
};
newTmAtlas.set(model.axisLabel, entry);
totalHeight += entry.height;
maxWidth = entry.width;
results.titleWidth = entry.width;
results.titleHeight = entry.height; // and the ticks, NaN Below and Above
results.tickWidth = 0;
results.tickHeight = 0;
applyTextStyle(model.tmContext, model.tickTextStyle);
var strings = [].concat(_toConsumableArray(model.tickStrings), ['NaN', 'Below', 'Above']);
for (var t = 0; t < strings.length; t++) {
if (!newTmAtlas.has(strings[t])) {
metrics = model.tmContext.measureText(strings[t]);
entry = {
height: metrics.actualBoundingBoxAscent + 2,
startingHeight: totalHeight,
width: metrics.width + 2,
textStyle: model.tickTextStyle
};
newTmAtlas.set(strings[t], entry);
totalHeight += entry.height;
if (maxWidth < entry.width) {
maxWidth = entry.width;
}
if (results.tickWidth < entry.width) {
results.tickWidth = entry.width;
}
if (results.tickHeight < entry.height) {
results.tickHeight = entry.height;
}
}
} // always use power of two to avoid interpolation
// in cases where PO2 is required
maxWidth = nearestPowerOfTwo(maxWidth);
totalHeight = nearestPowerOfTwo(totalHeight); // set the tcoord values
newTmAtlas.forEach(function (value) {
value.tcoords = [0.0, (totalHeight - value.startingHeight - value.height) / totalHeight, value.width / maxWidth, (totalHeight - value.startingHeight - value.height) / totalHeight, value.width / maxWidth, (totalHeight - value.startingHeight) / totalHeight, 0.0, (totalHeight - value.startingHeight) / totalHeight];
}); // make sure we have power of two dimensions
model.tmCanvas.width = maxWidth;
model.tmCanvas.height = totalHeight;
model.tmContext.textBaseline = 'bottom';
model.tmContext.textAlign = 'left';
model.tmContext.clearRect(0, 0, maxWidth, totalHeight); // draw the text onto the texture
newTmAtlas.forEach(function (value, key) {
applyTextStyle(model.tmContext, value.textStyle);
model.tmContext.fillText(key, 1, value.startingHeight + value.height - 1);
});
var image = new Image();
image.src = model.tmCanvas.toDataURL('image/png');
model.nextImage = image;
model._nextAtlas = newTmAtlas;
if (image.complete) {
publicAPI.completedImage(false);
} else {
image.addEventListener('load', function () {
publicAPI.completedImage(true);
});
}
return results;
};
publicAPI.computeBarSize = function (textSizes) {
// compute orientation
model.vertical = model.boxSize[1] > model.boxSize[0];
var tickHeight = 2.0 * textSizes.tickHeight / model.lastSize[1];
var segSize = [1, 1]; // horizontal and vertical have different astetics so adjust based on
// orientation
if (model.vertical) {
var tickWidth = 2.0 * (textSizes.tickWidth + model.tickLabelPixelOffset) / model.lastSize[0];
if (model.topTitle) {
var titleHeight = 2.0 * (textSizes.titleHeight + model.axisTitlePixelOffset) / model.lastSize[1];
model.barSize[0] = model.boxSize[0] - tickWidth;
model.barSize[1] = model.boxSize[1] - titleHeight;
} else {
// rotated title so width is based off height
var titleWidth = 2.0 * (textSizes.titleHeight + model.axisTitlePixelOffset) / model.lastSize[0];
model.barSize[0] = model.boxSize[0] - titleWidth - tickWidth;
model.barSize[1] = model.boxSize[1];
}
model.barPosition[0] = model.boxPosition[0] + tickWidth;
model.barPosition[1] = model.boxPosition[1];
segSize[1] = tickHeight;
} else {
var _tickWidth2 = (2.0 * textSizes.tickWidth - 8) / model.lastSize[0];
var _titleHeight = 2.0 * (textSizes.titleHeight + model.axisTitlePixelOffset) / model.lastSize[1];
model.barSize[0] = model.boxSize[0];
model.barPosition[0] = model.boxPosition[0];
model.barSize[1] = model.boxSize[1] - _titleHeight - tickHeight;
model.barPosition[1] = model.boxPosition[1];
segSize[0] = _tickWidth2;
}
return segSize;
}; // based on all the settins compute a barSegments array
// containing the segments opf the scalar bar
// each segment contains
// corners[4][2]
// title - e.g. NaN, Above, ticks
// scalars - the normalized scalars values to use for that segment
//
// Note that the bar consumes the space in the box that remains after
// leaving room for the text labels
publicAPI.recomputeBarSegments = function (textSizes) {
// first compute the barSize/Position
var segSize = publicAPI.computeBarSize(textSizes);
model.barSegments = [];
var startPos = [0.0, 0.0]; // horizontal and vertical have different astetics so adjust based on
// orientation
var barAxis = model.vertical ? 1 : 0;
var segSpace = model.vertical ? 0.01 : 0.02;
function pushSeg(title, scalars) {
model.barSegments.push({
corners: [[].concat(startPos), [startPos[0] + segSize[0], startPos[1]], [startPos[0] + segSize[0], startPos[1] + segSize[1]], [startPos[0], startPos[1] + segSize[1]]],
scalars: scalars,
title: title
});
startPos[barAxis] += segSize[barAxis] + segSpace;
}
if (typeof model.scalarsToColors.getNanColor === 'function') {
pushSeg('NaN', [NaN, NaN, NaN, NaN]);
}
if (typeof model.scalarsToColors.getUseBelowRangeColor === 'function' && model.scalarsToColors.getUseBelowRangeColor()) {
pushSeg('Below', [-0.1, -0.1, -0.1, -0.1]);
}
var haveAbove = typeof model.scalarsToColors.getUseAboveRangeColor === 'function' && model.scalarsToColors.getUseAboveRangeColor(); // extra space around the ticks section
startPos[barAxis] += segSpace;
var oldSegSize = segSize[barAxis];
segSize[barAxis] = haveAbove ? 1.0 - 2.0 * segSpace - segSize[barAxis] - startPos[barAxis] : 1.0 - segSpace - startPos[barAxis];
pushSeg('ticks', model.vertical ? [0, 0, 0.995, 0.995] : [0, 0.995, 0.995, 0]);
if (haveAbove) {
segSize[barAxis] = oldSegSize;
startPos[barAxis] += segSpace;
pushSeg('Above', [1.1, 1.1, 1.1, 1.1]);
}
}; // called by updatePolyDataForLabels
// modifies class constants ptv3, tmpv3
publicAPI.createPolyDataForOneLabel = function (text, pos, xdir, ydir, dir, offset, results) {
var value = model._tmAtlas.get(text);
if (!value) {
return;
} // have to find the four corners of the texture polygon for this label
// convert anchor point to View Coords
var ptIdx = results.ptIdx;
var cellIdx = results.cellIdx;
ptv3[0] = pos[0];
ptv3[1] = pos[1];
ptv3[2] = pos[2]; // horizontal left, right, or middle alignment based on dir[0]
if (dir[0] < -0.5) {
scale(tmpv3, xdir, dir[0] * offset - value.width);
} else if (dir[0] > 0.5) {
scale(tmpv3, xdir, dir[0] * offset);
} else {
scale(tmpv3, xdir, dir[0] * offset - value.width / 2.0);
}
add(ptv3, ptv3, tmpv3);
scale(tmpv3, ydir, dir[1] * offset - value.height / 2.0);
add(ptv3, ptv3, tmpv3);
results.points[ptIdx * 3] = ptv3[0];
results.points[ptIdx * 3 + 1] = ptv3[1];
results.points[ptIdx * 3 + 2] = ptv3[2];
results.tcoords[ptIdx * 2] = value.tcoords[0];
results.tcoords[ptIdx * 2 + 1] = value.tcoords[1];
ptIdx++;
scale(tmpv3, xdir, value.width);
add(ptv3, ptv3, tmpv3);
results.points[ptIdx * 3] = ptv3[0];
results.points[ptIdx * 3 + 1] = ptv3[1];
results.points[ptIdx * 3 + 2] = ptv3[2];
results.tcoords[ptIdx * 2] = value.tcoords[2];
results.tcoords[ptIdx * 2 + 1] = value.tcoords[3];
ptIdx++;
scale(tmpv3, ydir, value.height);
add(ptv3, ptv3, tmpv3);
results.points[ptIdx * 3] = ptv3[0];
results.points[ptIdx * 3 + 1] = ptv3[1];
results.points[ptIdx * 3 + 2] = ptv3[2];
results.tcoords[ptIdx * 2] = value.tcoords[4];
results.tcoords[ptIdx * 2 + 1] = value.tcoords[5];
ptIdx++;
scale(tmpv3, xdir, value.width);
subtract(ptv3, ptv3, tmpv3);
results.points[ptIdx * 3] = ptv3[0];
results.points[ptIdx * 3 + 1] = ptv3[1];
results.points[ptIdx * 3 + 2] = ptv3[2];
results.tcoords[ptIdx * 2] = value.tcoords[6];
results.tcoords[ptIdx * 2 + 1] = value.tcoords[7];
ptIdx++; // add the two triangles to represent the quad
results.polys[cellIdx * 4] = 3;
results.polys[cellIdx * 4 + 1] = ptIdx - 4;
results.polys[cellIdx * 4 + 2] = ptIdx - 3;
results.polys[cellIdx * 4 + 3] = ptIdx - 2;
cellIdx++;
results.polys[cellIdx * 4] = 3;
results.polys[cellIdx * 4 + 1] = ptIdx - 4;
results.polys[cellIdx * 4 + 2] = ptIdx - 2;
results.polys[cellIdx * 4 + 3] = ptIdx - 1;
results.ptIdx += 4;
results.cellIdx += 2;
}; // update the polydata associated with drawing the text labels
// specifically the quads used for each label and their associated tcoords
// etc. This changes every time the camera viewpoint changes
publicAPI.updatePolyDataForLabels = function () {
var cmat = model.camera.getCompositeProjectionMatrix(model.lastAspectRatio, -1, 1);
transpose(cmat, cmat);
invert(invmat, cmat);
var size = model.lastSize; // compute pixel to distance factors
tmpv3[0] = 0.0;
tmpv3[1] = 0.0;
tmpv3[2] = -0.99; // near plane
transformMat4(ptv3, tmpv3, invmat); // moving 0.1 in NDC
tmpv3[0] += 0.1;
transformMat4(pt2v3, tmpv3, invmat); // results in WC move of
subtract(xDir, pt2v3, ptv3);
tmpv3[0] -= 0.1;
tmpv3[1] += 0.1;
transformMat4(pt2v3, tmpv3, invmat); // results in WC move of
subtract(yDir, pt2v3, ptv3);
for (var i = 0; i < 3; i++) {
xDir[i] /= 0.5 * 0.1 * size[0];
yDir[i] /= 0.5 * 0.1 * size[1];
} // update the polydata
var numLabels = model.tickStrings.length + model.barSegments.length;
var numPts = numLabels * 4;
var numTris = numLabels * 2;
var points = new Float64Array(numPts * 3);
var polys = new Uint16Array(numTris * 4);
var tcoords = new Float32Array(numPts * 2);
var results = {
ptIdx: 0,
cellIdx: 0,
polys: polys,
points: points,
tcoords: tcoords
}; // compute the direction vector, to make the code general we place text
var offsetAxis = model.vertical ? 0 : 1;
var spacedAxis = model.vertical ? 1 : 0; // draw the title
var dir = [0, 1];
if (model.vertical) {
if (model.topTitle) {
tmpv3[0] = model.boxPosition[0] + 0.5 * model.boxSize[0];
tmpv3[1] = model.barPosition[1] + model.barSize[1];
transformMat4(ptv3, tmpv3, invmat); // write the axis label
publicAPI.createPolyDataForOneLabel(model.axisLabel, ptv3, xDir, yDir, [0, 1], model.axisTitlePixelOffset, results);
} else {
tmpv3[0] = model.barPosition[0] + model.barSize[0];
tmpv3[1] = model.barPosition[1] + 0.5 * model.barSize[1];
transformMat4(ptv3, tmpv3, invmat); // write the axis label
scale(xDir, xDir, -1);
publicAPI.createPolyDataForOneLabel(model.axisLabel, ptv3, yDir, xDir, [0, -1], model.axisTitlePixelOffset, results);
scale(xDir, xDir, -1);
}
dir = [-1, 0];
} else {
tmpv3[0] = model.barPosition[0] + 0.5 * model.barSize[0];
tmpv3[1] = model.barPosition[1] + model.barSize[1];
transformMat4(ptv3, tmpv3, invmat);
publicAPI.createPolyDataForOneLabel(model.axisLabel, ptv3, xDir, yDir, dir, model.axisTitlePixelOffset, results);
}
tmp2v3[2] = -0.99; // near plane
tmp2v3[offsetAxis] = model.barPosition[offsetAxis] + (0.5 * dir[offsetAxis] + 0.5) * model.barSize[offsetAxis];
tmp2v3[spacedAxis] = model.barPosition[spacedAxis] + model.barSize[spacedAxis] * 0.5; // draw bar segment labels
var tickSeg = null;
for (var _i = 0; _i < model.barSegments.length; _i++) {
var seg = model.barSegments[_i];
if (seg.title === 'ticks') {
// handle ticks below
tickSeg = seg;
} else {
tmp2v3[spacedAxis] = model.barPosition[spacedAxis] + 0.5 * model.barSize[spacedAxis] * (seg.corners[2][spacedAxis] + seg.corners[0][spacedAxis]);
transformMat4(ptv3, tmp2v3, invmat);
publicAPI.createPolyDataForOneLabel(seg.title, ptv3, xDir, yDir, dir, model.tickLabelPixelOffset, results);
}
} // write the tick labels
var tickSegmentStart = model.barPosition[spacedAxis] + model.barSize[spacedAxis] * tickSeg.corners[0][spacedAxis];
var tickSegmentSize = model.barSize[spacedAxis] * (tickSeg.corners[2][spacedAxis] - tickSeg.corners[0][spacedAxis]);
for (var t = 0; t < model.ticks.length; t++) {
var tickPos = (model.ticks[t] - model.lastTickBounds[0]) / (model.lastTickBounds[1] - model.lastTickBounds[0]);
tmp2v3[spacedAxis] = tickSegmentStart + tickSegmentSize * tickPos;
transformMat4(ptv3, tmp2v3, invmat);
publicAPI.createPolyDataForOneLabel(model.tickStrings[t], ptv3, xDir, yDir, dir, model.tickLabelPixelOffset, results);
}
var tcoordDA = vtkDataArray.newInstance({
numberOfComponents: 2,
values: tcoords,
name: 'TextureCoordinates'
});
model.tmPolyData.getPointData().setTCoords(tcoordDA);
model.tmPolyData.getPoints().setData(points, 3);
model.tmPolyData.getPoints().modified();
model.tmPolyData.getPolys().setData(polys, 1);
model.tmPolyData.getPolys().modified();
model.tmPolyData.modified();
};
publicAPI.updatePolyDataForBarSegments = function () {
var cmat = model.camera.getCompositeProjectionMatrix(model.lastAspectRatio, -1, 1);
transpose(cmat, cmat);
invert(invmat, cmat);
var haveExtraColors = typeof model.scalarsToColors.getNanColor === 'function' && typeof model.scalarsToColors.getAboveRangeColor === 'function' && typeof model.scalarsToColors.getBelowRangeColor === 'function';
var numPts = 4 + (haveExtraColors ? 12 : 0);
var numQuads = numPts; // handle vector component mode
var numComps = 1;
if (model.scalarsToColors.getVectorMode() === VectorMode.COMPONENT) {
numComps = model.scalarsToColors.getVectorComponent() + 1;
} // create the colored bars
var points = new Float64Array(numPts * 3);
var cells = new Uint16Array(numQuads * 5);
var scalars = new Float32Array(numPts * numComps);
var ptIdx = 0;
var cellIdx = 0;
for (var i = 0; i < model.barSegments.length; i++) {
var seg = model.barSegments[i];
tmp2v3[1] = model.barPosition[1] + model.barSize[1] * 0.5;
tmp2v3[2] = -0.99; // near plane
for (var e = 0; e < 4; e++) {
tmp2v3[0] = model.barPosition[0] + seg.corners[e][0] * model.barSize[0];
tmp2v3[1] = model.barPosition[1] + seg.corners[e][1] * model.barSize[1];
transformMat4(ptv3, tmp2v3, invmat);
points[ptIdx * 3] = ptv3[0];
points[ptIdx * 3 + 1] = ptv3[1];
points[ptIdx * 3 + 2] = ptv3[2];
for (var nc = 0; nc < numComps; nc++) {
scalars[ptIdx * numComps + nc] = model.lastTickBounds[0] + seg.scalars[e] * (model.lastTickBounds[1] - model.lastTickBounds[0]);
}
ptIdx++;
}
cells[cellIdx * 5] = 4;
cells[cellIdx * 5 + 1] = ptIdx - 4;
cells[cellIdx * 5 + 2] = ptIdx - 3;
cells[cellIdx * 5 + 3] = ptIdx - 2;
cells[cellIdx * 5 + 4] = ptIdx - 1;
cellIdx++;
}
var scalarsDA = vtkDataArray.newInstance({
numberOfComponents: numComps,
values: scalars,
name: 'Scalars'
});
model.polyData.getPointData().setScalars(scalarsDA);
model.polyData.getPoints().setData(points, 3);
model.polyData.getPoints().modified();
model.polyData.getPolys().setData(cells, 1);
model.polyData.getPolys().modified();
model.polyData.modified();
};
publicAPI.getActors = function () {
return [model.barActor, model.tmActor];
};
publicAPI.getNestedProps = function () {
return publicAPI.getActors();
};
publicAPI.setTickTextStyle = function (tickStyle) {
model.tickTextStyle = _objectSpread(_objectSpread({}, model.tickTextStyle), tickStyle);
publicAPI.modified();
};
publicAPI.setAxisTextStyle = function (axisStyle) {
model.axisTextStyle = _objectSpread(_objectSpread({}, model.axisTextStyle), axisStyle);
publicAPI.modified();
};
publicAPI.setVisibility = macro.chain(publicAPI.setVisibility, model.barActor.setVisibility, model.tmActor.setVisibility);
} // ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------
function defaultValues(initialValues) {
return _objectSpread({
automated: true,
axisLabel: 'Scalar Value',
barPosition: [0, 0],
barSize: [0, 0],
boxPosition: [0.88, -0.92],
boxSize: [0.1, 1.1],
scalarToColors: null,
axisTitlePixelOffset: 36.0,
axisTextStyle: {
fontColor: 'white',
fontStyle: 'normal',
fontSize: 18,
fontFamily: 'serif'
},
tickLabelPixelOffset: 14.0,
tickTextStyle: {
fontColor: 'white',
fontStyle: 'normal',
fontSize: 14,
fontFamily: 'serif'
}
}, initialValues);
} // ----------------------------------------------------------------------------
function extend(publicAPI, model) {
var initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
Object.assign(model, defaultValues(initialValues)); // Inheritance
vtkActor.extend(publicAPI, model, initialValues);
publicAPI.getProperty().setDiffuse(0.0);
publicAPI.getProperty().setAmbient(1.0);
model._tmAtlas = new Map(); // internal variables
model.lastSize = [800, 800];
model.lastAspectRatio = 1.0;
model.textValues = [];
model.lastTickBounds = [];
model.barMapper = vtkMapper.newInstance();
model.barMapper.setInterpolateScalarsBeforeMapping(true);
model.polyData = vtkPolyData.newInstance();
model.barMapper.setInputData(model.polyData);
model.barActor = vtkActor.newInstance();
model.barActor.setMapper(model.barMapper);
model.barActor.setProperty(publicAPI.getProperty());
model.lastRedrawTime = {};
macro.obj(model.lastRedrawTime, {
mtime: 0
});
model.lastRebuildTime = {};
macro.obj(model.lastRebuildTime, {
mtime: 0
});
model.textPolyData = vtkPolyData.newInstance(); // for texture atlas
model.tmPolyData = vtkPolyData.newInstance();
model.tmMapper = vtkMapper.newInstance();
model.tmMapper.setInputData(model.tmPolyData);
model.tmTexture = vtkTexture.newInstance();
model.tmTexture.setInterpolate(false);
model.tmActor = vtkActor.newInstance();
model.tmActor.setMapper(model.tmMapper);
model.tmActor.addTexture(model.tmTexture);
model.tmActor.setProperty(publicAPI.getProperty());
model.tmCanvas = document.createElement('canvas');
model.tmContext = model.tmCanvas.getContext('2d'); // PixelSpaceCallbackMapper - we do need an empty polydata
// really just used to get the window size which we need to do
// proper text positioning and scaling.
model.mapper = vtkPixelSpaceCallbackMapper.newInstance();
model.pixelMapperPolyData = vtkPolyData.newInstance();
model.mapper.setInputData(model.pixelMapperPolyData);
model.mapper.setCallback(function (coords, camera, aspect, depthValues, size) {
model.camera = camera;
if (model.lastSize[0] !== size[0] || model.lastSize[1] !== size[1]) {
model.lastSize[0] = size[0];
model.lastSize[1] = size[1];
model.lastAspectRatio = size[0] / size[1]; // we could use modified, but really the public state is not
// modified
model.forceUpdate = true;
}
publicAPI.update();
});
macro.setGet(publicAPI, model, ['automated', 'axisTitlePixelOffset', 'axisLabel', 'scalarsToColors', 'tickLabelPixelOffset']);
macro.get(publicAPI, model, ['axisTextStyle', 'tickTextStyle']);
macro.getArray(publicAPI, model, ['boxPosition', 'boxSize']);
macro.setArray(publicAPI, model, ['boxPosition', 'boxSize'], 2); // Object methods
vtkScalarBarActor(publicAPI, model);
} // ----------------------------------------------------------------------------
var newInstance = macro.newInstance(extend, 'vtkScalarBarActor'); // ----------------------------------------------------------------------------
var vtkScalarBarActor$1 = {
newInstance: newInstance,
extend: extend
};
export default vtkScalarBarActor$1;
export { extend, newInstance };