UNPKG

awv3

Version:
623 lines (514 loc) 27.7 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.ObjectSelector = undefined; var _typeof2 = require('babel-runtime/helpers/typeof'); var _typeof3 = _interopRequireDefault(_typeof2); var _getIterator2 = require('babel-runtime/core-js/get-iterator'); var _getIterator3 = _interopRequireDefault(_getIterator2); var _set = require('babel-runtime/core-js/set'); var _set2 = _interopRequireDefault(_set); var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _createClass2 = require('babel-runtime/helpers/createClass'); var _createClass3 = _interopRequireDefault(_createClass2); var _three = require('three'); var THREE = _interopRequireWildcard(_three); var _object = require('../three/object3'); var _object2 = _interopRequireDefault(_object); var _orbit = require('../controls/orbit'); var _orbit2 = _interopRequireDefault(_orbit); var _perspective = require('../three/perspective'); var _perspective2 = _interopRequireDefault(_perspective); var _region = require('../three/region'); var _region2 = _interopRequireDefault(_region); var _elements = require('./store/elements'); var _helpers = require('./helpers'); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * @class ObjectSelector is used to select whole objects in the view * (Filtersettings: Object). * includes single selection as well as rubberband selection. Object selection * is based on the object's id only and works without userData and meta-information. */ var ObjectSelector = exports.ObjectSelector = function () { function ObjectSelector(session, options) { var _this = this; (0, _classCallCheck3.default)(this, ObjectSelector); this.session = session; // Wait until the sessions pool has been added into the view (happens in <App/>) this.session.pool.viewFound().then(function (view) { return _this.view = view; }); // the currently active selecion-element this.element = undefined; // stores the selected objects this.selectedSet = new _set2.default(); // call unobserve when deactivated this.unobserve = undefined; } /** * Deactivates the object-selector. Observation of selection-element is stopped. * Rubberband selection handlers are removed. */ (0, _createClass3.default)(ObjectSelector, [{ key: 'deactivate', value: function deactivate() { var element = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.element; this.removeAll(false); this.shiftHandler && document.removeEventListener('keydown', this.shiftHandler); this.shiftHandler = undefined; this.element = undefined; this.unobserve && this.unobserve(); } /** * Activates the object-selector. The Given selection-element is observed in * order to register changes when click-deleting labels. Handlers for * rubberband selection are created. */ }, { key: 'activate', value: function activate() { var _this2 = this; var element = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.element; this.unobserve = this.session.observe(function (state) { return state.elements[element.id].children; }, function () { for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _helpers.arrayDiff.apply(undefined, args.concat([function (newItems) {}, function (deletedItems) { var candidates = []; var _loop = function _loop(i) { _this2.selectedSet.forEach(function (object) { if (deletedItems[i] === object.id) { candidates.push(object); } }); }; for (var i = 0; i < deletedItems.length; i++) { _loop(i); } candidates.forEach(function (object) { return _this2.remove({ object: object }); }); }])); }); this.element = element; this.view.interaction.filter = [this.session.pool]; // restore previously selected objects if (this.element.children.length > 0) { this.session.pool.traverse(function (obj) { if (_this2.element.children.indexOf(obj.id) > -1) { _this2.session.store.dispatch(_elements.actions.removeChild(_this2.element.id, obj.id)); _this2.add({ object: obj }); } }); } // update materials this.session.pool.traverse(function (item) { return item.updateMaterials(); }); // SHIFT KEY selection handler var candidates = []; this.shiftHandler = function (event) { if (!_this2.shiftHandler.handled && event.keyCode === 16) { (function () { _this2.shiftHandler.handled = true; _this2.view.input.debounce = false; _this2.view.controls.enabled = false; _this2.view.interaction.enabled = false; var boundingBoxes2D = []; _this2.session.pool.traverse(function (item) { //project bounding box to view coordinates if (item.visible && item.interactive && item.geometry) { item.updateMatrixWorld(true); item.geometry.computeBoundingBox(); var minPt = item.geometry.boundingBox.min.clone(); //TODO: get all 8 points var maxPt = item.geometry.boundingBox.max.clone(); //TODO: get all 8 points //project to view-coordinates var p1 = _this2.view.getPoint2(minPt); var p2 = _this2.view.getPoint2(maxPt); //bounding box in 2D var bounds2D = new THREE.Box2(); bounds2D.setFromPoints([p1, p2]); bounds2D.__object = item; boundingBoxes2D.push(bounds2D); } }); //draw rectangle var nearDistance = _this2.view.camera.near; var farDistance = _this2.view.camera.far; _this2.view.hud = true; _this2.view.controlsHud = undefined; _this2.view.cameraHud = new _perspective2.default({ near: nearDistance, far: farDistance, fov: _this2.view.camera.fov }); _this2.view.measure(true); var modelBounds = _this2.view.scene.updateBounds().bounds; var geom = new THREE.PlaneGeometry(1, 1); var box = new THREE.Mesh(geom, new THREE.MeshBasicMaterial({ transparent: true, opacity: 0.05, color: new THREE.Color(0) })); box.renderOrder = -1; _this2.view.sceneHud.add(box); var clickDown = void 0, mousePos = void 0, rubberBandLine = void 0, clickHud = void 0; var handler = function handler(event) { var _ret3 = function () { switch (event.type) { case 'mousedown': clickDown = new THREE.Vector2(event.offsetX, event.offsetY); mousePos = new THREE.Vector2(event.offsetX + 11, event.offsetY + 1); clickHud = _this2.view.getPoint3({ x: event.offsetX, y: event.offsetY }, _this2.view.cameraHud, 0); box.position.copy(clickHud); break; case 'mousemove': if (!clickDown) return { v: void 0 }; //update rectangle var tempPoint = _this2.view.getPoint3({ x: event.offsetX, y: event.offsetY }, _this2.view.cameraHud, 0); var delta = tempPoint.sub(clickHud); var width = Math.abs(delta.x); var height = Math.abs(delta.y); var halfHeight = height / 2; var halfWidth = width / 2; var halfDeltaX = delta.x / 2; var halfDeltaY = delta.y / 2; geom.vertices[0].set(-halfWidth + halfDeltaX, halfHeight + halfDeltaY, 0); geom.vertices[1].set(width - halfWidth + halfDeltaX, halfHeight + halfDeltaY, 0); geom.vertices[2].set(-halfWidth + halfDeltaX, -(height - halfHeight) + halfDeltaY, 0); geom.vertices[3].set(width - halfWidth + halfDeltaX, -(height - halfHeight) + halfDeltaY, 0); geom.verticesNeedUpdate = true; mousePos = new THREE.Vector2(event.offsetX, event.offsetY); //check intersection with rectangle in display-coordinates var rubberBandRectangle = new THREE.Box2(); rubberBandRectangle.setFromPoints([clickDown, mousePos]); var newCandidates = []; var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = (0, _getIterator3.default)(boundingBoxes2D), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var _box = _step.value; if (rubberBandRectangle.containsBox(_box)) { // create new object identical to raycast-hit newCandidates.push({ distance: 0, point: undefined, face: undefined, faceIndex: undefined, indices: undefined, object: _box.__object }); } } // Remove items not present any longer } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = (0, _getIterator3.default)(candidates), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var item = _step2.value; var found = false; var _iteratorNormalCompletion4 = true; var _didIteratorError4 = false; var _iteratorError4 = undefined; try { for (var _iterator4 = (0, _getIterator3.default)(newCandidates), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { var newItem = _step4.value; if (item.object.id === newItem.object.id) { found = true; break; } } } catch (err) { _didIteratorError4 = true; _iteratorError4 = err; } finally { try { if (!_iteratorNormalCompletion4 && _iterator4.return) { _iterator4.return(); } } finally { if (_didIteratorError4) { throw _iteratorError4; } } } if (!found) { _this2.remove(item, false); } } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2.return) { _iterator2.return(); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } candidates = newCandidates; // Add new items, but only if they aren't known yet var _iteratorNormalCompletion3 = true; var _didIteratorError3 = false; var _iteratorError3 = undefined; try { for (var _iterator3 = (0, _getIterator3.default)(candidates), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { var _item = _step3.value; _this2.add(_item, false); } } catch (err) { _didIteratorError3 = true; _iteratorError3 = err; } finally { try { if (!_iteratorNormalCompletion3 && _iterator3.return) { _iterator3.return(); } } finally { if (_didIteratorError3) { throw _iteratorError3; } } } _this2.view.invalidate(); break; case 'mouseup': box && box.destroy(); var tempIds = []; candidates.forEach(function (item) { return tempIds.push(item.object.id); }); clickDown = undefined; if (rubberBandLine != undefined) { _this2.view.scene.remove(rubberBandLine); rubberBandLine = undefined; } // Update UI after mouse-up _this2.session.store.dispatch(_elements.actions.update(_this2.element.id, { children: candidates.map(function (item) { return item.material.meta.id; }) })); break; } }(); if ((typeof _ret3 === 'undefined' ? 'undefined' : (0, _typeof3.default)(_ret3)) === "object") return _ret3.v; }; _this2.view.input.on(['mousedown', 'mousemove', 'mouseup'], handler); _this2.tempHandler = function () { box && box.destroy(); _this2.shiftHandler.handled = false; _this2.view.input.removeListener(['mousedown', 'mousemove', 'mouseup'], handler); document.removeEventListener('keyup', _this2.tempHandler); _this2.view.input.debounce = true; _this2.view.controls.enabled = true; _this2.view.interaction.enabled = true; _this2.view.scene.setRenderOrder(); }; document.addEventListener('keyup', _this2.tempHandler); })(); } }; this.shiftHandler.handled = false; document.addEventListener('keydown', this.shiftHandler); } /** * Add object to the set of selected elements * @param {RayCast-Hit} event - Object generated by the raycaster including the * hit object, material and meta-information */ }, { key: 'add', value: function add(event) { var notify = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; if (!this.isSelected(event.object)) { this.select(event.object); this.selectedSet.add(event.object); notify && this.session.store.dispatch(_elements.actions.addChild(this.element.id, event.object.id)); } return event; } /** * Remove object from the set of selected elements * @param {RayCast-Hit} event - Object generated by the raycaster including the * hit object, material and meta-information */ }, { key: 'remove', value: function remove(event) { var notify = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; if (this.isSelected(event.object)) { this.unselect(event.object); this.selectedSet.delete(event.object); notify && this.session.store.dispatch(_elements.actions.removeChild(this.element.id, event.object.id)); } } /** * Remove all items (three object) from the set of selected elements * @param {Boolean} keepLocals - If true, selected ids are kept within the selection-element */ }, { key: 'removeAll', value: function removeAll() { var _this3 = this; var removeElements = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; this.selectedSet.forEach(function (object) { return _this3.unselect(object); }); this.selectedSet.clear(); if (removeElements) { this.session.store.dispatch(_elements.actions.removeAllChilds(this.element.id)); } } /** * Called by selector when event is triggered. */ }, { key: 'hover', value: function hover(event) { this.session.pool.view.setCursor('pointer'); if (event.object.materials && !this.isSelected(event.object)) { var anim = event.object.animate({ materials: { meshes: [{ color: new THREE.Color(0x28d79f), opacity: 1 }] } }); if (event.object.__origProps === undefined) { event.object.__origProps = anim.getProperties(); } anim.start(0); } } /** * Called by selector when event is triggered. */ }, { key: 'unhover', value: function unhover(event) { if (event.object.materials && event.object.__origProps && !this.isSelected(event.object)) { event.object.animate(event.object.__origProps).start(500); } } /** * Highlight the selected object. Store original material for unhighlight. */ }, { key: 'select', value: function select(object) { if (object.materials) { var anim = object.animate({ materials: { meshes: [{ color: new THREE.Color(0xc23369), opacity: 1 }] } }); anim.start(500); } } /** * Unighlight the object using hover material. */ }, { key: 'unselect', value: function unselect(object) { if (this.view.interaction.hitsArray.length && object.materials) { object.animate({ materials: { meshes: [{ color: new THREE.Color(0x28d79f), opacity: 1 }] } }).start(0); } else if (object.materials && object.__origProps) { object.animate(object.__origProps).start(0); } } /** * Called by selector when event is triggered. */ }, { key: 'clicked', value: function clicked(event) { if (this.shiftHandler.handled) return; if (this.isSelected(event.object)) { this.remove(event); } else { this.add(event); } } /** * Called by selector when event is triggered. */ }, { key: 'missed', value: function missed(event) { this.removeAll(true); } /** * Called by selector when event is triggered. */ }, { key: 'rendered', value: function rendered(event) {} /** * Check if object is already selected * @return TRUE if selected, FALSE otherwise */ }, { key: 'isSelected', value: function isSelected(object) { return this.selectedSet.has(object); } /** * Returns the selected ids in an array * @return selectedIds - Array with the selected ids */ }, { key: 'getSelectedIds', value: function getSelectedIds() { var iter = this.selectedSet.values(); var selectedIds = []; var item = iter.next(); while (item.value !== undefined) { selectedIds.push(item.id); item = iter.next(); } return selectedIds; } /** * Returns the selected elements in an array * @return selectedElements - Array with the selected elements */ }, { key: 'getSelectedElements', value: function getSelectedElements() { var iter = this.selectedSet.values(); var selectedElements = []; var item = iter.next(); while (item.value !== undefined) { selectedElements.push(item.value); item = iter.next(); } return selectedElements; } /** * Removes the given elements from the current selection. * @param {array} elements - elements to be removed from the selection. */ }, { key: 'unselectElements', value: function unselectElements(elements) { var _this4 = this; elements.forEach(function (element) { return _this4.remove({ object: element }); }); } }]); return ObjectSelector; }();