@kitware/vtk.js
Version:
Visualization Toolkit for the Web
804 lines (670 loc) • 34.3 kB
JavaScript
import _toConsumableArray from '@babel/runtime/helpers/toConsumableArray';
import _defineProperty from '@babel/runtime/helpers/defineProperty';
import * as d3 from 'd3-scale';
import { M as nearestPowerOfTwo } from '../../Common/Core/Math/index.js';
import macro from '../../macros.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 vtkPolyData from '../../Common/DataModel/PolyData.js';
import vtkTexture from './Texture.js';
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); 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 = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : 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
//
// Developer note: This class is broken into the main class and a helper
// class. The main class holds view independent properties (those properties
// that do not change as the view's resolution/aspect ratio change). The
// helper class is instantiated one per view and holds properties that can
// depend on view specific values such as resolution. The helper class code
// could have been left to the View specific implementation (such as
// vtkWebGPUScalarBarActor) but is instead placed here to it can be shared by
// multiple rendering backends.
//
// ----------------------------------------------------------------------------
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);
} // ----------------------------------------------------------------------------
// Default autoLayout function
// ----------------------------------------------------------------------------
// 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
//
// Note that this function can and should read values from the
// ScalarBarActor but should only write values to the view dependent helper
// instance that is provided as those values are the ones that will be used
// for rendering.
//
function defaultAutoLayout(publicAPI, model) {
return function (helper) {
// we don't do a linear scale, the proportions for
// a 700 pixel window differ from a 1400
var lastSize = helper.getLastSize();
var xAxisAdjust = Math.pow(lastSize[0] / 700, 0.8);
var yAxisAdjust = Math.pow(lastSize[1] / 700, 0.8);
var minAdjust = Math.min(xAxisAdjust, yAxisAdjust);
var axisTextStyle = helper.getAxisTextStyle();
var tickTextStyle = helper.getTickTextStyle();
Object.assign(axisTextStyle, model.axisTextStyle);
Object.assign(tickTextStyle, model.tickTextStyle); // compute a reasonable font size first
axisTextStyle.fontSize = Math.max(24 * minAdjust, 12);
if (helper.getLastAspectRatio() > 1.0) {
tickTextStyle.fontSize = Math.max(20 * minAdjust, 10);
} else {
tickTextStyle.fontSize = Math.max(16 * minAdjust, 10);
} // rebuild the text atlas
var textSizes = helper.updateTextureAtlas(); // now compute the boxSize and pixel offsets, different algorithm
// for horizonal versus vertical
helper.setTopTitle(false);
var boxSize = helper.getBoxSizeByReference(); // if vertical
if (helper.getLastAspectRatio() > 1.0) {
helper.setTickLabelPixelOffset(0.3 * tickTextStyle.fontSize); // if the title will fit within the width of the bar then that looks
// nicer to put it at the top (helper.topTitle), otherwise rotate it
// and place it sideways
if (textSizes.titleWidth <= textSizes.tickWidth + helper.getTickLabelPixelOffset() + 0.8 * tickTextStyle.fontSize) {
helper.setTopTitle(true);
helper.setAxisTitlePixelOffset(0.2 * tickTextStyle.fontSize);
boxSize[0] = 2.0 * (textSizes.tickWidth + helper.getTickLabelPixelOffset() + 0.8 * tickTextStyle.fontSize) / lastSize[0];
helper.setBoxPosition([0.98 - boxSize[0], -0.92]);
} else {
helper.setAxisTitlePixelOffset(0.2 * tickTextStyle.fontSize);
boxSize[0] = 2.0 * (textSizes.titleHeight + helper.getAxisTitlePixelOffset() + textSizes.tickWidth + helper.getTickLabelPixelOffset() + 0.8 * tickTextStyle.fontSize) / lastSize[0];
helper.setBoxPosition([0.99 - boxSize[0], -0.92]);
}
boxSize[1] = Math.max(1.2, Math.min(1.84 / yAxisAdjust, 1.84));
} else {
// horizontal
helper.setAxisTitlePixelOffset(1.2 * tickTextStyle.fontSize);
helper.setTickLabelPixelOffset(0.1 * tickTextStyle.fontSize);
var titleHeight = // total offset from top of bar (includes ticks)
2.0 * (0.8 * tickTextStyle.fontSize + textSizes.titleHeight + helper.getAxisTitlePixelOffset()) / lastSize[1];
var tickWidth = 2.0 * textSizes.tickWidth / lastSize[0];
boxSize[0] = Math.min(1.9, Math.max(1.4, 1.4 * tickWidth * (helper.getTicks().length + 3)));
boxSize[1] = titleHeight;
helper.setBoxPosition([-0.5 * boxSize[0], -0.97]);
} // recomute bar segments based on positioning
helper.recomputeBarSegments(textSizes);
};
} // ----------------------------------------------------------------------------
// Default generateTicks function
// ----------------------------------------------------------------------------
// This function returns the default function used to generate vtkScalarBarActor ticks.
// The default function makes use of d3.scaleLinear() to generate 5 tick marks between
// the minimum and maximum values of the scalar bar. Customize this behavior by passing
// a function to vtkScalarBarActor.newInstance({ generateTicks: customGenerateTicks })
// or by calling scalarBarActor.setGenerateTicks(customGenerateTicks).
function defaultGenerateTicks(publicApi, model) {
return function (helper) {
var lastTickBounds = helper.getLastTickBounds();
var scale = d3.scaleLinear().domain([lastTickBounds[0], lastTickBounds[1]]);
var ticks = scale.ticks(5);
var format = scale.tickFormat(5);
helper.setTicks(ticks);
helper.setTickStrings(ticks.map(format));
};
} // many properties of this actor depend on the API specific view The main
// dependency being the resolution as that drives what font sizes to use.
// Bacause of this we need to do some of the calculations in a API specific
// subclass. But... we don't want a lot of duplicated code between WebGL and
// WebGPU for example so we have this helper class, that is designed to be
// fairly API independent so that API specific views can call this to do
// most of the work.
function vtkScalarBarActorHelper(publicAPI, model) {
// Set our className
model.classHierarchy.push('vtkScalarBarActorHelper');
publicAPI.setRenderable = function (renderable) {
if (model.renderable === renderable) {
return;
}
model.renderable = renderable;
model.barActor.setProperty(renderable.getProperty());
model.barActor.setParentProp(renderable);
model.barActor.setCoordinateSystemToDisplay();
model.tmActor.setProperty(renderable.getProperty());
model.tmActor.setParentProp(renderable);
model.tmActor.setCoordinateSystemToDisplay();
model.generateTicks = renderable.generateTicks;
model.axisTextStyle = _objectSpread({}, renderable.getAxisTextStyle());
model.tickTextStyle = _objectSpread({}, renderable.getTickTextStyle());
publicAPI.modified();
};
publicAPI.updateAPISpecificData = function (size, camera, renderWindow) {
// has the size changed?
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];
model.forceUpdate = true;
}
var scalarsToColors = model.renderable.getScalarsToColors();
if (!scalarsToColors || !model.renderable.getVisibility()) {
return;
} // make sure the lut is assigned to our mapper
model.barMapper.setLookupTable(scalarsToColors); // camera should be the same for all views
model.camera = camera;
model.renderWindow = renderWindow; // did something significant change? If so rebuild a lot of things
if (model.forceUpdate || Math.max(scalarsToColors.getMTime(), publicAPI.getMTime(), model.renderable.getMTime()) > model.lastRebuildTime.getMTime()) {
var range = scalarsToColors.getMappingRange();
model.lastTickBounds = _toConsumableArray(range); // compute tick marks for axes (update for log scale)
model.renderable.getGenerateTicks()(publicAPI);
if (model.renderable.getAutomated()) {
model.renderable.getAutoLayout()(publicAPI);
} else {
// copy values from renderable
model.axisTextStyle = _objectSpread({}, model.renderable.getAxisTextStyle());
model.tickTextStyle = _objectSpread({}, model.renderable.getTickTextStyle());
model.barPosition = _toConsumableArray(model.renderable.getBarPosition());
model.barSize = _toConsumableArray(model.renderable.getBarSize());
model.boxPosition = _toConsumableArray(model.renderable.getBoxPosition());
model.boxSize = _toConsumableArray(model.renderable.getBoxSize());
model.axisTitlePixelOffset = model.renderable.getAxisTitlePixelOffset();
model.tickLabelPixelOffset = model.renderable.getTickLabelPixelOffset(); // 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);
}
publicAPI.updatePolyDataForLabels();
publicAPI.updatePolyDataForBarSegments();
model.lastRebuildTime.modified();
model.forceUpdate = false;
}
}; // 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.renderable.getAxisLabel());
var entry = {
height: metrics.actualBoundingBoxAscent + 2,
startingHeight: totalHeight,
width: metrics.width + 2,
textStyle: model.axisTextStyle
};
newTmAtlas.set(model.renderable.getAxisLabel(), 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(publicAPI.getTickStrings()), ['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);
});
model.tmTexture.setCanvas(model.tmCanvas); // mark as modified since the canvas typically doesn't change
model.tmTexture.modified();
model._tmAtlas = newTmAtlas;
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 _tickWidth = (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;
model.barPosition[1] = model.boxPosition[1];
segSize[0] = _tickWidth;
}
return segSize;
}; // based on all the settins compute a barSegments array
// containing the segments of 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) {
var _model$renderable$get, _model$renderable$get2, _model$renderable$get3, _model$renderable$get4;
// 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 (model.renderable.getDrawNanAnnotation() && model.renderable.getScalarsToColors().getNanColor()) {
pushSeg('NaN', [NaN, NaN, NaN, NaN]);
}
if (model.renderable.getDrawBelowRangeSwatch() && (_model$renderable$get = (_model$renderable$get2 = model.renderable.getScalarsToColors()).getUseBelowRangeColor) !== null && _model$renderable$get !== void 0 && _model$renderable$get.call(_model$renderable$get2)) {
pushSeg('Below', [-0.1, -0.1, -0.1, -0.1]);
}
var haveAbove = (_model$renderable$get3 = (_model$renderable$get4 = model.renderable.getScalarsToColors()).getUseAboveRangeColor) === null || _model$renderable$get3 === void 0 ? void 0 : _model$renderable$get3.call(_model$renderable$get4); // 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 (model.renderable.getDrawAboveRangeSwatch() && haveAbove) {
segSize[barAxis] = oldSegSize;
startPos[barAxis] += segSpace;
pushSeg('Above', [1.1, 1.1, 1.1, 1.1]);
}
}; // called by updatePolyDataForLabels
// modifies class constants tmp2v3
var tmp2v3 = new Float64Array(3); // anchor point = pos
// H alignment = left, middle, right
// V alignment = bottom, middle, top
// Text Orientation = horizontal, vertical
// orientation
publicAPI.createPolyDataForOneLabel = function (text, pos, alignment, orientation, offset, results) {
var value = model._tmAtlas.get(text);
if (!value) {
return;
} // have to find the four corners of the texture polygon for this label
var ptIdx = results.ptIdx;
var cellIdx = results.cellIdx; // get achor point in pixels
tmp2v3[0] = (0.5 * pos[0] + 0.5) * model.lastSize[0];
tmp2v3[1] = (0.5 * pos[1] + 0.5) * model.lastSize[1];
tmp2v3[2] = pos[2];
tmp2v3[0] += offset[0];
tmp2v3[1] += offset[1]; // get text size in display pixels
var textSize = [];
var textAxes = orientation === 'vertical' ? [1, 0] : [0, 1];
if (orientation === 'vertical') {
textSize[0] = value.width;
textSize[1] = -value.height; // update anchor point based on alignment
if (alignment[0] === 'middle') {
tmp2v3[1] -= value.width / 2.0;
} else if (alignment[0] === 'right') {
tmp2v3[1] -= value.width;
}
if (alignment[1] === 'middle') {
tmp2v3[0] += value.height / 2.0;
} else if (alignment[1] === 'top') {
tmp2v3[0] += value.height;
}
} else {
textSize[0] = value.width;
textSize[1] = value.height; // update anchor point based on alignment
if (alignment[0] === 'middle') {
tmp2v3[0] -= value.width / 2.0;
} else if (alignment[0] === 'right') {
tmp2v3[0] -= value.width;
}
if (alignment[1] === 'middle') {
tmp2v3[1] -= value.height / 2.0;
} else if (alignment[1] === 'top') {
tmp2v3[1] -= value.height;
}
}
results.points[ptIdx * 3] = tmp2v3[0];
results.points[ptIdx * 3 + 1] = tmp2v3[1];
results.points[ptIdx * 3 + 2] = tmp2v3[2];
results.tcoords[ptIdx * 2] = value.tcoords[0];
results.tcoords[ptIdx * 2 + 1] = value.tcoords[1];
ptIdx++;
tmp2v3[textAxes[0]] += textSize[0];
results.points[ptIdx * 3] = tmp2v3[0];
results.points[ptIdx * 3 + 1] = tmp2v3[1];
results.points[ptIdx * 3 + 2] = tmp2v3[2];
results.tcoords[ptIdx * 2] = value.tcoords[2];
results.tcoords[ptIdx * 2 + 1] = value.tcoords[3];
ptIdx++;
tmp2v3[textAxes[1]] += textSize[1];
results.points[ptIdx * 3] = tmp2v3[0];
results.points[ptIdx * 3 + 1] = tmp2v3[1];
results.points[ptIdx * 3 + 2] = tmp2v3[2];
results.tcoords[ptIdx * 2] = value.tcoords[4];
results.tcoords[ptIdx * 2 + 1] = value.tcoords[5];
ptIdx++;
tmp2v3[textAxes[0]] -= textSize[0];
results.points[ptIdx * 3] = tmp2v3[0];
results.points[ptIdx * 3 + 1] = tmp2v3[1];
results.points[ptIdx * 3 + 2] = tmp2v3[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
var tmpv3 = new Float64Array(3);
publicAPI.updatePolyDataForLabels = function () {
// update the polydata
var numLabels = publicAPI.getTickStrings().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
var offsetAxis = model.vertical ? 0 : 1;
var spacedAxis = model.vertical ? 1 : 0;
tmpv3[2] = -0.99; // near plane
// draw the title
var alignment = model.vertical ? ['right', 'middle'] : ['middle', 'bottom'];
var dir = [0, 1];
var tickOffsets = [0, 0];
if (model.vertical) {
tickOffsets[0] = -model.tickLabelPixelOffset;
if (model.topTitle) {
tmpv3[0] = model.boxPosition[0] + 0.5 * model.boxSize[0];
tmpv3[1] = model.barPosition[1] + model.barSize[1]; // write the axis label
publicAPI.createPolyDataForOneLabel(model.renderable.getAxisLabel(), tmpv3, ['middle', 'bottom'], 'horizontal', [0, model.axisTitlePixelOffset], results);
} else {
tmpv3[0] = model.barPosition[0] + model.barSize[0];
tmpv3[1] = model.barPosition[1] + 0.5 * model.barSize[1]; // write the axis label
publicAPI.createPolyDataForOneLabel(model.renderable.getAxisLabel(), tmpv3, ['middle', 'top'], 'vertical', [model.axisTitlePixelOffset, 0], results);
}
dir = [-1, 0];
} else {
tickOffsets[1] = model.tickLabelPixelOffset;
tmpv3[0] = model.barPosition[0] + 0.5 * model.barSize[0];
tmpv3[1] = model.barPosition[1] + model.barSize[1];
publicAPI.createPolyDataForOneLabel(model.renderable.getAxisLabel(), tmpv3, ['middle', 'bottom'], 'horizontal', [0, model.axisTitlePixelOffset], results);
}
tmpv3[offsetAxis] = model.barPosition[offsetAxis] + (0.5 * dir[offsetAxis] + 0.5) * model.barSize[offsetAxis];
tmpv3[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 {
tmpv3[spacedAxis] = model.barPosition[spacedAxis] + 0.5 * model.barSize[spacedAxis] * (seg.corners[2][spacedAxis] + seg.corners[0][spacedAxis]);
publicAPI.createPolyDataForOneLabel(seg.title, tmpv3, alignment, 'horizontal', tickOffsets, 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]);
var ticks = publicAPI.getTicks();
var tickStrings = publicAPI.getTickStrings();
for (var t = 0; t < ticks.length; t++) {
var tickPos = (ticks[t] - model.lastTickBounds[0]) / (model.lastTickBounds[1] - model.lastTickBounds[0]);
tmpv3[spacedAxis] = tickSegmentStart + tickSegmentSize * tickPos;
publicAPI.createPolyDataForOneLabel(tickStrings[t], tmpv3, alignment, 'horizontal', tickOffsets, 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 _scalarsToColors$getU, _scalarsToColors$getU2;
var scalarsToColors = model.renderable.getScalarsToColors();
var numberOfExtraColors = 0;
if (model.renderable.getDrawNanAnnotation() && scalarsToColors.getNanColor()) {
numberOfExtraColors += 1;
}
if (model.renderable.getDrawBelowRangeSwatch() && (_scalarsToColors$getU = scalarsToColors.getUseBelowRangeColor) !== null && _scalarsToColors$getU !== void 0 && _scalarsToColors$getU.call(scalarsToColors)) {
numberOfExtraColors += 1;
}
if (model.renderable.getDrawAboveRangeSwatch() && (_scalarsToColors$getU2 = scalarsToColors.getUseAboveRangeColor) !== null && _scalarsToColors$getU2 !== void 0 && _scalarsToColors$getU2.call(scalarsToColors)) {
numberOfExtraColors += 1;
}
var numPts = 4 * (1 + numberOfExtraColors);
var numQuads = numPts; // handle vector component mode
var numComps = 1;
if (scalarsToColors.getVectorMode() === VectorMode.COMPONENT) {
numComps = 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];
for (var e = 0; e < 4; e++) {
tmpv3[0] = model.barPosition[0] + seg.corners[e][0] * model.barSize[0];
tmpv3[1] = model.barPosition[1] + seg.corners[e][1] * model.barSize[1];
points[ptIdx * 3] = (0.5 * tmpv3[0] + 0.5) * model.lastSize[0];
points[ptIdx * 3 + 1] = (0.5 * tmpv3[1] + 0.5) * model.lastSize[1];
points[ptIdx * 3 + 2] = tmpv3[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();
};
}
var newScalarBarActorHelper = macro.newInstance(function (publicAPI, model) {
var initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {
renderable: null
};
Object.assign(model, {}, initialValues); // Inheritance
macro.obj(publicAPI, model);
macro.setGet(publicAPI, model, ['axisTitlePixelOffset', 'tickLabelPixelOffset', 'renderable', 'topTitle', 'ticks', 'tickStrings']);
macro.get(publicAPI, model, ['lastSize', 'lastAspectRatio', 'lastTickBounds', 'axisTextStyle', 'tickTextStyle', 'barActor', 'tmActor']);
macro.getArray(publicAPI, model, ['boxPosition', 'boxSize']);
macro.setArray(publicAPI, model, ['boxPosition', 'boxSize'], 2);
model.forceUpdate = false;
model.lastRebuildTime = {};
macro.obj(model.lastRebuildTime, {
mtime: 0
});
model.lastSize = [-1, -1];
model.tmCanvas = document.createElement('canvas');
model.tmContext = model.tmCanvas.getContext('2d');
model._tmAtlas = new Map();
model.barMapper = vtkMapper.newInstance();
model.barMapper.setInterpolateScalarsBeforeMapping(true);
model.barMapper.setUseLookupTableScalarRange(true);
model.polyData = vtkPolyData.newInstance();
model.barMapper.setInputData(model.polyData);
model.barActor = vtkActor.newInstance();
model.barActor.setMapper(model.barMapper); // for texture atlas
model.tmPolyData = vtkPolyData.newInstance();
model.tmMapper = vtkMapper.newInstance();
model.tmMapper.setInputData(model.tmPolyData);
model.tmTexture = vtkTexture.newInstance({
resizable: true
});
model.tmTexture.setInterpolate(false);
model.tmActor = vtkActor.newInstance({
parentProp: publicAPI
});
model.tmActor.setMapper(model.tmMapper);
model.tmActor.addTexture(model.tmTexture);
model.barPosition = [0, 0];
model.barSize = [0, 0];
model.boxPosition = [0.88, -0.92];
model.boxSize = [0.1, 1.1]; // internal variables
model.lastTickBounds = [];
vtkScalarBarActorHelper(publicAPI, model);
}, 'vtkScalarBarActorHelper'); //
// Now we define the public class that the application sets view independent
// properties on. This class is fairly small as it mainly just holds
// properties setter and getters leaving all calculations to the helper
// class.
//
function vtkScalarBarActor(publicAPI, model) {
// Set our className
model.classHierarchy.push('vtkScalarBarActor');
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.resetAutoLayoutToDefault = function () {
publicAPI.setAutoLayout(defaultAutoLayout(publicAPI, model));
};
publicAPI.resetGenerateTicksToDefault = function () {
publicAPI.setGenerateTicks(defaultGenerateTicks());
};
} // ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------
function defaultValues(initialValues) {
return _objectSpread({
automated: true,
autoLayout: null,
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'
},
generateTicks: null,
drawNanAnnotation: true,
drawBelowRangeSwatch: true,
drawAboveRangeSwatch: true
}, initialValues);
} // ----------------------------------------------------------------------------
function extend(publicAPI, model) {
var initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
Object.assign(model, defaultValues(initialValues));
if (!model.autoLayout) model.autoLayout = defaultAutoLayout(publicAPI, model);
if (!model.generateTicks) model.generateTicks = defaultGenerateTicks(); // Inheritance
vtkActor.extend(publicAPI, model, initialValues);
publicAPI.getProperty().setDiffuse(0.0);
publicAPI.getProperty().setAmbient(1.0);
macro.setGet(publicAPI, model, ['automated', 'autoLayout', 'axisTitlePixelOffset', 'axisLabel', 'scalarsToColors', 'tickLabelPixelOffset', 'generateTicks', 'drawNanAnnotation', 'drawBelowRangeSwatch', 'drawAboveRangeSwatch']);
macro.get(publicAPI, model, ['axisTextStyle', 'tickTextStyle']);
macro.getArray(publicAPI, model, ['barPosition', 'barSize', 'boxPosition', 'boxSize']);
macro.setArray(publicAPI, model, ['barPosition', 'barSize', 'boxPosition', 'boxSize'], 2); // Object methods
vtkScalarBarActor(publicAPI, model);
} // ----------------------------------------------------------------------------
var newInstance = macro.newInstance(extend, 'vtkScalarBarActor'); // ----------------------------------------------------------------------------
var vtkScalarBarActor$1 = {
newInstance: newInstance,
extend: extend,
newScalarBarActorHelper: newScalarBarActorHelper
};
export { vtkScalarBarActor$1 as default, extend, newInstance };