How-to: Draw a Bounding Box in the Web Viewer

Language: JavaScript

The following JavaScript is a modified version of the Bounding Box example provided in the Developer Examples section of the Quickstart menu. This modified example contains three components:

  1. BoundingBoxMarkup class extended from MarkupItem
  2. Selection event handler
  3. Registering event handler as a Callback

Complete the following steps to add this BoundingBoxMarkup class to any Sample Model in the Quickstart application:

  1. Launch the Quickstart server and choose any of the sample models
  2. Open the web browser console
  3. Add the following BoundingBoxMarkup class by copying it into the console:
//Create bounding box markup item
var BoundingBoxMarkup = /** @class */ (function (_super) {
	__extends(BoundingBoxMarkup, _super);
	function BoundingBoxMarkup(viewer) {
		var _this = _super.call(this) || this;
		_this._box = null;
		_this._boxVertices = new Communicator.Markup.Shape.CircleCollection();
		_this._boxVertexSize = 1.0;
		_this._boxWires = new Communicator.Markup.Shape.LineCollection();
		_this._viewer = viewer;
		return _this;
	}
	BoundingBoxMarkup.prototype.setVertexSize = function (vertexSize) {
		this._boxVertexSize = vertexSize;
		this._viewer.markupManager.refreshMarkup();
	};
	BoundingBoxMarkup.prototype.setWireWidth = function (wireWidth) {
		this._boxWires.setStrokeWidth(wireWidth);
		this._viewer.markupManager.refreshMarkup();
	};
	BoundingBoxMarkup.prototype.draw = function () {
		if (!this._box) {
			return;
		}
		this._update();
		var renderer = this._viewer.markupManager.getRenderer();
		renderer.drawCircles(this._boxVertices);
		renderer.drawLines(this._boxWires);
	};
	BoundingBoxMarkup.prototype.setBox = function (box) {
		this._box = box.copy();
	};
	BoundingBoxMarkup.prototype.clearBox = function () {
		this._box = null;
	};
	BoundingBoxMarkup.prototype.setBoxColor = function (color) {
		this._boxVertices.setFillColor(color);
		this._boxVertices.setStrokeColor(color);
		this._boxWires.setStrokeColor(color);
		this._viewer.markupManager.refreshMarkup();
	};
	BoundingBoxMarkup.prototype._update = function () {
		this._boxVertices.clear();
		this._boxWires.clear();
		
		if (this._box === null) {
			return;
		}
		
		var view = this._viewer.view;
		
		// create points around the selection
		var points = [];
		points.push(new Communicator.Point3(this._box.min.x, this._box.max.y, this._box.max.z));
		points.push(new Communicator.Point3(this._box.max.x, this._box.max.y, this._box.max.z));
		points.push(new Communicator.Point3(this._box.max.x, this._box.min.y, this._box.max.z));
		points.push(new Communicator.Point3(this._box.min.x, this._box.min.y, this._box.max.z));
		points.push(new Communicator.Point3(this._box.min.x, this._box.max.y, this._box.min.z));
		points.push(new Communicator.Point3(this._box.max.x, this._box.max.y, this._box.min.z));
		points.push(new Communicator.Point3(this._box.max.x, this._box.min.y, this._box.min.z));
		points.push(new Communicator.Point3(this._box.min.x, this._box.min.y, this._box.min.z));
		
		points = points.map((point) => view.projectPoint(point));
		
		// generate vertices from points
		var vertices = [];
		vertices = points.map((point) => Communicator.Point2.fromPoint3(point));
				
		// add points		
		vertices.forEach((vertex) => this._boxVertices.addCircle(vertex, this._boxVertexSize));
		
		// create box wireframe
		this._boxWires.addLine(vertices[0], vertices[1]);
		this._boxWires.addLine(vertices[1], vertices[2]);
		this._boxWires.addLine(vertices[2], vertices[3]);
		this._boxWires.addLine(vertices[3], vertices[0]);
		this._boxWires.addLine(vertices[4], vertices[5]);
		this._boxWires.addLine(vertices[5], vertices[6]);
		this._boxWires.addLine(vertices[6], vertices[7]);
		this._boxWires.addLine(vertices[7], vertices[4]);
		this._boxWires.addLine(vertices[0], vertices[4]);
		this._boxWires.addLine(vertices[1], vertices[5]);
		this._boxWires.addLine(vertices[2], vertices[6]);
		this._boxWires.addLine(vertices[3], vertices[7]);
	};
	return BoundingBoxMarkup;
}(Communicator.Markup.MarkupItem));
  1. Next, add an event handler that will trigger when a selection is made:
//Selection function that adds bounding box to selected node
function mySelectionFunc(event) {
	var markupManager = hwv.getMarkupManager();
	var model = hwv.getModel();
	var selection = event.getSelection();
	if (selection.isNodeSelection()) {
		var partId = selection.getNodeId();
		if (model.isNodeLoaded(partId)) {
			model.getNodesBounding([partId]).then(function (boundingBox) {
				_boundingBoxMarkup.setBox(boundingBox);
				_boundingBoxMarkupHandle = hwv.getMarkupManager().registerMarkup(_boundingBoxMarkup);
			});
		}
	}
	else {
		_boundingBoxMarkup.clearBox();
		if (_boundingBoxMarkupHandle !== null) {
			hwv.getMarkupManager().unregisterMarkup(_boundingBoxMarkupHandle);
		}
	}
};
  1. Now register the event handler:
//Set callback for selection function
hwv.setCallbacks({
	selectionArray: function (events) {
		events.forEach((event) => mySelectionFunc(event));
	}
});
  1. Last, initialize a new BoundingBoxMarkup :
//Create variables
var _boundingBoxMarkup = new BoundingBoxMarkup(hwv);

Make a selection on the model. A bounding box should be drawn around the item.

For your convenience in doing a single copy-and-paste operation in the Web Viewer, the code above has been consolidated:

//Create bounding box markup item
var BoundingBoxMarkup = /** @class */ (function (_super) {
	__extends(BoundingBoxMarkup, _super);
	function BoundingBoxMarkup(viewer) {
		var _this = _super.call(this) || this;
		_this._box = null;
		_this._boxVertices = new Communicator.Markup.Shape.CircleCollection();
		_this._boxVertexSize = 1.0;
		_this._boxWires = new Communicator.Markup.Shape.LineCollection();
		_this._viewer = viewer;
		return _this;
	}
	BoundingBoxMarkup.prototype.setVertexSize = function (vertexSize) {
		this._boxVertexSize = vertexSize;
		this._viewer.markupManager.refreshMarkup();
	};
	BoundingBoxMarkup.prototype.setWireWidth = function (wireWidth) {
		this._boxWires.setStrokeWidth(wireWidth);
		this._viewer.markupManager.refreshMarkup();
	};
	BoundingBoxMarkup.prototype.draw = function () {
		if (!this._box) {
			return;
		}
		this._update();
		var renderer = this._viewer.markupManager.getRenderer();
		renderer.drawCircles(this._boxVertices);
		renderer.drawLines(this._boxWires);
	};
	BoundingBoxMarkup.prototype.setBox = function (box) {
		this._box = box.copy();
	};
	BoundingBoxMarkup.prototype.clearBox = function () {
		this._box = null;
	};
	BoundingBoxMarkup.prototype.setBoxColor = function (color) {
		this._boxVertices.setFillColor(color);
		this._boxVertices.setStrokeColor(color);
		this._boxWires.setStrokeColor(color);
		this._viewer.markupManager.refreshMarkup();
	};
	BoundingBoxMarkup.prototype._update = function () {
		this._boxVertices.clear();
		this._boxWires.clear();
		
		if (this._box === null) {
			return;
		}
		
		var view = this._viewer.view;
		
		// create points around the selection
		var points = [];
		points.push(new Communicator.Point3(this._box.min.x, this._box.max.y, this._box.max.z));
		points.push(new Communicator.Point3(this._box.max.x, this._box.max.y, this._box.max.z));
		points.push(new Communicator.Point3(this._box.max.x, this._box.min.y, this._box.max.z));
		points.push(new Communicator.Point3(this._box.min.x, this._box.min.y, this._box.max.z));
		points.push(new Communicator.Point3(this._box.min.x, this._box.max.y, this._box.min.z));
		points.push(new Communicator.Point3(this._box.max.x, this._box.max.y, this._box.min.z));
		points.push(new Communicator.Point3(this._box.max.x, this._box.min.y, this._box.min.z));
		points.push(new Communicator.Point3(this._box.min.x, this._box.min.y, this._box.min.z));
		
		points = points.map((point) => view.projectPoint(point));
		
		// generate vertices from points
		var vertices = [];
		vertices = points.map((point) => Communicator.Point2.fromPoint3(point));
				
		// add points		
		vertices.forEach((vertex) => this._boxVertices.addCircle(vertex, this._boxVertexSize));
		
		// create box wireframe
		this._boxWires.addLine(vertices[0], vertices[1]);
		this._boxWires.addLine(vertices[1], vertices[2]);
		this._boxWires.addLine(vertices[2], vertices[3]);
		this._boxWires.addLine(vertices[3], vertices[0]);
		this._boxWires.addLine(vertices[4], vertices[5]);
		this._boxWires.addLine(vertices[5], vertices[6]);
		this._boxWires.addLine(vertices[6], vertices[7]);
		this._boxWires.addLine(vertices[7], vertices[4]);
		this._boxWires.addLine(vertices[0], vertices[4]);
		this._boxWires.addLine(vertices[1], vertices[5]);
		this._boxWires.addLine(vertices[2], vertices[6]);
		this._boxWires.addLine(vertices[3], vertices[7]);
	};
	return BoundingBoxMarkup;
}(Communicator.Markup.MarkupItem));

//Selection function that adds bounding box to selected node
function mySelectionFunc(event) {
	var markupManager = hwv.getMarkupManager();
	var model = hwv.getModel();
	var selection = event.getSelection();
	if (selection.isNodeSelection()) {
		var partId = selection.getNodeId();
		if (model.isNodeLoaded(partId)) {
			model.getNodesBounding([partId]).then(function (boundingBox) {
				_boundingBoxMarkup.setBox(boundingBox);
				_boundingBoxMarkupHandle = hwv.getMarkupManager().registerMarkup(_boundingBoxMarkup);
			});
		}
	}
	else {
		_boundingBoxMarkup.clearBox();
		if (_boundingBoxMarkupHandle !== null) {
			hwv.getMarkupManager().unregisterMarkup(_boundingBoxMarkupHandle);
		}
	}
};

//Set callback for selection function
hwv.setCallbacks({
	selectionArray: function (events) {
		events.forEach((event) => mySelectionFunc(event));
	}
});

//Create variables
var _boundingBoxMarkup = new BoundingBoxMarkup(hwv);