├── .gitignore ├── .DS_Store ├── Markup ├── core │ ├── package-lock.json │ ├── package.json │ ├── MarkupTypes.js │ ├── edit-actions │ │ ├── DeleteStamp.js │ │ ├── DeleteCloud.js │ │ ├── SetStyle.js │ │ ├── DeleteFreehand.js │ │ ├── DeleteRectangle.js │ │ ├── DeleteText.js │ │ ├── DeleteHighlight.js │ │ ├── DeletePolyline.js │ │ ├── DeletePolycloud.js │ │ ├── DeleteCallout.js │ │ ├── DeleteArrow.js │ │ ├── SetText.js │ │ ├── CloneMarkup.js │ │ ├── CreateStamp.js │ │ ├── CreateCloud.js │ │ ├── SetCallout.js │ │ ├── DeleteDimension.js │ │ ├── CreateText.js │ │ ├── CreateRectangle.js │ │ ├── CreateDimension.js │ │ ├── CreateFreehand.js │ │ ├── CreateHighlight.js │ │ ├── CreateArrow.js │ │ ├── SetRotation.js │ │ ├── SetPosition.js │ │ ├── CreatePolyline.js │ │ ├── CreatePolycloud.js │ │ ├── DeleteCircle.js │ │ ├── CreateCallout.js │ │ ├── SetPolyline.js │ │ ├── SetPolycloud.js │ │ ├── SetFreehand.js │ │ ├── SetHighlight.js │ │ ├── SetStamp.js │ │ ├── SetSize.js │ │ ├── CreateCircle.js │ │ ├── SetCloud.js │ │ ├── SetRectangle.js │ │ ├── EditAction.js │ │ ├── SetDimension.js │ │ ├── SetArrow.js │ │ ├── SetCircle.js │ │ ├── EditActionGroup.js │ │ └── EditActionManager.js │ ├── MarkupFreehand.js │ ├── MarkupHighlight.js │ ├── EditModeManager.js │ ├── edit-modes │ │ ├── EditModeFreehand.js │ │ ├── BuiltinEditModes.js │ │ ├── EditModeHighlight.js │ │ ├── EditModeStamp.js │ │ ├── EditModeCloud.js │ │ ├── EditModeCircle.js │ │ ├── EditModeRectangle.js │ │ ├── EditModeArrow.js │ │ └── EditModePen.js │ ├── edit-clipboard │ │ └── Clipboard.js │ ├── Markups.css │ ├── DomElementStyle.js │ ├── MarkupCircle.js │ ├── MarkupRectangle.js │ ├── MarkupEvents.js │ ├── MarkupStamp.js │ ├── MarkupPolyLine.js │ ├── MarkupPen.js │ └── StyleUtils.js ├── gui │ └── MarkupsGui.css └── Markup.js ├── Measure ├── EventTypes.js ├── res │ └── icon-spinner-sm.svg ├── MagnifyingGlass.js ├── PolygonCentroid.js └── MeasurementsManager.js ├── LICENSE ├── README.md ├── webpack.js └── thirdparty └── resize-observer-polyfill └── ResizeObserver.min.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | build/Release 3 | node_modules/ 4 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wallabyway/forge-markup-measure-extensions/HEAD/.DS_Store -------------------------------------------------------------------------------- /Markup/core/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@adsk/markupscore", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1 5 | } 6 | -------------------------------------------------------------------------------- /Measure/EventTypes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Fired to start or stop mouse tracking 3 | * the mouse tracker starts and stop a mousetracker used by an application 4 | * this can be used to support autoscrolling in an application 5 | * @event SET_MOUSE_TRACKING 6 | * @property {string} [mode] - 'start' or 'stop' 7 | */ 8 | module.exports.SET_MOUSE_TRACKING = 'mouseTracking'; 9 | -------------------------------------------------------------------------------- /Markup/gui/MarkupsGui.css: -------------------------------------------------------------------------------- 1 | 2 | .adsk-icon-markup:before { 3 | content: "a"; 4 | } 5 | 6 | .lmv-markup-gui-toolbar { 7 | position: absolute; 8 | top: 0; 9 | margin: 5px 5px; 10 | color: #000000; 11 | } 12 | 13 | .lmv-markup-gui-toolbar-content > * { 14 | margin: 0 2px; 15 | } 16 | 17 | .lmv-markup-gui-style-options { 18 | display: inline-block; 19 | } -------------------------------------------------------------------------------- /Markup/core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@adsk/markupscore", 3 | "version": "1.0.0", 4 | "description": "core library for Markup class", 5 | "main": "./MarkupsCore.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "peerDependencies": { 10 | "resize-observer-polyfill": "^1.5.1" 11 | }, 12 | "private": true 13 | } 14 | -------------------------------------------------------------------------------- /Measure/res/icon-spinner-sm.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Asset 6 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Markup/core/MarkupTypes.js: -------------------------------------------------------------------------------- 1 | 2 | // These are all the supported markup types. 3 | 4 | export const MARKUP_TYPE_ARROW = "arrow"; 5 | export const MARKUP_TYPE_TEXT = "label"; 6 | export const MARKUP_TYPE_RECTANGLE = "rectangle"; 7 | export const MARKUP_TYPE_CIRCLE = "ellipse"; 8 | export const MARKUP_TYPE_CLOUD = "cloud"; 9 | export const MARKUP_TYPE_FREEHAND = "freehand"; 10 | export const MARKUP_TYPE_HIGHLIGHT = "highlight"; 11 | export const MARKUP_TYPE_POLYLINE = "polyline"; 12 | export const MARKUP_TYPE_POLYCLOUD = "polycloud"; 13 | export const MARKUP_TYPE_CALLOUT = "callout"; 14 | export const MARKUP_TYPE_DIMENSION = "dimension"; 15 | export const MARKUP_TYPE_STAMP = "stamp"; -------------------------------------------------------------------------------- /Markup/core/edit-actions/DeleteStamp.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | import { CreateStamp } from './CreateStamp'; 5 | 6 | export { DeleteStamp }; 7 | 8 | class DeleteStamp extends EditAction { 9 | constructor(editor, stamp) { 10 | super(editor, 'DELETE-STAMP', stamp.id); 11 | 12 | this.createStamp = new CreateStamp( 13 | editor, 14 | stamp.id, 15 | stamp.position, 16 | stamp.size, 17 | stamp.rotation, 18 | stamp.getStyle() 19 | ); 20 | } 21 | 22 | redo() { 23 | this.createStamp.undo(); 24 | } 25 | 26 | undo() { 27 | this.createStamp.redo(); 28 | } 29 | } -------------------------------------------------------------------------------- /Markup/core/MarkupFreehand.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { MarkupPen } from './MarkupPen'; 4 | import * as MarkupTypes from './MarkupTypes'; 5 | import { EditModeFreehand } from './edit-modes/EditModeFreehand'; 6 | 7 | 8 | /** 9 | * 10 | * @param id 11 | * @param editor 12 | * @constructor 13 | */ 14 | export function MarkupFreehand(id, editor) { 15 | 16 | MarkupPen.call(this, id, editor); 17 | this.type = MarkupTypes.MARKUP_TYPE_FREEHAND; 18 | } 19 | 20 | MarkupFreehand.prototype = Object.create(MarkupPen.prototype); 21 | MarkupFreehand.prototype.constructor = MarkupFreehand; 22 | 23 | var proto = MarkupFreehand.prototype; 24 | 25 | proto.getEditMode = function() { 26 | 27 | return new EditModeFreehand(this.editor); 28 | }; 29 | 30 | -------------------------------------------------------------------------------- /Markup/core/MarkupHighlight.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { MarkupPen } from './MarkupPen'; 4 | import * as MarkupTypes from './MarkupTypes'; 5 | import { EditModeHighlight } from './edit-modes/EditModeHighlight'; 6 | 7 | /** 8 | * 9 | * @param id 10 | * @param editor 11 | * @constructor 12 | */ 13 | export function MarkupHighlight(id, editor) { 14 | 15 | MarkupPen.call(this, id, editor); 16 | this.type = MarkupTypes.MARKUP_TYPE_HIGHLIGHT; 17 | } 18 | 19 | MarkupHighlight.prototype = Object.create(MarkupPen.prototype); 20 | MarkupHighlight.prototype.constructor = MarkupHighlight; 21 | 22 | var proto = MarkupHighlight.prototype; 23 | 24 | proto.getEditMode = function() { 25 | 26 | return new EditModeHighlight(this.editor); 27 | }; 28 | 29 | -------------------------------------------------------------------------------- /Markup/core/EditModeManager.js: -------------------------------------------------------------------------------- 1 | 2 | // Maps EditMode id (string) into a contructor/class 3 | var _editModes = {}; 4 | 5 | class EditModeManager { 6 | constructor(){ 7 | // nothing // 8 | } 9 | 10 | register(id, clazz) { 11 | if (id in _editModes) 12 | throw new Error(`EditMode with id (${id}) already registered.`); 13 | 14 | _editModes[id] = clazz; 15 | } 16 | 17 | unregister(id) { 18 | if (id in _editModes) 19 | delete _editModes[id]; 20 | } 21 | 22 | getClass(id) { 23 | return _editModes[id] || null; 24 | } 25 | 26 | getRegistered() { 27 | var ret = {}; 28 | for (var id in _editModes) { 29 | if (Object.prototype.hasOwnProperty.call(_editModes, id)) { 30 | ret[id] = _editModes[id]; 31 | } 32 | } 33 | return ret; // shallow copy. 34 | } 35 | } 36 | 37 | 38 | export var theEditModeManager = new EditModeManager(); -------------------------------------------------------------------------------- /Markup/core/edit-actions/DeleteCloud.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | import { CreateCloud } from './CreateCloud'; 5 | 6 | /** 7 | * 8 | * @param editor 9 | * @param cloud 10 | * @constructor 11 | */ 12 | export function DeleteCloud(editor, cloud) { 13 | 14 | EditAction.call(this, editor, 'DELETE-CLOUD', cloud.id); 15 | this.createCloud = new CreateCloud( 16 | editor, 17 | cloud.id, 18 | cloud.position, 19 | cloud.size, 20 | cloud.rotation, 21 | cloud.getStyle()); 22 | } 23 | 24 | DeleteCloud.prototype = Object.create(EditAction.prototype); 25 | DeleteCloud.prototype.constructor = DeleteCloud; 26 | 27 | var proto = DeleteCloud.prototype; 28 | 29 | proto.redo = function() { 30 | 31 | this.createCloud.undo(); 32 | }; 33 | 34 | proto.undo = function() { 35 | 36 | this.createCloud.redo(); 37 | }; 38 | 39 | -------------------------------------------------------------------------------- /Markup/core/edit-actions/SetStyle.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | import { cloneStyle } from '../StyleUtils'; 5 | 6 | /** 7 | * 8 | * @param editor 9 | * @param markup 10 | * @param style 11 | * @constructor 12 | */ 13 | export function SetStyle(editor, markup, style) { 14 | 15 | EditAction.call(this, editor, 'SET-STYLE', markup.id); 16 | 17 | this.newStyle = cloneStyle(style); 18 | this.oldStyle = markup.getStyle(); 19 | } 20 | 21 | SetStyle.prototype = Object.create(EditAction.prototype); 22 | SetStyle.prototype.constructor = SetStyle; 23 | 24 | var proto = SetStyle.prototype; 25 | 26 | proto.redo = function() { 27 | 28 | var markup = this.editor.getMarkup(this.targetId); 29 | markup && markup.setStyle(this.newStyle); 30 | }; 31 | 32 | proto.undo = function() { 33 | 34 | var markup = this.editor.getMarkup(this.targetId); 35 | markup && markup.setStyle(this.oldStyle); 36 | }; 37 | -------------------------------------------------------------------------------- /Markup/core/edit-actions/DeleteFreehand.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | import { CreateFreehand } from './CreateFreehand'; 5 | 6 | /** 7 | * 8 | * @param editor 9 | * @param freehand 10 | * @constructor 11 | */ 12 | export function DeleteFreehand(editor, freehand) { 13 | EditAction.call(this, editor, 'DELETE-FREEHAND', freehand.id); 14 | this.createFreehand = new CreateFreehand( 15 | editor, 16 | freehand.id, 17 | freehand.position, 18 | freehand.size, 19 | freehand.rotation, 20 | freehand.locations, 21 | freehand.getStyle()); 22 | } 23 | 24 | DeleteFreehand.prototype = Object.create(EditAction.prototype); 25 | DeleteFreehand.prototype.constructor = DeleteFreehand; 26 | 27 | var proto = DeleteFreehand.prototype; 28 | 29 | proto.redo = function() { 30 | 31 | this.createFreehand.undo(); 32 | }; 33 | 34 | proto.undo = function() { 35 | 36 | this.createFreehand.redo(); 37 | }; 38 | -------------------------------------------------------------------------------- /Markup/core/edit-actions/DeleteRectangle.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | import { CreateRectangle } from './CreateRectangle'; 5 | 6 | /** 7 | * 8 | * @param editor 9 | * @param rectangle 10 | * @constructor 11 | */ 12 | export var DeleteRectangle = function(editor, rectangle) { 13 | 14 | EditAction.call(this, editor, 'DELETE-RECTANGLE', rectangle.id); 15 | this.createRectangle = new CreateRectangle( 16 | editor, 17 | rectangle.id, 18 | rectangle.position, 19 | rectangle.size, 20 | rectangle.rotation, 21 | rectangle.getStyle()); 22 | }; 23 | 24 | DeleteRectangle.prototype = Object.create(EditAction.prototype); 25 | DeleteRectangle.prototype.constructor = DeleteRectangle; 26 | 27 | var proto = DeleteRectangle.prototype; 28 | 29 | proto.redo = function() { 30 | 31 | this.createRectangle.undo(); 32 | }; 33 | 34 | proto.undo = function() { 35 | 36 | this.createRectangle.redo(); 37 | }; 38 | -------------------------------------------------------------------------------- /Markup/core/edit-actions/DeleteText.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | import { CreateText } from './CreateText'; 5 | 6 | /** 7 | * 8 | * @param editor 9 | * @param text 10 | * @constructor 11 | */ 12 | export function DeleteText(editor, text) { 13 | 14 | EditAction.call(this, editor, 'DELETE-TEXT', text.id); 15 | 16 | var position = {x: text.position.x, y: text.position.y}; 17 | var size = {x: text.size.x, y: text.size.y}; 18 | 19 | this.createText = new CreateText( 20 | editor, 21 | text.id, 22 | position, 23 | size, 24 | text.getText(), 25 | text.getStyle()); 26 | } 27 | 28 | DeleteText.prototype = Object.create(EditAction.prototype); 29 | DeleteText.prototype.constructor = DeleteText; 30 | 31 | var proto = DeleteText.prototype; 32 | 33 | proto.redo = function() { 34 | 35 | this.createText.undo(); 36 | }; 37 | 38 | proto.undo = function() { 39 | 40 | this.createText.redo(); 41 | }; 42 | -------------------------------------------------------------------------------- /Markup/core/edit-actions/DeleteHighlight.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | import { CreateHighlight } from './CreateHighlight'; 5 | 6 | /** 7 | * 8 | * @param editor 9 | * @param highlight 10 | * @constructor 11 | */ 12 | export function DeleteHighlight(editor, highlight) { 13 | EditAction.call(this, editor, 'DELETE-HIGHLIGHT', highlight.id); 14 | this.createHighlight = new CreateHighlight( 15 | editor, 16 | highlight.id, 17 | highlight.position, 18 | highlight.size, 19 | highlight.rotation, 20 | highlight.locations, 21 | highlight.getStyle()); 22 | } 23 | 24 | DeleteHighlight.prototype = Object.create(EditAction.prototype); 25 | DeleteHighlight.prototype.constructor = DeleteHighlight; 26 | 27 | var proto = DeleteHighlight.prototype; 28 | 29 | proto.redo = function() { 30 | 31 | this.createHighlight.undo(); 32 | }; 33 | 34 | proto.undo = function() { 35 | 36 | this.createHighlight.redo(); 37 | }; 38 | -------------------------------------------------------------------------------- /Markup/core/edit-actions/DeletePolyline.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | import { CreatePolyline } from './CreatePolyline'; 5 | 6 | /** 7 | * 8 | * @param editor 9 | * @param polyline 10 | * @constructor 11 | */ 12 | export function DeletePolyline(editor, polyline) { 13 | 14 | EditAction.call(this, editor, 'DELETE-POLYLINE', polyline.id); 15 | this.createPolyline = new CreatePolyline( 16 | editor, 17 | polyline.id, 18 | polyline.position, 19 | polyline.size, 20 | polyline.rotation, 21 | polyline.locations, 22 | polyline.getStyle(), 23 | polyline.closed); 24 | } 25 | 26 | DeletePolyline.prototype = Object.create(EditAction.prototype); 27 | DeletePolyline.prototype.constructor = DeletePolyline; 28 | 29 | var proto = DeletePolyline.prototype; 30 | 31 | proto.redo = function() { 32 | 33 | this.createPolyline.undo(); 34 | }; 35 | 36 | proto.undo = function() { 37 | 38 | this.createPolyline.redo(); 39 | }; 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 wallabyway 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Markup/core/edit-actions/DeletePolycloud.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | import { CreatePolycloud } from './CreatePolycloud'; 5 | 6 | /** 7 | * 8 | * @param editor 9 | * @param polycloud 10 | * @constructor 11 | */ 12 | export function DeletePolycloud(editor, polycloud) { 13 | 14 | EditAction.call(this, editor, 'DELETE-POLYCLOUD', polycloud.id); 15 | this.createPolycloud = new CreatePolycloud( 16 | editor, 17 | polycloud.id, 18 | polycloud.position, 19 | polycloud.size, 20 | polycloud.rotation, 21 | polycloud.locations, 22 | polycloud.getStyle(), 23 | polycloud.closed); 24 | } 25 | 26 | DeletePolycloud.prototype = Object.create(EditAction.prototype); 27 | DeletePolycloud.prototype.constructor = DeletePolycloud; 28 | 29 | var proto = DeletePolycloud.prototype; 30 | 31 | proto.redo = function() { 32 | 33 | this.createPolycloud.undo(); 34 | }; 35 | 36 | proto.undo = function() { 37 | 38 | this.createPolycloud.redo(); 39 | }; 40 | -------------------------------------------------------------------------------- /Markup/core/edit-actions/DeleteCallout.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | import { CreateCallout } from './CreateCallout'; 5 | 6 | /** 7 | * 8 | * @param editor 9 | * @param text 10 | * @constructor 11 | */ 12 | export function DeleteCallout(editor, callout) { 13 | 14 | EditAction.call(this, editor, 'DELETE-CALLOUT', callout.id); 15 | 16 | var position = {x: callout.position.x, y: callout.position.y}; 17 | var size = {x: callout.size.x, y: callout.size.y}; 18 | 19 | this.createCallout = new CreateCallout( 20 | editor, 21 | callout.id, 22 | position, 23 | size, 24 | callout.getText(), 25 | callout.getStyle(), 26 | callout.isFrameUsed); 27 | } 28 | 29 | DeleteCallout.prototype = Object.create(EditAction.prototype); 30 | DeleteCallout.prototype.constructor = DeleteCallout; 31 | 32 | var proto = DeleteCallout.prototype; 33 | 34 | proto.redo = function() { 35 | 36 | this.createCallout.undo(); 37 | }; 38 | 39 | proto.undo = function() { 40 | 41 | this.createCallout.redo(); 42 | }; 43 | 44 | -------------------------------------------------------------------------------- /Markup/core/edit-actions/DeleteArrow.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | import { CreateArrow } from './CreateArrow'; 5 | 6 | /** 7 | * 8 | * @param editor 9 | * @param arrow 10 | * @constructor 11 | */ 12 | export function DeleteArrow(editor, arrow) { 13 | 14 | // Confusing naming here. Arrow.tail is the starting point of the arrow, 15 | // and arrow.head is the final point. In CreateArrow the head argument 16 | // is the first point of the arrow and the tail argument is the second 17 | // point of the argument. So construct CreateArrow with the tail before 18 | // the head. 19 | EditAction.call(this, editor, 'DELETE-ARROW', arrow.id); 20 | this.createArrow = new CreateArrow( 21 | editor, 22 | arrow.id, 23 | arrow.tail, 24 | arrow.head, 25 | arrow.getStyle()); 26 | } 27 | 28 | DeleteArrow.prototype = Object.create(EditAction.prototype); 29 | DeleteArrow.prototype.constructor = DeleteArrow; 30 | 31 | var proto = DeleteArrow.prototype; 32 | 33 | proto.redo = function() { 34 | 35 | this.createArrow.undo(); 36 | }; 37 | 38 | proto.undo = function() { 39 | 40 | this.createArrow.redo(); 41 | }; 42 | -------------------------------------------------------------------------------- /Markup/core/edit-actions/SetText.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | 5 | /** 6 | * 7 | * @param editor 8 | * @param markup 9 | * @param position 10 | * @param size 11 | * @param text 12 | * @constructor 13 | */ 14 | export function SetText(editor, markup, position, size, text) { 15 | 16 | EditAction.call(this, editor, 'SET-TEXT', markup.id); 17 | 18 | this.newPosition = {x: position.x, y: position.y}; 19 | this.oldPosition = {x: markup.position.x, y: markup.position.y}; 20 | this.newSize = {x: size.x, y: size.y}; 21 | this.oldSize = {x: markup.size.x, y: markup.size.y}; 22 | this.newText = text; 23 | this.oldText = markup.getText(); 24 | } 25 | 26 | SetText.prototype = Object.create(EditAction.prototype); 27 | SetText.prototype.constructor = SetText; 28 | 29 | var proto = SetText.prototype; 30 | 31 | proto.redo = function() { 32 | 33 | var text = this.editor.getMarkup(this.targetId); 34 | text && text.set(this.newPosition, this.newSize, this.newText); 35 | }; 36 | 37 | proto.undo = function() { 38 | 39 | var text = this.editor.getMarkup(this.targetId); 40 | text && text.set(this.oldPosition, this.oldSize, this.oldText); 41 | }; 42 | -------------------------------------------------------------------------------- /Markup/core/edit-actions/CloneMarkup.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | 5 | /** 6 | * 7 | * @param editor 8 | * @param id 9 | * @param markup 10 | * @param position 11 | * @constructor 12 | */ 13 | export function CloneMarkup(editor, id, markup, position) { 14 | 15 | EditAction.call(this, editor, 'CLONE-MARKUP', id); 16 | 17 | this.clone = markup.clone(); 18 | this.clone.id = id; 19 | this.position = {x: position.x, y: position.y}; 20 | } 21 | 22 | CloneMarkup.prototype = Object.create(EditAction.prototype); 23 | CloneMarkup.prototype.constructor = CloneMarkup; 24 | 25 | var proto = CloneMarkup.prototype; 26 | 27 | proto.redo = function() { 28 | 29 | var editor = this.editor; 30 | var clone = this.clone; 31 | var position = this.position; 32 | 33 | if (editor.getMarkup(this.targetId)) { 34 | return; 35 | } 36 | 37 | var markup = clone.clone(); 38 | markup.setPosition(position.x, position.y); 39 | 40 | editor.addMarkup(markup); 41 | }; 42 | 43 | proto.undo = function() { 44 | 45 | var markup = this.editor.getMarkup(this.targetId); 46 | markup && this.editor.removeMarkup(markup); 47 | }; 48 | 49 | 50 | -------------------------------------------------------------------------------- /Markup/core/edit-actions/CreateStamp.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | import { MarkupStamp } from '../MarkupStamp'; 5 | import { cloneStyle } from '../StyleUtils'; 6 | 7 | export { CreateStamp }; 8 | 9 | /** 10 | * @constructor 11 | * 12 | * @param editor 13 | * @param id 14 | * @param position 15 | * @param size 16 | * @param style 17 | * @param {string} svg 18 | */ 19 | 20 | class CreateStamp extends EditAction { 21 | constructor(editor, id, position, size, rotation, style, svgData) { 22 | super(editor, 'CREATE-STAMP', id); 23 | 24 | this.selectOnExecution = false; 25 | this.position = {x: position.x, y: position.y}; 26 | this.size = {x: size.x, y: size.y}; 27 | this.rotation = rotation; 28 | this.style = cloneStyle(style); 29 | this.svgData = svgData; 30 | } 31 | 32 | redo() { 33 | const stamp = new MarkupStamp(this.targetId, this.editor, this.svgData); 34 | 35 | this.editor.addMarkup(stamp); 36 | 37 | stamp.setSize(this.position, this.size.x, this.size.y); 38 | stamp.setRotation(this.rotation); 39 | stamp.setStyle(this.style); 40 | } 41 | 42 | undo() { 43 | const markup = this.editor.getMarkup(this.targetId); 44 | this.editor.removeMarkup(markup); 45 | } 46 | } 47 | 48 | -------------------------------------------------------------------------------- /Markup/core/edit-actions/CreateCloud.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | import { MarkupCloud } from '../MarkupCloud'; 5 | import { cloneStyle } from '../StyleUtils'; 6 | 7 | /** 8 | * 9 | * @param editor 10 | * @param id 11 | * @param position 12 | * @param size 13 | * @param rotation 14 | * @param style 15 | * @constructor 16 | */ 17 | export function CreateCloud(editor, id, position, size, rotation, style) { 18 | 19 | EditAction.call(this, editor, 'CREATE-CLOUD', id); 20 | 21 | this.selectOnExecution = false; 22 | this.position = {x: position.x, y: position.y}; 23 | this.size = {x: size.x, y: size.y}; 24 | this.rotation = rotation; 25 | this.style = cloneStyle(style); 26 | } 27 | 28 | CreateCloud.prototype = Object.create(EditAction.prototype); 29 | CreateCloud.prototype.constructor = CreateCloud; 30 | 31 | var proto = CreateCloud.prototype; 32 | 33 | proto.redo = function() { 34 | 35 | var editor = this.editor; 36 | var cloud = new MarkupCloud(this.targetId, editor); 37 | 38 | editor.addMarkup(cloud); 39 | 40 | cloud.set(this.position, this.size); 41 | cloud.setRotation(this.rotation); 42 | cloud.setStyle(this.style); 43 | }; 44 | 45 | proto.undo = function() { 46 | 47 | var markup = this.editor.getMarkup(this.targetId); 48 | markup && this.editor.removeMarkup(markup); 49 | }; 50 | -------------------------------------------------------------------------------- /Markup/core/edit-actions/SetCallout.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | 5 | /** 6 | * 7 | * @param editor 8 | * @param markup 9 | * @param position 10 | * @param size 11 | * @param text 12 | * @constructor 13 | */ 14 | export function SetCallout(editor, markup, position, size, text, isFrameUsed) { 15 | 16 | EditAction.call(this, editor, 'SET-CALLOUT', markup.id); 17 | 18 | this.newPosition = {x: position.x, y: position.y}; 19 | this.oldPosition = {x: markup.position.x, y: markup.position.y}; 20 | this.newSize = {x: size.x, y: size.y}; 21 | this.oldSize = {x: markup.size.x, y: markup.size.y}; 22 | this.newText = text; 23 | this.oldText = markup.getText(); 24 | this.newIsFrameUsed = isFrameUsed; 25 | this.oldIsFrameUsed = markup.isFrameUsed; 26 | } 27 | 28 | SetCallout.prototype = Object.create(EditAction.prototype); 29 | SetCallout.prototype.constructor = SetCallout; 30 | 31 | var proto = SetCallout.prototype; 32 | 33 | proto.redo = function() { 34 | 35 | var callout = this.editor.getMarkup(this.targetId); 36 | callout && callout.set(this.newPosition, this.newSize, this.newText, this.newIsFrameUsed); 37 | }; 38 | 39 | proto.undo = function() { 40 | 41 | var callout = this.editor.getMarkup(this.targetId); 42 | callout && callout.set(this.oldPosition, this.oldSize, this.oldText, this.oldIsFrameUsed); 43 | }; 44 | -------------------------------------------------------------------------------- /Markup/core/edit-actions/DeleteDimension.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | import { CreateDimension } from './CreateDimension'; 5 | 6 | /** 7 | * 8 | * @param editor 9 | * @param dimension 10 | * @constructor 11 | */ 12 | export function DeleteDimension(editor, dimension) { 13 | 14 | // Confusing naming here. Dimension.secondAnchor is the starting point of the dimension, 15 | // and dimension.firstAnchor is the final point. In CreateDimension the firstAnchor argument 16 | // is the first point of the dimension and the secondAnchor argument is the second 17 | // point of the argument. So construct CreateDimension with the secondAnchor before 18 | // the firstAnchor. 19 | EditAction.call(this, editor, 'DELETE-DIMENSION', dimension.id); 20 | this.createDimension = new CreateDimension( 21 | editor, 22 | dimension.id, 23 | dimension.secondAnchor, 24 | dimension.firstAnchor, 25 | dimension.currentText, 26 | dimension.getStyle()); 27 | } 28 | 29 | DeleteDimension.prototype = Object.create(EditAction.prototype); 30 | DeleteDimension.prototype.constructor = DeleteDimension; 31 | 32 | var proto = DeleteDimension.prototype; 33 | 34 | proto.redo = function() { 35 | 36 | this.createDimension.undo(); 37 | }; 38 | 39 | proto.undo = function() { 40 | 41 | this.createDimension.redo(); 42 | }; 43 | 44 | 45 | -------------------------------------------------------------------------------- /Markup/core/edit-actions/CreateText.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | import { MarkupText } from '../MarkupText'; 5 | import { cloneStyle } from '../StyleUtils'; 6 | 7 | /** 8 | * 9 | * @param editor 10 | * @param id 11 | * @param position 12 | * @param size 13 | * @param text 14 | * @param style 15 | * @constructor 16 | */ 17 | export function CreateText(editor, id, position, size, text, style ) { 18 | 19 | EditAction.call(this, editor, 'CREATE-TEXT', id); 20 | 21 | this.text = text; 22 | this.position = {x: position.x, y: position.y}; 23 | this.size = {x: size.x, y: size.y}; 24 | this.style = cloneStyle(style); 25 | } 26 | 27 | CreateText.prototype = Object.create(EditAction.prototype); 28 | CreateText.prototype.constructor = CreateText; 29 | 30 | var proto = CreateText.prototype; 31 | 32 | proto.redo = function () { 33 | 34 | var editor = this.editor; 35 | var position = this.position; 36 | var size = this.size; 37 | 38 | var text = new MarkupText(this.targetId, editor, size); 39 | 40 | editor.addMarkup(text); 41 | 42 | text.set(position, size, this.text); 43 | text.setStyle(this.style); 44 | }; 45 | 46 | proto.undo = function () { 47 | 48 | var markup = this.editor.getMarkup(this.targetId); 49 | if (markup) { 50 | this.editor.removeMarkup(markup); 51 | markup.destroy(); 52 | } 53 | }; 54 | 55 | 56 | -------------------------------------------------------------------------------- /Markup/core/edit-actions/CreateRectangle.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | import { MarkupRectangle } from '../MarkupRectangle'; 5 | import { cloneStyle } from '../StyleUtils'; 6 | 7 | /** 8 | * 9 | * @param editor 10 | * @param id 11 | * @param position 12 | * @param size 13 | * @param rotation 14 | * @param style 15 | * @constructor 16 | */ 17 | export function CreateRectangle(editor, id, position, size, rotation, style) { 18 | 19 | EditAction.call(this, editor, 'CREATE-RECTANGLE', id); 20 | 21 | this.selectOnExecution = false; 22 | this.position = {x: position.x, y: position.y}; 23 | this.size = {x: size.x, y: size.y}; 24 | this.rotation = rotation; 25 | this.style = cloneStyle(style); 26 | } 27 | 28 | CreateRectangle.prototype = Object.create(EditAction.prototype); 29 | CreateRectangle.prototype.constructor = CreateRectangle; 30 | 31 | var proto = CreateRectangle.prototype; 32 | 33 | proto.redo = function() { 34 | 35 | var editor = this.editor; 36 | var rectangle = new MarkupRectangle(this.targetId, editor); 37 | 38 | editor.addMarkup(rectangle); 39 | 40 | rectangle.set(this.position, this.size); 41 | rectangle.setRotation(this.rotation); 42 | rectangle.setStyle(this.style); 43 | }; 44 | 45 | proto.undo = function() { 46 | 47 | var markup = this.editor.getMarkup(this.targetId); 48 | markup && this.editor.removeMarkup(markup); 49 | }; 50 | 51 | -------------------------------------------------------------------------------- /Markup/core/edit-actions/CreateDimension.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | import { MarkupDimension } from '../MarkupDimension'; 5 | import { cloneStyle } from '../StyleUtils'; 6 | 7 | /** 8 | * @constructor 9 | */ 10 | export function CreateDimension(editor, id, firstAnchor, secondAnchor, text, style) { 11 | 12 | EditAction.call(this, editor, 'CREATE-DIMENSION', id); 13 | 14 | this.selectOnExecution = false; 15 | this.secondAnchor = secondAnchor; 16 | this.firstAnchor = firstAnchor; 17 | this.text = text; 18 | this.style = cloneStyle(style); 19 | } 20 | 21 | CreateDimension.prototype = Object.create(EditAction.prototype); 22 | CreateDimension.prototype.constructor = CreateDimension; 23 | 24 | var proto = CreateDimension.prototype; 25 | 26 | proto.redo = function() { 27 | 28 | var editor = this.editor; 29 | var dimension = new MarkupDimension(this.targetId, editor); 30 | 31 | editor.addMarkup(dimension); 32 | 33 | // Don't display the dimension markup when there is only one Anchor (First click, before mouse move). 34 | if (this.secondAnchor) { 35 | dimension.set(this.firstAnchor.x, this.firstAnchor.y, this.secondAnchor.x, this.secondAnchor.y, this.text); 36 | dimension.setStyle(this.style); 37 | } 38 | }; 39 | 40 | proto.undo = function() { 41 | 42 | var markup = this.editor.getMarkup(this.targetId); 43 | markup && this.editor.removeMarkup(markup); 44 | }; 45 | 46 | 47 | -------------------------------------------------------------------------------- /Markup/core/edit-modes/EditModeFreehand.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditModePen } from './EditModePen'; 4 | import { DeleteFreehand } from '../edit-actions/DeleteFreehand'; 5 | import { CreateFreehand } from '../edit-actions/CreateFreehand'; 6 | import { SetFreehand } from '../edit-actions/SetFreehand'; 7 | import * as MarkupTypes from '../MarkupTypes'; 8 | 9 | /** 10 | * 11 | * @param editor 12 | * @constructor 13 | */ 14 | export function EditModeFreehand(editor) { 15 | 16 | var styleAttributes = ['stroke-width', 'stroke-color', 'stroke-opacity']; 17 | EditModePen.call(this, editor, MarkupTypes.MARKUP_TYPE_FREEHAND, styleAttributes); 18 | } 19 | 20 | EditModeFreehand.prototype = Object.create(EditModePen.prototype); 21 | EditModeFreehand.prototype.constructor = EditModeFreehand; 22 | 23 | var proto = EditModeFreehand.prototype; 24 | 25 | proto.createPen = function(markupId, position, size, rotation, locations) { 26 | return new CreateFreehand(this.editor, 27 | markupId, 28 | position, 29 | size, 30 | rotation, 31 | locations, 32 | this.style); 33 | }; 34 | 35 | proto.deletePen = function(markup) { 36 | return new DeleteFreehand(this.editor, markup); 37 | }; 38 | 39 | proto.setPen = function(position, size, locations, isAbsoluteCoords) { 40 | return new SetFreehand(this.editor, 41 | this.selectedMarkup, 42 | position, 43 | size, 44 | locations, 45 | isAbsoluteCoords); 46 | }; 47 | 48 | -------------------------------------------------------------------------------- /Markup/core/edit-actions/CreateFreehand.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | import { MarkupFreehand } from '../MarkupFreehand'; 5 | import { cloneStyle } from '../StyleUtils'; 6 | 7 | /** 8 | * 9 | * @param editor 10 | * @param id 11 | * @param position 12 | * @param size 13 | * @param rotation 14 | * @param locations 15 | * @param style 16 | * @constructor 17 | */ 18 | export function CreateFreehand(editor, id, position, size, rotation, locations, style) { 19 | 20 | EditAction.call(this, editor, 'CREATE-FREEHAND', id); 21 | 22 | this.selectOnExecution = false; 23 | this.position = position; 24 | this.size = size; 25 | this.rotation = rotation; 26 | this.movements = locations.slice(0); 27 | this.style = cloneStyle(style); 28 | } 29 | 30 | CreateFreehand.prototype = Object.create(EditAction.prototype); 31 | CreateFreehand.prototype.constructor = CreateFreehand; 32 | 33 | var proto = CreateFreehand.prototype; 34 | 35 | proto.redo = function() { 36 | 37 | var editor = this.editor; 38 | var freehand = new MarkupFreehand(this.targetId, editor); 39 | 40 | editor.addMarkup(freehand); 41 | 42 | freehand.set(this.position, this.size, this.movements, false); 43 | freehand.setRotation(this.rotation); 44 | freehand.setStyle(this.style); 45 | }; 46 | 47 | proto.undo = function() { 48 | 49 | var markup = this.editor.getMarkup(this.targetId); 50 | markup && this.editor.removeMarkup(markup); 51 | }; 52 | 53 | -------------------------------------------------------------------------------- /Markup/core/edit-actions/CreateHighlight.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | import { MarkupHighlight } from '../MarkupHighlight'; 5 | import { cloneStyle } from '../StyleUtils'; 6 | 7 | /** 8 | * 9 | * @param editor 10 | * @param id 11 | * @param position 12 | * @param size 13 | * @param rotation 14 | * @param locations 15 | * @param style 16 | * @constructor 17 | */ 18 | export function CreateHighlight(editor, id, position, size, rotation, locations, style) { 19 | 20 | EditAction.call(this, editor, 'CREATE-HIGHLIGHT', id); 21 | 22 | this.selectOnExecution = false; 23 | this.position = position; 24 | this.size = size; 25 | this.rotation = rotation; 26 | this.movements = locations.slice(0); 27 | this.style = cloneStyle(style); 28 | } 29 | 30 | CreateHighlight.prototype = Object.create(EditAction.prototype); 31 | CreateHighlight.prototype.constructor = CreateHighlight; 32 | 33 | var proto = CreateHighlight.prototype; 34 | 35 | proto.redo = function() { 36 | 37 | var editor = this.editor; 38 | var highlight = new MarkupHighlight(this.targetId, editor); 39 | 40 | editor.addMarkup(highlight); 41 | 42 | highlight.set(this.position, this.size, this.movements, false); 43 | highlight.setRotation(this.rotation); 44 | highlight.setStyle(this.style); 45 | }; 46 | 47 | proto.undo = function() { 48 | 49 | var markup = this.editor.getMarkup(this.targetId); 50 | markup && this.editor.removeMarkup(markup); 51 | }; 52 | 53 | 54 | -------------------------------------------------------------------------------- /Markup/core/edit-actions/CreateArrow.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | import { MarkupArrow } from '../MarkupArrow'; 5 | import { cloneStyle } from '../StyleUtils'; 6 | 7 | /** 8 | * @constructor 9 | */ 10 | export function CreateArrow(editor, id, head, tail, style) { 11 | 12 | EditAction.call(this, editor, 'CREATE-ARROW', id); 13 | 14 | this.selectOnExecution = false; 15 | this.tail = tail; 16 | this.head = head; 17 | this.style = cloneStyle(style); 18 | } 19 | 20 | CreateArrow.prototype = Object.create(EditAction.prototype); 21 | CreateArrow.prototype.constructor = CreateArrow; 22 | 23 | var proto = CreateArrow.prototype; 24 | 25 | proto.redo = function() { 26 | 27 | var editor = this.editor; 28 | var arrow = new MarkupArrow(this.targetId, editor); 29 | 30 | editor.addMarkup(arrow); 31 | 32 | // Confusing naming here. in arrow.set the first two numbers are 33 | // the point you drag from and the second two are the point you 34 | // drag to. So the head point is actually where the tail of the 35 | // arrow is positioned and the tail point is the head is positioned. 36 | 37 | //TODO: In MarkupArrow "set" function has tail x, tail y, head x, head y but used here in the opposite way 38 | arrow.set(this.head.x, this.head.y, this.tail.x, this.tail.y); 39 | arrow.setStyle(this.style); 40 | }; 41 | 42 | proto.undo = function() { 43 | 44 | var markup = this.editor.getMarkup(this.targetId); 45 | markup && this.editor.removeMarkup(markup); 46 | }; 47 | 48 | -------------------------------------------------------------------------------- /Markup/core/edit-actions/SetRotation.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | 5 | /** 6 | * 7 | * @param editor 8 | * @param markup 9 | * @param angle 10 | * @constructor 11 | */ 12 | export function SetRotation(editor, markup, angle) { 13 | 14 | EditAction.call(this, editor, 'SET-ROTATION', markup.id); 15 | 16 | var curAngle = markup.getRotation(); 17 | 18 | this.newRotation = {angle: angle}; 19 | this.oldRotation = {angle: curAngle}; 20 | } 21 | 22 | SetRotation.prototype = Object.create(EditAction.prototype); 23 | SetRotation.prototype.constructor = SetRotation; 24 | 25 | var proto = SetRotation.prototype; 26 | 27 | proto.redo = function() { 28 | 29 | var markup = this.editor.getMarkup(this.targetId); 30 | markup && markup.setRotation(this.newRotation.angle); 31 | }; 32 | 33 | proto.undo = function() { 34 | 35 | var markup = this.editor.getMarkup(this.targetId); 36 | markup && markup.setRotation(this.oldRotation.angle); 37 | }; 38 | 39 | /** 40 | * 41 | * @param action 42 | * @returns {boolean} 43 | */ 44 | proto.merge = function(action) { 45 | 46 | if (this.targetId === action.targetId && 47 | this.type === action.type) { 48 | 49 | this.newRotation = action.newRotation; 50 | return true; 51 | } 52 | return false; 53 | }; 54 | 55 | /** 56 | * @returns {boolean} 57 | */ 58 | proto.isIdentity = function() { 59 | 60 | return this.newRotation.angle === this.oldRotation.angle; 61 | }; 62 | 63 | -------------------------------------------------------------------------------- /Markup/core/edit-actions/SetPosition.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | 5 | export function SetPosition(editor, markup, position) { 6 | 7 | EditAction.call(this, editor, 'SET-POSITION', markup.id); 8 | 9 | this.newPosition = {x: position.x, y: position.y}; 10 | this.oldPosition = {x: markup.position.x, y: markup.position.y}; 11 | } 12 | 13 | SetPosition.prototype = Object.create(EditAction.prototype); 14 | SetPosition.prototype.constructor = SetPosition; 15 | 16 | var proto = SetPosition.prototype; 17 | 18 | proto.redo = function() { 19 | 20 | var markup = this.editor.getMarkup(this.targetId); 21 | markup && markup.setPosition(this.newPosition.x, this.newPosition.y); 22 | }; 23 | 24 | proto.undo = function() { 25 | 26 | var markup = this.editor.getMarkup(this.targetId); 27 | markup && markup.setPosition(this.oldPosition.x, this.oldPosition.y); 28 | }; 29 | 30 | /** 31 | * 32 | * @param action 33 | * @returns {boolean} 34 | */ 35 | proto.merge = function(action) { 36 | 37 | if (this.targetId === action.targetId && 38 | this.type === action.type) { 39 | 40 | this.newPosition = action.newPosition; 41 | return true; 42 | } 43 | return false; 44 | }; 45 | 46 | /** 47 | * @returns {boolean} 48 | */ 49 | proto.isIdentity = function() { 50 | 51 | var newPosition = this.newPosition; 52 | var oldPosition = this.oldPosition; 53 | 54 | return newPosition.x === oldPosition.x && newPosition.y === oldPosition.y; 55 | }; 56 | 57 | -------------------------------------------------------------------------------- /Markup/core/edit-actions/CreatePolyline.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | import { MarkupPolyline } from '../MarkupPolyLine'; 5 | import { cloneStyle } from '../StyleUtils'; 6 | 7 | /** 8 | * 9 | * @param editor 10 | * @param id 11 | * @param position 12 | * @param size 13 | * @param rotation 14 | * @param locations 15 | * @param closed 16 | * @param style 17 | * @constructor 18 | */ 19 | export function CreatePolyline(editor, id, position, size, rotation, locations, style, closed) { 20 | 21 | EditAction.call(this, editor, 'CREATE-POLYLINE', id); 22 | 23 | this.selectOnExecution = false; 24 | this.position = position; 25 | this.size = size; 26 | this.rotation = rotation; 27 | this.movements = locations.concat(); 28 | this.closed = closed; 29 | this.style = cloneStyle(style); 30 | } 31 | 32 | CreatePolyline.prototype = Object.create(EditAction.prototype); 33 | CreatePolyline.prototype.constructor = CreatePolyline; 34 | 35 | var proto = CreatePolyline.prototype; 36 | 37 | proto.redo = function() { 38 | 39 | var editor = this.editor; 40 | var polyline = new MarkupPolyline(this.targetId, editor); 41 | 42 | editor.addMarkup(polyline); 43 | 44 | polyline.set(this.position, this.size, this.movements, this.closed); 45 | polyline.setRotation(this.rotation); 46 | polyline.setStyle(this.style); 47 | }; 48 | 49 | proto.undo = function() { 50 | 51 | var markup = this.editor.getMarkup(this.targetId); 52 | markup && this.editor.removeMarkup(markup); 53 | }; 54 | 55 | -------------------------------------------------------------------------------- /Markup/core/edit-clipboard/Clipboard.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { CloneMarkup } from '../edit-actions/CloneMarkup'; 4 | import { addTraitEventDispatcher } from '../MarkupsCoreUtils'; 5 | 6 | /** 7 | * 8 | * @param editor 9 | * @constructor 10 | */ 11 | export function Clipboard(editor) { 12 | 13 | this.editor = editor; 14 | this.content = null; 15 | this.pastePosition = {x:0, y: 0}; 16 | 17 | addTraitEventDispatcher(this); 18 | } 19 | 20 | var proto = Clipboard.prototype; 21 | 22 | proto.copy = function() { 23 | 24 | var selectedMarkup = this.editor.getSelection(); 25 | if(!selectedMarkup) { 26 | return; 27 | } 28 | 29 | this.content = selectedMarkup.clone(); 30 | this.pastePosition.x = selectedMarkup.position.x; 31 | this.pastePosition.y = selectedMarkup.position.y; 32 | }; 33 | 34 | proto.cut = function() { 35 | 36 | var selectedMarkup = this.editor.getSelection(); 37 | if(!selectedMarkup) { 38 | return; 39 | } 40 | 41 | this.copy(); 42 | this.editor.deleteMarkup(selectedMarkup); 43 | }; 44 | 45 | proto.paste = function() { 46 | 47 | var content = this.content; 48 | if(!content) { 49 | return; 50 | } 51 | 52 | var editor = this.editor; 53 | var position = this.pastePosition; 54 | var delta = editor.sizeFromClientToMarkups(20, 20); 55 | 56 | position.x += delta.x; 57 | position.y -= delta.y; 58 | 59 | var cloneMarkup = new CloneMarkup(editor, editor.getId(), content, position); 60 | cloneMarkup.execute(); 61 | }; 62 | -------------------------------------------------------------------------------- /Markup/core/edit-actions/CreatePolycloud.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | import { MarkupPolycloud } from '../MarkupPolycloud'; 5 | import { cloneStyle } from '../StyleUtils'; 6 | 7 | /** 8 | * 9 | * @param editor 10 | * @param id 11 | * @param position 12 | * @param size 13 | * @param rotation 14 | * @param locations 15 | * @param closed 16 | * @param style 17 | * @constructor 18 | */ 19 | export function CreatePolycloud(editor, id, position, size, rotation, locations, style, closed) { 20 | 21 | EditAction.call(this, editor, 'CREATE-POLYCLOUD', id); 22 | 23 | this.selectOnExecution = false; 24 | this.position = position; 25 | this.size = size; 26 | this.rotation = rotation; 27 | this.movements = locations.concat(); 28 | this.style = cloneStyle(style); 29 | this.closed = closed; 30 | } 31 | 32 | CreatePolycloud.prototype = Object.create(EditAction.prototype); 33 | CreatePolycloud.prototype.constructor = CreatePolycloud; 34 | 35 | var proto = CreatePolycloud.prototype; 36 | 37 | proto.redo = function() { 38 | 39 | var editor = this.editor; 40 | var polyline = new MarkupPolycloud(this.targetId, editor); 41 | 42 | editor.addMarkup(polyline); 43 | 44 | polyline.set(this.position, this.size, this.movements, this.closed); 45 | polyline.setRotation(this.rotation); 46 | polyline.setStyle(this.style); 47 | }; 48 | 49 | proto.undo = function() { 50 | 51 | var markup = this.editor.getMarkup(this.targetId); 52 | markup && this.editor.removeMarkup(markup); 53 | }; 54 | 55 | -------------------------------------------------------------------------------- /Markup/core/edit-actions/DeleteCircle.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | import { CreateCircle } from './CreateCircle'; 5 | 6 | /** 7 | * Markup delete circle action. 8 | * 9 | * Implements an {@link Autodesk.Viewing.Extensions.Markups.Core.EditAction|EditAction} 10 | * for deleting a Circle {@link Autodesk.Viewing.Extensions.Markups.Core.Markup|Markup}. 11 | * Included in documentation as an example of how to create 12 | * a specific EditAction that deals with Markup deletion. 13 | * Developers are encourage to look into this class's source code and copy 14 | * as much code as they need. Find link to source code below. 15 | * 16 | * @tutorial feature_markup 17 | * @constructor 18 | * @memberof Autodesk.Viewing.Extensions.Markups.Core 19 | * @extends Autodesk.Viewing.Extensions.Markups.Core.EditAction 20 | * 21 | * @param editor 22 | * @param circle 23 | */ 24 | export function DeleteCircle(editor, circle) { 25 | 26 | EditAction.call(this, editor, 'DELETE-CIRCLE', circle.id); 27 | this.createCircle = new CreateCircle( 28 | editor, 29 | circle.id, 30 | circle.position, 31 | circle.size, 32 | circle.rotation, 33 | circle.getStyle()); 34 | } 35 | 36 | DeleteCircle.prototype = Object.create(EditAction.prototype); 37 | DeleteCircle.prototype.constructor = DeleteCircle; 38 | 39 | var proto = DeleteCircle.prototype; 40 | 41 | proto.redo = function() { 42 | 43 | this.createCircle.undo(); 44 | }; 45 | 46 | proto.undo = function() { 47 | 48 | this.createCircle.redo(); 49 | }; 50 | 51 | 52 | -------------------------------------------------------------------------------- /Markup/core/edit-actions/CreateCallout.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | import { MarkupCallout } from '../MarkupCallout'; 5 | import { cloneStyle } from '../StyleUtils'; 6 | 7 | /** 8 | * 9 | * @param editor 10 | * @param id 11 | * @param position 12 | * @param size 13 | * @param text 14 | * @param style 15 | * @constructor 16 | */ 17 | export function CreateCallout(editor, id, position, size, text, style, isFrameUsed) { 18 | 19 | EditAction.call(this, editor, 'CREATE-CALLOUT', id); 20 | 21 | this.text = text; 22 | this.position = {x: position.x, y: position.y}; 23 | this.size = {x: size.x, y: size.y}; 24 | this.style = cloneStyle(style); 25 | this.isFrameUsed = isFrameUsed; 26 | } 27 | 28 | CreateCallout.prototype = Object.create(EditAction.prototype); 29 | CreateCallout.prototype.constructor = CreateCallout; 30 | 31 | var proto = CreateCallout.prototype; 32 | 33 | proto.redo = function () { 34 | 35 | var editor = this.editor; 36 | var position = this.position; 37 | var size = this.size; 38 | 39 | var callout = new MarkupCallout(this.targetId, editor, size); 40 | 41 | editor.addMarkup(callout); 42 | 43 | callout.setIsFilledFrameUsed(this.isFrameUsed); 44 | callout.setText(this.text); 45 | callout.setSize(position, size.x, size.y); 46 | callout.setStyle(this.style); 47 | }; 48 | 49 | proto.undo = function () { 50 | 51 | var markup = this.editor.getMarkup(this.targetId); 52 | if (markup) { 53 | this.editor.removeMarkup(markup); 54 | markup.destroy(); 55 | } 56 | }; 57 | 58 | -------------------------------------------------------------------------------- /Markup/core/edit-modes/BuiltinEditModes.js: -------------------------------------------------------------------------------- 1 | 2 | import { theEditModeManager } from '../EditModeManager'; 3 | import * as MarkupTypes from '../MarkupTypes'; 4 | 5 | import { EditModeArrow } from './EditModeArrow'; 6 | import { EditModeText } from './EditModeText'; 7 | import { EditModeRectangle } from './EditModeRectangle'; 8 | import { EditModeCircle } from './EditModeCircle'; 9 | import { EditModeCloud } from './EditModeCloud'; 10 | import { EditModeFreehand } from './EditModeFreehand'; 11 | import { EditModeHighlight } from './EditModeHighlight'; 12 | import { EditModePolyline } from './EditModePolyline'; 13 | import { EditModePolycloud } from './EditModePolycloud'; 14 | import { EditModeCallout } from './EditModeCallout'; 15 | import { EditModeDimension } from './EditModeDimension'; 16 | import { EditModeStamp } from './EditModeStamp'; 17 | 18 | 19 | theEditModeManager.register(MarkupTypes.MARKUP_TYPE_ARROW, EditModeArrow); 20 | theEditModeManager.register(MarkupTypes.MARKUP_TYPE_TEXT, EditModeText); 21 | theEditModeManager.register(MarkupTypes.MARKUP_TYPE_RECTANGLE, EditModeRectangle); 22 | theEditModeManager.register(MarkupTypes.MARKUP_TYPE_CIRCLE, EditModeCircle); 23 | theEditModeManager.register(MarkupTypes.MARKUP_TYPE_CLOUD, EditModeCloud); 24 | theEditModeManager.register(MarkupTypes.MARKUP_TYPE_FREEHAND, EditModeFreehand); 25 | theEditModeManager.register(MarkupTypes.MARKUP_TYPE_HIGHLIGHT, EditModeHighlight); 26 | theEditModeManager.register(MarkupTypes.MARKUP_TYPE_POLYLINE, EditModePolyline); 27 | theEditModeManager.register(MarkupTypes.MARKUP_TYPE_POLYCLOUD, EditModePolycloud); 28 | theEditModeManager.register(MarkupTypes.MARKUP_TYPE_CALLOUT, EditModeCallout); 29 | theEditModeManager.register(MarkupTypes.MARKUP_TYPE_DIMENSION, EditModeDimension); 30 | theEditModeManager.register(MarkupTypes.MARKUP_TYPE_STAMP, EditModeStamp); 31 | 32 | -------------------------------------------------------------------------------- /Markup/core/edit-actions/SetPolyline.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | 5 | /** 6 | * 7 | * @param editor 8 | * @param polyline 9 | * @param position 10 | * @param size 11 | * @param locations 12 | * @param closed 13 | * @constructor 14 | */ 15 | export function SetPolyline(editor, polyline, position, size, locations, closed) { 16 | 17 | EditAction.call(this, editor, 'SET-POLYLINE', polyline.id); 18 | 19 | this.position = position; 20 | this.size = size; 21 | this.locations = locations.concat(); 22 | this.closed = closed; 23 | 24 | // No need to save old data 25 | } 26 | 27 | SetPolyline.prototype = Object.create(EditAction.prototype); 28 | SetPolyline.prototype.constructor = SetPolyline; 29 | 30 | var proto = SetPolyline.prototype; 31 | 32 | proto.redo = function() { 33 | 34 | var polyline = this.editor.getMarkup(this.targetId); 35 | if(!polyline) { 36 | return; 37 | } 38 | 39 | polyline.set(this.position, this.size, this.locations, this.closed); 40 | }; 41 | 42 | proto.undo = function() { 43 | // No need for undo. 44 | }; 45 | 46 | proto.merge = function(action) { 47 | 48 | if (this.targetId === action.targetId && 49 | this.type === action.type) { 50 | 51 | this.locations = action.locations.concat(); 52 | this.position = action.position; 53 | this.size = action.size; 54 | this.closed = action.closed; 55 | return true; 56 | } 57 | return false; 58 | }; 59 | 60 | /** 61 | * @returns {boolean} 62 | */ 63 | proto.isIdentity = function() { 64 | 65 | return false; // No need to optimize, always false. 66 | }; 67 | 68 | -------------------------------------------------------------------------------- /Markup/core/edit-actions/SetPolycloud.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | 5 | /** 6 | * 7 | * @param editor 8 | * @param polycloud 9 | * @param position 10 | * @param size 11 | * @param locations 12 | * @param closed 13 | * @constructor 14 | */ 15 | export function SetPolycloud(editor, polycloud, position, size, locations, closed) { 16 | 17 | EditAction.call(this, editor, 'SET-POLYCLOUD', polycloud.id); 18 | 19 | this.position = position; 20 | this.size = size; 21 | this.locations = locations.concat(); 22 | this.closed = closed; 23 | 24 | // No need to save old data 25 | } 26 | 27 | SetPolycloud.prototype = Object.create(EditAction.prototype); 28 | SetPolycloud.prototype.constructor = SetPolycloud; 29 | 30 | var proto = SetPolycloud.prototype; 31 | 32 | proto.redo = function() { 33 | 34 | var polycloud = this.editor.getMarkup(this.targetId); 35 | if(!polycloud) { 36 | return; 37 | } 38 | 39 | polycloud.set(this.position, this.size, this.locations, this.closed); 40 | }; 41 | 42 | proto.undo = function() { 43 | // No need for undo. 44 | }; 45 | 46 | proto.merge = function(action) { 47 | 48 | if (this.targetId === action.targetId && 49 | this.type === action.type) { 50 | 51 | this.locations = action.locations.concat(); 52 | this.position = action.position; 53 | this.size = action.size; 54 | this.closed = action.closed; 55 | return true; 56 | } 57 | return false; 58 | }; 59 | 60 | /** 61 | * @returns {boolean} 62 | */ 63 | proto.isIdentity = function() { 64 | 65 | return false; // No need to optimize, always false. 66 | }; 67 | 68 | -------------------------------------------------------------------------------- /Markup/core/edit-modes/EditModeHighlight.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditModePen } from './EditModePen'; 4 | import { DeleteHighlight } from '../edit-actions/DeleteHighlight'; 5 | import { CreateHighlight } from '../edit-actions/CreateHighlight'; 6 | import { SetHighlight } from '../edit-actions/SetHighlight'; 7 | import * as MarkupTypes from '../MarkupTypes'; 8 | 9 | /** 10 | * 11 | * @param editor 12 | * @constructor 13 | */ 14 | export function EditModeHighlight(editor) { 15 | 16 | var styleAttributes = ['stroke-width', 'stroke-color', 'stroke-opacity']; 17 | EditModePen.call(this, editor, MarkupTypes.MARKUP_TYPE_HIGHLIGHT, styleAttributes); 18 | 19 | var normaStrokeWidth = editor.getStrokeWidth(); 20 | this.style['stroke-opacity'] = 0.50; 21 | this.style['stroke-color'] = '#ffff00'; 22 | this.style['stroke-width'] = 4 * normaStrokeWidth; // Very Thick 23 | } 24 | 25 | EditModeHighlight.prototype = Object.create(EditModePen.prototype); 26 | EditModeHighlight.prototype.constructor = EditModeHighlight; 27 | 28 | var proto = EditModeHighlight.prototype; 29 | 30 | proto.createPen = function(markupId, position, size, rotation, locations) { 31 | return new CreateHighlight(this.editor, 32 | markupId, 33 | position, 34 | size, 35 | rotation, 36 | locations, 37 | this.style); 38 | }; 39 | 40 | proto.deletePen = function(markup) { 41 | return new DeleteHighlight(this.editor, markup); 42 | }; 43 | 44 | proto.setPen = function(position, size, locations, isAbsoluteCoords) { 45 | return new SetHighlight(this.editor, 46 | this.selectedMarkup, 47 | position, 48 | size, 49 | locations, 50 | isAbsoluteCoords); 51 | }; 52 | 53 | -------------------------------------------------------------------------------- /Markup/core/edit-actions/SetFreehand.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | 5 | /** 6 | * 7 | * @param editor 8 | * @param freehand 9 | * @param position 10 | * @param size 11 | * @param locations 12 | * @constructor 13 | */ 14 | export function SetFreehand(editor, freehand, position, size, locations, isAbsoluteCoords) { 15 | 16 | EditAction.call(this, editor, 'SET-FREEHAND', freehand.id); 17 | 18 | this.position = position; 19 | this.size = size; 20 | this.locations = isAbsoluteCoords ? locations : locations.slice(0); 21 | this.isAbsoluteCoords = isAbsoluteCoords; 22 | 23 | // No need to save old data 24 | } 25 | 26 | SetFreehand.prototype = Object.create(EditAction.prototype); 27 | SetFreehand.prototype.constructor = SetFreehand; 28 | 29 | var proto = SetFreehand.prototype; 30 | 31 | proto.redo = function() { 32 | 33 | var freehand = this.editor.getMarkup(this.targetId); 34 | if (!freehand) { 35 | return; 36 | } 37 | 38 | freehand.set(this.position, this.size, this.locations, this.isAbsoluteCoords); 39 | }; 40 | 41 | proto.undo = function() { 42 | // No need for undo. 43 | }; 44 | 45 | proto.merge = function(action) { 46 | 47 | if (this.targetId === action.targetId && 48 | this.type === action.type) { 49 | 50 | this.locations = action.isAbsoluteCoords ? action.locations : action.locations.slice(0); 51 | this.position = action.position; 52 | this.size = action.size; 53 | this.isAbsoluteCoords = action.isAbsoluteCoords; 54 | return true; 55 | } 56 | return false; 57 | }; 58 | 59 | /** 60 | * @returns {boolean} 61 | */ 62 | proto.isIdentity = function() { 63 | 64 | return false; // No need to optimize, always false. 65 | }; 66 | -------------------------------------------------------------------------------- /Markup/core/edit-actions/SetHighlight.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | 5 | /** 6 | * 7 | * @param editor 8 | * @param highlight 9 | * @param position 10 | * @param size 11 | * @param locations 12 | * @constructor 13 | */ 14 | export function SetHighlight(editor, highlight, position, size, locations, isAbsoluteCoords) { 15 | 16 | EditAction.call(this, editor, 'SET-HIGHLIGHT', highlight.id); 17 | 18 | this.position = position; 19 | this.size = size; 20 | this.locations = isAbsoluteCoords ? locations : locations.slice(0); 21 | this.isAbsoluteCoords = isAbsoluteCoords; 22 | 23 | // No need to save old data 24 | } 25 | 26 | SetHighlight.prototype = Object.create(EditAction.prototype); 27 | SetHighlight.prototype.constructor = SetHighlight; 28 | 29 | var proto = SetHighlight.prototype; 30 | 31 | proto.redo = function() { 32 | 33 | var highlight = this.editor.getMarkup(this.targetId); 34 | if (!highlight) { 35 | return; 36 | } 37 | 38 | highlight.set(this.position, this.size, this.locations, this.isAbsoluteCoords); 39 | }; 40 | 41 | proto.undo = function() { 42 | // No need for undo. 43 | }; 44 | 45 | proto.merge = function(action) { 46 | 47 | if (this.targetId === action.targetId && 48 | this.type === action.type) { 49 | 50 | this.locations = action.isAbsoluteCoords ? action.locations : action.locations.slice(0); 51 | this.position = action.position; 52 | this.size = action.size; 53 | this.isAbsoluteCoords = action.isAbsoluteCoords; 54 | return true; 55 | } 56 | return false; 57 | }; 58 | 59 | /** 60 | * @returns {boolean} 61 | */ 62 | proto.isIdentity = function() { 63 | 64 | return false; // No need to optimize, always false. 65 | }; 66 | 67 | -------------------------------------------------------------------------------- /Markup/core/edit-actions/SetStamp.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | 5 | export { SetStamp }; 6 | 7 | class SetStamp extends EditAction { 8 | constructor(editor, stamp, position, size) { 9 | super(editor, 'SET-STAMP', stamp.id); 10 | 11 | this.newPosition = {x: position.x, y: position.y}; 12 | this.newSize = {x: size.x, y: size.y}; 13 | this.oldPosition = {x: stamp.position.x, y: stamp.position.y}; 14 | this.oldSize = {x: stamp.size.x, y: stamp.size.y}; 15 | } 16 | 17 | redo() { 18 | this.applyState(this.targetId, this.newPosition, this.newSize); 19 | } 20 | 21 | undo() { 22 | this.applyState(this.targetId, this.oldPosition, this.oldSize); 23 | } 24 | 25 | merge(action) { 26 | if (this.targetId === action.targetId && this.type === action.type) { 27 | this.newPosition = action.newPosition; 28 | this.newSize = action.newSize; 29 | return true; 30 | } 31 | 32 | return false; 33 | } 34 | 35 | applyState(targetId, position, size) { 36 | const stamp = this.editor.getMarkup(targetId); 37 | if (!stamp) { 38 | return; 39 | } 40 | 41 | // Different stroke widths make positions differ at sub-pixel level. 42 | const epsilon = 0.0001; 43 | if ( 44 | Math.abs(stamp.position.x - position.x) > epsilon 45 | || Math.abs(stamp.position.y - position.y) > epsilon 46 | || Math.abs(stamp.size.x - size.x) > epsilon 47 | || Math.abs(stamp.size.y - size.y) > epsilon 48 | ) { 49 | stamp.set(position, size); 50 | } 51 | } 52 | 53 | isIdentity() { 54 | return ( 55 | this.newPosition.x === this.oldPosition.x 56 | && this.newPosition.y === this.oldPosition.y 57 | && this.newSize.x === this.oldSize.x 58 | && this.newSize.y === this.newSize.y 59 | ); 60 | } 61 | } -------------------------------------------------------------------------------- /Markup/core/edit-actions/SetSize.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | 5 | /** 6 | * 7 | * @param editor 8 | * @param markup 9 | * @param position 10 | * @param width 11 | * @param height 12 | * @constructor 13 | */ 14 | export function SetSize(editor, markup, position, width, height) { 15 | 16 | EditAction.call(this, editor, 'SET-SIZE', markup.id); 17 | 18 | this.newPosition = {x: position.x, y: position.y}; 19 | this.oldPosition = {x: markup.position.x, y: markup.position.y}; 20 | this.newWidth = width; 21 | this.oldWidth = markup.size.x; 22 | this.newHeight = height; 23 | this.oldHeight = markup.size.y; 24 | } 25 | 26 | SetSize.prototype = Object.create(EditAction.prototype); 27 | SetSize.prototype.constructor = SetSize; 28 | 29 | var proto = SetSize.prototype; 30 | 31 | proto.redo = function() { 32 | 33 | var markup = this.editor.getMarkup(this.targetId); 34 | markup && markup.setSize(this.newPosition, this.newWidth, this.newHeight); 35 | }; 36 | 37 | proto.undo = function() { 38 | 39 | var markup = this.editor.getMarkup(this.targetId); 40 | markup && markup.setSize(this.oldPosition, this.oldWidth, this.oldHeight); 41 | }; 42 | 43 | proto.merge = function(action) { 44 | 45 | if (this.targetId === action.targetId && 46 | this.type === action.type) { 47 | 48 | this.newPosition = action.newPosition; 49 | this.newWidth = action.newWidth; 50 | this.newHeight = action.newHeight; 51 | return true; 52 | } 53 | return false; 54 | }; 55 | 56 | /** 57 | * @returns {boolean} 58 | */ 59 | proto.isIdentity = function() { 60 | 61 | var identity = 62 | this.newPosition.x === this.oldPosition.x && 63 | this.newPosition.y === this.oldPosition.y && 64 | this.newWidth === this.oldWidth && 65 | this.newHeight === this.oldHeight; 66 | 67 | return identity; 68 | }; 69 | -------------------------------------------------------------------------------- /Markup/core/edit-actions/CreateCircle.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | import { MarkupCircle } from '../MarkupCircle'; 5 | import { cloneStyle } from '../StyleUtils'; 6 | 7 | /** 8 | * Markup create circle action. 9 | * 10 | * Implements an {@link Autodesk.Viewing.Extensions.Markups.Core.EditAction|EditAction} 11 | * for creating a Circle {@link Autodesk.Viewing.Extensions.Markups.Core.Markup|Markup}. 12 | * Included in documentation as an example of how to create 13 | * a specific EditAction that deals with Markup creation. 14 | * Developers are encourage to look into this class's source code and copy 15 | * as much code as they need. Find link to source code below. 16 | * 17 | * @tutorial feature_markup 18 | * @constructor 19 | * @memberof Autodesk.Viewing.Extensions.Markups.Core 20 | * @extends Autodesk.Viewing.Extensions.Markups.Core.EditAction 21 | * 22 | * @param editor 23 | * @param id 24 | * @param position 25 | * @param size 26 | * @param rotation 27 | * @param style 28 | */ 29 | export function CreateCircle(editor, id, position, size, rotation, style) { 30 | 31 | EditAction.call(this, editor, 'CREATE-CIRCLE', id); 32 | 33 | this.selectOnExecution = false; 34 | this.position = {x: position.x, y: position.y}; 35 | this.size = {x: size.x, y: size.y}; 36 | this.rotation = rotation; 37 | this.style = cloneStyle(style); 38 | } 39 | 40 | CreateCircle.prototype = Object.create(EditAction.prototype); 41 | CreateCircle.prototype.constructor = CreateCircle; 42 | 43 | var proto = CreateCircle.prototype; 44 | 45 | proto.redo = function() { 46 | 47 | var editor = this.editor; 48 | var circle = new MarkupCircle(this.targetId, editor); 49 | 50 | editor.addMarkup(circle); 51 | 52 | circle.setSize(this.position, this.size.x, this.size.y); 53 | circle.setRotation(this.rotation); 54 | circle.setStyle(this.style); 55 | }; 56 | 57 | proto.undo = function() { 58 | 59 | var markup = this.editor.getMarkup(this.targetId); 60 | markup && this.editor.removeMarkup(markup); 61 | }; 62 | 63 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Building Measure/Markup extensions 2 | 3 | This is a public 'mirror' version of forge viewer markup and measure extensions. Use webpack to build these extensions locally, then modify as desired. 4 | 5 | **Motivation:** 6 | Forge customers can customize markup and measure tool 7 | 8 | Here's a blog post on how to use the built-in features: https://forge.autodesk.com/blog/using-autodeskviewingmarkupscore-extension 9 | 10 | ![](https://flint-prodcms-forge.s3.amazonaws.com/prod/s3fs-public/2018-07/prev.gif) 11 | 12 | Source: https://forge.autodesk.com/blog/viewing-large-ocrterrain-images-forge-viewer 13 | 14 | But these APIs are limited. Sometimes you have to hack the viewer3d.js file, in order to achieve the behavior you want. For example, creating an SVG stamp tool (see examples below). It's not really possible without overriding large amounts of code with prototypes. 15 | 16 | Instead, what if you could modify the existing markup and measure extensions, without touching viewer3d.js ? Well, here's how... 17 | 18 | Use this mirror code, to build these extensions seperately. Then modify the extensions code as you need, seperate from the viewer3d.js file. 19 | 20 | 21 | 22 | #### Customization blog posts: 23 | 24 | - to save/restore measurements to a database (save/restore): https://forge.autodesk.com/blog/area-planning-tool-forge-viewer-and-mysql 25 | - create an SVG 'stamp' for markup tool: https://forge.autodesk.com/blog/fast-pdf-viewingmarkup-inside-forge-viewer 26 | 27 | ## Setup 28 | 29 | 1. install cmd line... 30 | 31 | ``` 32 | npm install webpack 33 | npm install css-loader --save-dev 34 | npm install style-loader --save-dev 35 | npm install svg-url-loader --save-dev 36 | ``` 37 | 38 | 39 | ## Compile 40 | `webpack --config=webpack.js --env.BUILD_TASK=lmv-extensions --env.BUILD_PROD=true` 41 | 42 | this will create minified files under `build/extensions/`: 43 | 44 | ``` 45 | Measure/Measure.min.js 46 | Markup/Markup.min.js 47 | ``` 48 | 49 | ## Run 50 | which you can include in your index.html file, like this: 51 | 52 | ``` 53 | 54 | 55 | ``` 56 | 57 | ## Alternatives 58 | 59 | Edit2D extension: https://forge.autodesk.com/en/docs/viewer/v7/developers_guide/advanced_options/edit2d-use/ 60 | 61 | -------------------------------------------------------------------------------- /Markup/core/edit-actions/SetCloud.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | 5 | /** 6 | * 7 | * @param editor 8 | * @param cloud 9 | * @param position 10 | * @param size 11 | * @constructor 12 | */ 13 | export function SetCloud(editor, cloud, position, size) { 14 | 15 | EditAction.call(this, editor, 'SET-CLOUD', cloud.id); 16 | 17 | this.newPosition = {x: position.x, y: position.y}; 18 | this.newSize = {x: size.x, y: size.y}; 19 | this.oldPosition = {x: cloud.position.x, y: cloud.position.y}; 20 | this.oldSize = {x: cloud.size.x, y: cloud.size.y}; 21 | } 22 | 23 | SetCloud.prototype = Object.create(EditAction.prototype); 24 | SetCloud.prototype.constructor = SetCloud; 25 | 26 | var proto = SetCloud.prototype; 27 | 28 | proto.redo = function() { 29 | 30 | this.applyState(this.targetId, this.newPosition, this.newSize, this.newStrokeWidth, this.newColor); 31 | }; 32 | 33 | proto.undo = function() { 34 | 35 | this.applyState(this.targetId, this.oldPosition, this.oldSize, this.oldStrokeWidth, this.oldColor); 36 | }; 37 | 38 | proto.merge = function(action) { 39 | 40 | if (this.targetId === action.targetId && 41 | this.type === action.type) { 42 | 43 | this.newPosition = action.newPosition; 44 | this.newSize = action.newSize; 45 | return true; 46 | } 47 | return false; 48 | }; 49 | 50 | /** 51 | * 52 | * @private 53 | */ 54 | proto.applyState = function(targetId, position, size) { 55 | 56 | var cloud = this.editor.getMarkup(targetId); 57 | if(!cloud) { 58 | return; 59 | } 60 | 61 | // Different stroke widths make positions differ at sub-pixel level. 62 | var epsilon = 0.0001; 63 | 64 | if (Math.abs(cloud.position.x - position.x) > epsilon || Math.abs(cloud.size.y - size.y) > epsilon || 65 | Math.abs(cloud.position.y - position.y) > epsilon || Math.abs(cloud.size.y - size.y) > epsilon) { 66 | 67 | cloud.set(position, size); 68 | } 69 | }; 70 | 71 | /** 72 | * @returns {boolean} 73 | */ 74 | proto.isIdentity = function() { 75 | 76 | return ( 77 | this.newPosition.x === this.oldPosition.x && 78 | this.newPosition.y === this.oldPosition.y && 79 | this.newSize.x === this.oldSize.x && 80 | this.newSize.y === this.oldSize.y); 81 | }; 82 | 83 | -------------------------------------------------------------------------------- /Markup/core/edit-actions/SetRectangle.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | 5 | /** 6 | * 7 | * @param editor 8 | * @param rectangle 9 | * @param position 10 | * @param size 11 | * @constructor 12 | */ 13 | export function SetRectangle(editor, rectangle, position, size) { 14 | 15 | EditAction.call(this, editor, 'SET-RECTANGLE', rectangle.id); 16 | 17 | this.newPosition = {x: position.x, y: position.y}; 18 | this.newSize = {x: size.x, y: size.y}; 19 | this.oldPosition = {x: rectangle.position.x, y: rectangle.position.y}; 20 | this.oldSize = {x: rectangle.size.x, y: rectangle.size.y}; 21 | } 22 | 23 | SetRectangle.prototype = Object.create(EditAction.prototype); 24 | SetRectangle.prototype.constructor = SetRectangle; 25 | 26 | var proto = SetRectangle.prototype; 27 | 28 | proto.redo = function() { 29 | 30 | this.applyState(this.targetId, this.newPosition, this.newSize); 31 | }; 32 | 33 | proto.undo = function() { 34 | 35 | this.applyState(this.targetId, this.oldPosition, this.oldSize); 36 | }; 37 | 38 | proto.merge = function(action) { 39 | 40 | if (this.targetId === action.targetId && 41 | this.type === action.type) { 42 | 43 | this.newPosition = action.newPosition; 44 | this.newSize = action.newSize; 45 | return true; 46 | } 47 | return false; 48 | }; 49 | 50 | /** 51 | * 52 | * @private 53 | */ 54 | proto.applyState = function(targetId, position, size) { 55 | 56 | var rectangle = this.editor.getMarkup(targetId); 57 | if(!rectangle) { 58 | return; 59 | } 60 | 61 | // Different stroke widths make positions differ at sub-pixel level. 62 | var epsilon = 0.0001; 63 | 64 | if (Math.abs(rectangle.position.x - position.x) > epsilon || Math.abs(rectangle.size.y - size.y) > epsilon || 65 | Math.abs(rectangle.position.y - position.y) > epsilon || Math.abs(rectangle.size.y - size.y) > epsilon) { 66 | 67 | rectangle.set(position, size); 68 | } 69 | }; 70 | 71 | /** 72 | * @returns {boolean} 73 | */ 74 | proto.isIdentity = function() { 75 | 76 | return( 77 | this.newPosition.x === this.oldPosition.x && 78 | this.newPosition.y === this.oldPosition.y && 79 | this.newSize.x === this.oldSize.x && 80 | this.newSize.y === this.oldSize.y); 81 | }; 82 | -------------------------------------------------------------------------------- /Markup/core/edit-actions/EditAction.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Base class for all markup edit actions. 5 | * 6 | * EditActions encapsulate {@link Autodesk.Viewing.Extensions.Markups.Core.Markup|Markup} 7 | * operations (such as creation, edition and deletion) that hook into the undo/redo system. 8 | * 9 | * The minimum set of methods to implement on an EditAction extension are: 10 | * - execute() 11 | * - undo() 12 | * - redo() 13 | * 14 | * A good set of classes to check their implementation are: 15 | * {@link Autodesk.Viewing.Extensions.Markups.Core.CreateCircle|CreateCircle}. 16 | * {@link Autodesk.Viewing.Extensions.Markups.Core.DeleteCircle|DeleteCircle}. 17 | * {@link Autodesk.Viewing.Extensions.Markups.Core.SetCircle|SetCircle}. 18 | * 19 | * @tutorial feature_markup 20 | * @constructor 21 | * @memberof Autodesk.Viewing.Extensions.Markups.Core 22 | * 23 | * @param {Autodesk.Viewing.Extensions.Markups.Core.MarkupsCore} editor 24 | * @param {String} type - An identifier for the EditAction. 25 | * @param {number} targetId - The id of the markup being affected. 26 | */ 27 | export function EditAction(editor, type, targetId) { 28 | 29 | this.type = type; 30 | this.editor = editor; 31 | this.targetId = targetId; 32 | this.addToHistory = true; 33 | this.selectOnExecution = true; 34 | } 35 | 36 | /** 37 | * Performs the action. 38 | */ 39 | EditAction.prototype.execute = function() { 40 | 41 | this.editor.actionManager.execute(this); 42 | }; 43 | 44 | /** 45 | * @abstract 46 | */ 47 | EditAction.prototype.redo = function() { 48 | 49 | }; 50 | 51 | /** 52 | * @abstract 53 | */ 54 | EditAction.prototype.undo = function() { 55 | 56 | }; 57 | 58 | /** 59 | * Provides a mechanism to merge consecutive actions of the same type. 60 | * @param {Autodesk.Viewing.Extensions.Markups.Core.EditAction} action - Action to check if it can be merged with 'this'. 61 | * @returns {boolean} Returns true if merge has been applied. Parameter will be discarded. 62 | */ 63 | EditAction.prototype.merge = function(action) { 64 | 65 | return false; 66 | }; 67 | 68 | /** 69 | * Provides a mechanism to check whether the action yields no results. 70 | * @returns {boolean} Returns true if no changes happen with this action. 71 | */ 72 | EditAction.prototype.isIdentity = function() { 73 | 74 | return false; 75 | }; 76 | 77 | -------------------------------------------------------------------------------- /Markup/core/edit-actions/SetDimension.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | 5 | /** 6 | * 7 | * @param editor 8 | * @param dimension 9 | * @param firstAnchor 10 | * @param secondAnchor 11 | * @constructor 12 | */ 13 | export function SetDimension(editor, dimension, firstAnchor, secondAnchor, text) { 14 | 15 | EditAction.call(this, editor, 'SET-DIMENSION', dimension.id); 16 | 17 | this.newFirstAnchor = {x: firstAnchor.x, y: firstAnchor.y}; 18 | this.newSecondAnchor = {x: secondAnchor.x, y: secondAnchor.y}; 19 | this.oldFirstAnchor = {x: dimension.firstAnchor.x, y: dimension.firstAnchor.y}; 20 | this.oldSecondAnchor = {x: dimension.secondAnchor.x, y: dimension.secondAnchor.y}; 21 | this.newText = text; 22 | this.oldText = dimension.currentText; 23 | } 24 | 25 | SetDimension.prototype = Object.create(EditAction.prototype); 26 | SetDimension.prototype.constructor = SetDimension; 27 | 28 | var proto = SetDimension.prototype; 29 | 30 | proto.redo = function() { 31 | 32 | this.applyState(this.newFirstAnchor, this.newSecondAnchor, this.newText); 33 | 34 | }; 35 | 36 | proto.undo = function() { 37 | 38 | this.applyState(this.oldFirstAnchor, this.oldSecondAnchor, this.oldText); 39 | 40 | }; 41 | 42 | proto.merge = function(action) { 43 | 44 | if (this.targetId === action.targetId && 45 | this.type === action.type) { 46 | 47 | this.newFirstAnchor = action.newFirstAnchor; 48 | this.newSecondAnchor = action.newSecondAnchor; 49 | this.newText = action.newText; 50 | return true; 51 | } 52 | return false; 53 | }; 54 | 55 | /** 56 | * 57 | * @private 58 | */ 59 | proto.applyState = function(firstAnchor, secondAnchor, text) { 60 | 61 | var dimension = this.editor.getMarkup(this.targetId); 62 | 63 | if(!dimension) { 64 | return; 65 | } 66 | 67 | dimension.set(firstAnchor.x, firstAnchor.y, secondAnchor.x, secondAnchor.y, text); 68 | 69 | }; 70 | 71 | /** 72 | * @returns {boolean} 73 | */ 74 | proto.isIdentity = function() { 75 | 76 | return ((this.newText === this.oldText) && ( 77 | !this.newFirstAnchor || !this.newSecondAnchor || 78 | this.newFirstAnchor.x === this.oldFirstAnchor.x && 79 | this.newFirstAnchor.y === this.oldFirstAnchor.y && 80 | this.newSecondAnchor.x === this.oldSecondAnchor.x && 81 | this.newSecondAnchor.y === this.oldSecondAnchor.y)); 82 | }; 83 | -------------------------------------------------------------------------------- /Markup/core/edit-actions/SetArrow.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | 5 | /** 6 | * 7 | * @param editor 8 | * @param arrow 9 | * @param head 10 | * @param tail 11 | * @constructor 12 | */ 13 | export function SetArrow(editor, arrow, head, tail) { 14 | 15 | EditAction.call(this, editor, 'SET-ARROW', arrow.id); 16 | 17 | this.newHead = {x: head.x, y: head.y}; 18 | this.newTail = {x: tail.x, y: tail.y}; 19 | this.oldHead = {x: arrow.head.x, y: arrow.head.y}; 20 | this.oldTail = {x: arrow.tail.x, y: arrow.tail.y}; 21 | } 22 | 23 | SetArrow.prototype = Object.create(EditAction.prototype); 24 | SetArrow.prototype.constructor = SetArrow; 25 | 26 | var proto = SetArrow.prototype; 27 | 28 | proto.redo = function() { 29 | 30 | this.applyState(this.targetId, this.newHead, this.newTail); 31 | }; 32 | 33 | proto.undo = function() { 34 | 35 | this.applyState(this.targetId, this.oldHead, this.oldTail); 36 | }; 37 | 38 | proto.merge = function(action) { 39 | 40 | if (this.targetId === action.targetId && 41 | this.type === action.type) { 42 | 43 | this.newHead = action.newHead; 44 | this.newTail = action.newTail; 45 | return true; 46 | } 47 | return false; 48 | }; 49 | 50 | /** 51 | * 52 | * @private 53 | */ 54 | proto.applyState = function(targetId, head, tail) { 55 | 56 | var arrow = this.editor.getMarkup(targetId); 57 | if(!arrow) { 58 | return; 59 | } 60 | 61 | // Different stroke widths make positions differ at sub-pixel level. 62 | var epsilon = 0.0001; 63 | 64 | if (Math.abs(arrow.head.x - head.x) >= epsilon || Math.abs(arrow.head.y - head.y) >= epsilon || 65 | Math.abs(arrow.tail.x - tail.x) >= epsilon || Math.abs(arrow.tail.y - tail.y) >= epsilon) { 66 | 67 | // Confusing naming here. in arrow.set the first two numbers are 68 | // the point you drag from and the second two are the point you 69 | // drag to. So the head point is actually where the tail of the 70 | // arrow is positioned and the tail point is the head is positioned. 71 | arrow.set(head.x, head.y, tail.x, tail.y); 72 | } 73 | }; 74 | 75 | /** 76 | * @returns {boolean} 77 | */ 78 | proto.isIdentity = function() { 79 | 80 | return ( 81 | this.newHead.x === this.oldHead.x && 82 | this.newHead.y === this.oldHead.y && 83 | this.newTail.x === this.oldTail.x && 84 | this.newTail.y === this.oldTail.y); 85 | }; 86 | 87 | -------------------------------------------------------------------------------- /Markup/core/edit-modes/EditModeStamp.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditMode } from './EditMode'; 4 | import { DeleteStamp } from '../edit-actions/DeleteStamp'; 5 | import { CreateStamp } from '../edit-actions/CreateStamp'; 6 | import { SetStamp } from '../edit-actions/SetStamp'; 7 | import * as MarkupTypes from '../MarkupTypes'; 8 | 9 | export { EditModeStamp }; 10 | 11 | class EditModeStamp extends EditMode { 12 | constructor(editor, svgData) { 13 | var styleAttributes = [ 14 | 'text-data' 15 | ]; 16 | super(editor, MarkupTypes.MARKUP_TYPE_STAMP, styleAttributes); 17 | this.svgData = svgData; 18 | } 19 | 20 | deleteMarkup(markup, cantUndo) { 21 | markup = markup || this.selectedMarkup; 22 | if (markup && markup.type == this.type) { 23 | var deleteStamp = new DeleteStamp(this.editor, markup); 24 | deleteStamp.addToHistory = !cantUndo; 25 | deleteStamp.execute(); 26 | return true; 27 | } 28 | return false; 29 | } 30 | 31 | onMouseMove(event) { 32 | if (!EditMode.prototype.onMouseMove.call( this, event )) { 33 | return false; 34 | } 35 | 36 | const { selectedMarkup, editor } = this; 37 | 38 | let final = this.getFinalMouseDraggingPosition(); 39 | final = editor.clientToMarkups(final.x, final.y); 40 | let position = { 41 | x: (this.firstPosition.x + final.x) / 2, 42 | y: (this.firstPosition.y + final.y) / 2 43 | }; 44 | let size = this.size = { 45 | x: Math.abs(final.x - this.firstPosition.x), 46 | y: Math.abs(final.y - this.firstPosition.y) 47 | }; 48 | 49 | const action = new SetStamp(editor, selectedMarkup, position, size); 50 | action.execute(); 51 | return true; 52 | } 53 | 54 | onMouseDown() { 55 | EditMode.prototype.onMouseDown.call(this); 56 | 57 | if (this.selectedMarkup) { 58 | return; 59 | } 60 | 61 | const editor = this.editor; 62 | let mousePosition = editor.getMousePosition(); 63 | 64 | this.initialX = mousePosition.x; 65 | this.initialY = mousePosition.y; 66 | this.firstPosition = editor.clientToMarkups(this.initialX, this.initialY); 67 | this.size = editor.sizeFromClientToMarkups(1, 1); 68 | 69 | editor.beginActionGroup(); 70 | const markupId = editor.getId(); 71 | const action = new CreateStamp(editor, markupId, this.firstPosition, this.size, 0, this.style, this.svgData); 72 | action.execute(); 73 | 74 | // maybe this isn't being called right, that would explain it 75 | this.selectedMarkup = editor.getMarkup(markupId); 76 | this.creationBegin(); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Markup/core/Markups.css: -------------------------------------------------------------------------------- 1 | .adsk-viewing-viewer .autodesk-markups-extension-core-make-me-bigger:after { 2 | content: ""; 3 | position: absolute; 4 | top: -15px; 5 | bottom: -15px; 6 | left: -15px; 7 | right: -15px; 8 | } 9 | 10 | .adsk-viewing-viewer .autodesk-markups-extension-core-make-me-bigger.rotation-bridge:after { 11 | top: 0; 12 | bottom: 0px; 13 | } 14 | 15 | .adsk-viewing-viewer .selector-box { 16 | position: absolute; 17 | border: 1px dashed #0696D7; 18 | background: rgba(6, 150, 215, 0.05); 19 | z-index: 1; 20 | cursor: move; 21 | box-sizing: border-box; 22 | } 23 | 24 | .adsk-viewing-viewer .selector-drag-point, 25 | .adsk-viewing-viewer .selector-rotate-point { 26 | position: absolute; 27 | height: 8px; 28 | width: 8px; 29 | border-radius: 8px; /*HANDLE_SIZE*/ 30 | background: #FFFFFF; /*HANDLE_BACKGROUND_COLOR*/ 31 | border-color: rgba(107,120,127,0.7); /* HANDLE_BORDER_COLOR; */ 32 | border-width: 1px; /* BORDER_WIDTH */ 33 | border-style: solid; 34 | } 35 | 36 | .adsk-viewing-viewer .selector-rotate-point { 37 | top: calc(100% + 22px); /* 30 - 8 = 22 */ 38 | left: calc(50% + 1px); 39 | transform: translate3d(-50%, 0px, 0px); 40 | } 41 | 42 | .adsk-viewing-viewer .selector-drag-point.selected, 43 | .adsk-viewing-viewer .selector-rotate-point.selected:not(.rotation-bridge) { 44 | background: #0696D7; 45 | border-color: #0696D7; 46 | } 47 | 48 | .adsk-viewing-viewer .rotation-bridge { 49 | position: absolute; 50 | background-color: rgba(0,0,0,0); 51 | height: 30px; 52 | width: 0px; 53 | top: 100%; 54 | left: calc(50% + 1px); 55 | border: unset; 56 | border-left: 1px dashed #0696D7; 57 | } 58 | /*var placementOffset = -6;*/ 59 | .adsk-viewing-viewer .selector-drag-point.sdp-handle-n { 60 | top: -6px; 61 | left: calc(50% - 4px); 62 | position: relative; 63 | } 64 | 65 | .adsk-viewing-viewer .selector-drag-point.sdp-handle-s { 66 | top: calc(100% - 14px); 67 | left: calc(50% - 4px); 68 | position: relative; 69 | } 70 | 71 | .adsk-viewing-viewer .selector-drag-point.sdp-handle-w { 72 | left: -6px; 73 | top: 50%; 74 | transform: translate3d(0, -50%, 0); 75 | } 76 | 77 | .adsk-viewing-viewer .selector-drag-point.sdp-handle-e { 78 | right: -6px; 79 | top: 50%; 80 | transform: translate3d(0, -50%, 0); 81 | } 82 | 83 | .adsk-viewing-viewer .selector-drag-point.sdp-handle-nw { 84 | top: -6px; 85 | left: -6px; 86 | } 87 | 88 | .adsk-viewing-viewer .selector-drag-point.sdp-handle-ne { 89 | top: -6px; 90 | right: -6px; 91 | } 92 | 93 | .adsk-viewing-viewer .selector-drag-point.sdp-handle-sw { 94 | bottom: -6px; 95 | left: -6px; 96 | } 97 | 98 | .adsk-viewing-viewer .selector-drag-point.sdp-handle-se { 99 | bottom: -6px; 100 | right: -6px; 101 | } -------------------------------------------------------------------------------- /Markup/core/edit-actions/SetCircle.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditAction } from './EditAction'; 4 | 5 | /** 6 | * Markup set circle action. 7 | * 8 | * Implements an {@link Autodesk.Viewing.Extensions.Markups.Core.EditAction|EditAction} 9 | * for editing properties of a Circle {@link Autodesk.Viewing.Extensions.Markups.Core.Markup|Markup}. 10 | * Included in documentation as an example of how to create 11 | * a specific EditAction that deals with Markup edition. 12 | * Developers are encourage to look into this class's source code and copy 13 | * as much code as they need. Find link to source code below. 14 | * 15 | * @tutorial feature_markup 16 | * @constructor 17 | * @memberof Autodesk.Viewing.Extensions.Markups.Core 18 | * @extends Autodesk.Viewing.Extensions.Markups.Core.EditAction 19 | * 20 | * @param editor 21 | * @param circle 22 | * @param position 23 | * @param size 24 | */ 25 | export function SetCircle(editor, circle, position, size) { 26 | 27 | EditAction.call(this, editor, 'SET-CIRCLE', circle.id); 28 | 29 | this.newPosition = {x: position.x, y: position.y}; 30 | this.newSize = {x: size.x, y: size.y}; 31 | this.oldPosition = {x: circle.position.x, y: circle.position.y}; 32 | this.oldSize = {x: circle.size.x, y: circle.size.y}; 33 | } 34 | 35 | SetCircle.prototype = Object.create(EditAction.prototype); 36 | SetCircle.prototype.constructor = SetCircle; 37 | 38 | var proto = SetCircle.prototype; 39 | 40 | proto.redo = function() { 41 | 42 | this.applyState(this.targetId, this.newPosition, this.newSize); 43 | }; 44 | 45 | proto.undo = function() { 46 | 47 | this.applyState(this.targetId, this.oldPosition, this.oldSize); 48 | }; 49 | 50 | proto.merge = function(action) { 51 | 52 | if (this.targetId === action.targetId && 53 | this.type === action.type) { 54 | 55 | this.newPosition = action.newPosition; 56 | this.newSize = action.newSize; 57 | return true; 58 | } 59 | return false; 60 | }; 61 | 62 | /** 63 | * 64 | * @private 65 | */ 66 | proto.applyState = function(targetId, position, size) { 67 | 68 | var circle = this.editor.getMarkup(targetId); 69 | if(!circle) { 70 | return; 71 | } 72 | 73 | // Different stroke widths make positions differ at sub-pixel level. 74 | var epsilon = 0.0001; 75 | 76 | if (Math.abs(circle.position.x - position.x) > epsilon || Math.abs(circle.size.y - size.y) > epsilon || 77 | Math.abs(circle.position.y - position.y) > epsilon || Math.abs(circle.size.y - size.y) > epsilon) { 78 | 79 | circle.set(position, size); 80 | } 81 | }; 82 | 83 | /** 84 | * @returns {boolean} 85 | */ 86 | proto.isIdentity = function() { 87 | 88 | return ( 89 | this.newPosition.x === this.oldPosition.x && 90 | this.newPosition.y === this.oldPosition.y && 91 | this.newSize.x === this.oldSize.x && 92 | this.newSize.y === this.oldSize.y); 93 | }; 94 | 95 | -------------------------------------------------------------------------------- /Markup/core/DomElementStyle.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Curring object which generate a string that can be used 5 | * as a Dom element's 'style' value. 6 | * 7 | * @constructor 8 | */ 9 | export function DomElementStyle() { 10 | 11 | this.reset(); 12 | } 13 | 14 | /* 15 | * Constants 16 | */ 17 | var BROWSER_PREFIXES = ['-ms-', '-webkit-', '-moz-', '-o-']; 18 | 19 | var proto = DomElementStyle.prototype; 20 | 21 | proto.reset = function() { 22 | 23 | this.attributes = {}; 24 | this.dirty = false; 25 | this.styleString = ''; 26 | 27 | return this; 28 | }; 29 | 30 | /** 31 | * 32 | * @param {String} key 33 | * @param {*} value 34 | * @param {Object} [options] 35 | * @param {Boolean} [options.allBrowsers] - Whether to add browser prefix to key 36 | * @returns {Autodesk.Viewing.Extensions.Markups.Core.Utils.DomeElemStyle} 37 | */ 38 | proto.setAttribute = function(key, value, options) { 39 | 40 | this.attributes[key] = value; 41 | 42 | if (options && options.allBrowsers) { 43 | var that = this; 44 | BROWSER_PREFIXES.forEach(function(prefix){ 45 | that.attributes[(prefix+key)] = value; 46 | }); 47 | } 48 | this.dirty = true; // Could be optimized 49 | return this; 50 | }; 51 | 52 | /** 53 | * Removes one or more attributes 54 | * @param {String|Array} key - Key or Keys to be removed 55 | * @returns {Autodesk.Viewing.Extensions.Markups.Core.Utils.DomElemStyle} this 56 | */ 57 | proto.removeAttribute = function(key) { 58 | 59 | if (!Array.isArray(key)) { 60 | key = [key]; 61 | } 62 | 63 | var self = this; 64 | key.forEach(function(k) { 65 | if (k in self.attributes) { 66 | delete self.attributes[k]; 67 | self.dirty = true; 68 | } 69 | }); 70 | return this; 71 | }; 72 | 73 | /** 74 | * Gets the String representation of this style object 75 | * @returns {string} 76 | */ 77 | proto.getStyleString = function() { 78 | 79 | if (this.dirty) { 80 | this.styleString = generateStyle(this.attributes); 81 | this.dirty = false; 82 | } 83 | return this.styleString; 84 | }; 85 | 86 | /** 87 | * Clones the current Object 88 | * 89 | * @returns {Autodesk.Viewing.Extensions.Markups.Core.Utils.DomElemStyle} 90 | */ 91 | proto.clone = function() { 92 | 93 | var clone = new DomElementStyle(); 94 | var attributes = this.attributes; 95 | 96 | for (var key in attributes) { 97 | clone.setAttribute(key, attributes[key]); 98 | } 99 | return clone; 100 | }; 101 | 102 | /** 103 | * Generates the style value string. Non mutable function. 104 | * 105 | * @param {Object} attributes 106 | * @private 107 | */ 108 | function generateStyle(attributes) { 109 | 110 | var elements = []; 111 | for (var key in attributes) { 112 | var val = attributes[key]; 113 | elements.push(key); 114 | elements.push(':'); 115 | elements.push(val); 116 | elements.push('; '); 117 | } 118 | return elements.join(''); 119 | } 120 | -------------------------------------------------------------------------------- /Markup/core/MarkupCircle.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { Markup } from './Markup'; 4 | import * as MarkupTypes from './MarkupTypes'; 5 | import { createMarkupPathSvg, composeRGBAString, setAttributeToMarkupSvg, 6 | updateMarkupPathSvgHitarea, addMarkupMetadata, createEllipsePath } from './MarkupsCoreUtils'; 7 | import { cloneStyle } from './StyleUtils'; 8 | import { EditModeCircle } from './edit-modes/EditModeCircle'; 9 | 10 | /** 11 | * 12 | * @param id 13 | * @param editor 14 | * @constructor 15 | */ 16 | export function MarkupCircle(id, editor) { 17 | 18 | var styleAttributes = ['stroke-width', 'stroke-color', 'stroke-opacity', 'fill-color', 'fill-opacity']; 19 | Markup.call(this, id, editor, styleAttributes); 20 | 21 | // bind to this to pass this.globalManager 22 | this.addMarkupMetadata = addMarkupMetadata.bind(this); 23 | 24 | this.type = MarkupTypes.MARKUP_TYPE_CIRCLE; 25 | this.shape = createMarkupPathSvg(); 26 | 27 | this.bindDomEvents(); 28 | } 29 | 30 | MarkupCircle.prototype = Object.create(Markup.prototype); 31 | MarkupCircle.prototype.constructor = MarkupCircle; 32 | 33 | var proto = MarkupCircle.prototype; 34 | 35 | proto.getEditMode = function() { 36 | 37 | return new EditModeCircle(this.editor); 38 | }; 39 | 40 | proto.set = function(position, size) { 41 | 42 | this.setSize(position, size.x, size.y); 43 | }; 44 | 45 | /** 46 | * Applies data values into DOM element style/attribute(s) 47 | * 48 | */ 49 | proto.updateStyle = function() { 50 | 51 | var style = this.style; 52 | var shape = this.shape; 53 | var path = this.getPath().join(' '); 54 | 55 | var strokeWidth = this.style['stroke-width']; 56 | var strokeColor = this.highlighted ? this.highlightColor : composeRGBAString(style['stroke-color'], style['stroke-opacity']); 57 | var fillColor = composeRGBAString(style['fill-color'], style['fill-opacity']); 58 | var transform = this.getTransform(); 59 | 60 | setAttributeToMarkupSvg(shape, 'd', path); 61 | setAttributeToMarkupSvg(shape, 'stroke-width', strokeWidth); 62 | setAttributeToMarkupSvg(shape, 'stroke', strokeColor); 63 | setAttributeToMarkupSvg(shape, 'fill', fillColor); 64 | setAttributeToMarkupSvg(shape, 'transform', transform); 65 | updateMarkupPathSvgHitarea(shape, this.editor); 66 | }; 67 | 68 | proto.setMetadata = function() { 69 | 70 | var metadata = cloneStyle(this.style); 71 | 72 | metadata.type = this.type; 73 | metadata.position = [this.position.x, this.position.y].join(" "); 74 | metadata.size = [this.size.x, this.size.y].join(" "); 75 | metadata.rotation = String(this.rotation); 76 | 77 | return this.addMarkupMetadata(this.shape, metadata); 78 | }; 79 | 80 | proto.getPath = function() { 81 | 82 | var size = this.size; 83 | if (size.x === 1 || size.y === 1) { 84 | return ['']; 85 | } 86 | 87 | var strokeWidth = this.style['stroke-width']; 88 | 89 | var ellipseW = size.x - strokeWidth; 90 | var ellipseH = size.y - strokeWidth; 91 | 92 | var ellipseX = -0.5*ellipseW; 93 | var ellipseY = 0; 94 | 95 | var path = []; 96 | createEllipsePath(ellipseX, ellipseY, ellipseW, ellipseH, false, path); 97 | 98 | return path; 99 | }; 100 | -------------------------------------------------------------------------------- /Markup/core/edit-modes/EditModeCloud.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditMode } from './EditMode'; 4 | import { DeleteCloud } from '../edit-actions/DeleteCloud'; 5 | import { CreateCloud } from '../edit-actions/CreateCloud'; 6 | import { SetCloud } from '../edit-actions/SetCloud'; 7 | import * as MarkupTypes from '../MarkupTypes'; 8 | 9 | /** 10 | * 11 | * @param editor 12 | * @constructor 13 | */ 14 | export function EditModeCloud(editor) { 15 | 16 | var styleAttributes = ['stroke-width', 'stroke-color', 'stroke-opacity', 'fill-color', 'fill-opacity']; 17 | EditMode.call(this, editor, MarkupTypes.MARKUP_TYPE_CLOUD, styleAttributes); 18 | } 19 | 20 | EditModeCloud.prototype = Object.create(EditMode.prototype); 21 | EditModeCloud.prototype.constructor = EditModeCloud; 22 | 23 | var proto = EditModeCloud.prototype; 24 | 25 | proto.deleteMarkup = function(markup, cantUndo) { 26 | 27 | markup = markup || this.selectedMarkup; 28 | if (markup && markup.type == this.type) { 29 | var deleteCloud = new DeleteCloud(this.editor, markup); 30 | deleteCloud.addToHistory = !cantUndo; 31 | deleteCloud.execute(); 32 | return true; 33 | } 34 | return false; 35 | }; 36 | 37 | /** 38 | * Handler to mouse move events, used to create markups. 39 | * @param {MouseEvent} event Mouse event. 40 | * @private 41 | */ 42 | proto.onMouseMove = function(event) { 43 | 44 | if (!EditMode.prototype.onMouseMove.call( this, event )) { 45 | return false; 46 | } 47 | 48 | var selectedMarkup = this.selectedMarkup; 49 | 50 | var editor = this.editor; 51 | 52 | var pos = this.getFinalMouseDraggingPosition(); 53 | var final = editor.clientToMarkups(pos.x, pos.y); 54 | var position = { x: (this.firstPosition.x + final.x) / 2, y: (this.firstPosition.y + final.y) / 2 }; 55 | var size = this.size = { x: Math.abs(final.x - this.firstPosition.x), y: Math.abs(final.y - this.firstPosition.y) }; 56 | var setCloud = new SetCloud( 57 | editor, 58 | selectedMarkup, 59 | position, 60 | size); 61 | 62 | setCloud.execute(); 63 | return true; 64 | }; 65 | 66 | /** 67 | * Handler to mouse down events, used to start markups creation. 68 | * @private 69 | */ 70 | proto.onMouseDown = function() { 71 | 72 | EditMode.prototype.onMouseDown.call(this); 73 | 74 | if (this.selectedMarkup) { 75 | return; 76 | } 77 | 78 | var editor = this.editor; 79 | var mousePosition = editor.getMousePosition(); 80 | 81 | this.initialX = mousePosition.x; 82 | this.initialY = mousePosition.y; 83 | 84 | // Calculate center and size. 85 | var position = this.firstPosition = editor.clientToMarkups(this.initialX, this.initialY); 86 | var size = this.size = editor.sizeFromClientToMarkups(1, 1); 87 | 88 | // Create Cloud. 89 | editor.beginActionGroup(); 90 | 91 | var markupId = editor.getId(); 92 | var create = new CreateCloud( 93 | editor, 94 | markupId, 95 | position, 96 | size, 97 | 0, 98 | this.style); 99 | 100 | create.execute(); 101 | 102 | this.selectedMarkup = editor.getMarkup(markupId); 103 | this.creationBegin(); 104 | }; 105 | 106 | -------------------------------------------------------------------------------- /Markup/core/edit-modes/EditModeCircle.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { EditMode } from './EditMode'; 4 | import { DeleteCircle } from '../edit-actions/DeleteCircle'; 5 | import { CreateCircle } from '../edit-actions/CreateCircle'; 6 | import { SetCircle } from '../edit-actions/SetCircle'; 7 | import * as MarkupTypes from '../MarkupTypes'; 8 | 9 | /** 10 | * Markup circle edit mode. 11 | * 12 | * Implements a Circle {@link Autodesk.Viewing.Extensions.Markups.Core.EditMode|EditMode}. 13 | * Included in documentation as an example of how to create 14 | * an EditMode for a specific markup type. Developers are encourage to look into this class's source code and copy 15 | * as much code as they need. Find link to source code below. 16 | * 17 | * @tutorial feature_markup 18 | * @constructor 19 | * @memberof Autodesk.Viewing.Extensions.Markups.Core 20 | * @extends Autodesk.Viewing.Extensions.Markups.Core.EditMode 21 | * @param {Autodesk.Viewing.Extensions.Markups.Core.MarkupsCore} editor 22 | */ 23 | export function EditModeCircle(editor) { 24 | 25 | var styleAttributes = ['stroke-width', 'stroke-color', 'stroke-opacity', 'fill-color', 'fill-opacity']; 26 | EditMode.call(this, editor, MarkupTypes.MARKUP_TYPE_CIRCLE, styleAttributes); 27 | } 28 | 29 | EditModeCircle.prototype = Object.create(EditMode.prototype); 30 | EditModeCircle.prototype.constructor = EditModeCircle; 31 | 32 | var proto = EditModeCircle.prototype; 33 | 34 | proto.deleteMarkup = function(markup, cantUndo) { 35 | 36 | markup = markup || this.selectedMarkup; 37 | if (markup && markup.type == this.type) { 38 | var deleteCircle = new DeleteCircle(this.editor, markup); 39 | deleteCircle.addToHistory = !cantUndo; 40 | deleteCircle.execute(); 41 | return true; 42 | } 43 | return false; 44 | }; 45 | 46 | /** 47 | * Handler to mouse move events, used to create markups. 48 | * @param {MouseEvent} event Mouse event. 49 | * @private 50 | */ 51 | proto.onMouseMove = function(event) { 52 | 53 | if (!EditMode.prototype.onMouseMove.call( this, event )) { 54 | return false; 55 | } 56 | 57 | var selectedMarkup = this.selectedMarkup; 58 | 59 | var editor = this.editor; 60 | 61 | var final = this.getFinalMouseDraggingPosition(); 62 | final = editor.clientToMarkups(final.x, final.y); 63 | 64 | var sizeX = Math.abs(this.firstPosition.x - final.x); 65 | var sizeY = Math.abs(this.firstPosition.y - final.y); 66 | 67 | var position = {x: (this.firstPosition.x + final.x) * 0.5, y: (this.firstPosition.y + final.y) * 0.5}; 68 | var size = this.size = {x: sizeX, y: sizeY}; 69 | 70 | var setCircle = new SetCircle( 71 | editor, 72 | selectedMarkup, 73 | position, 74 | size); 75 | 76 | setCircle.execute(); 77 | return true; 78 | }; 79 | 80 | /** 81 | * Handler to mouse down events, used to start markups creation. 82 | * @private 83 | */ 84 | proto.onMouseDown = function() { 85 | 86 | EditMode.prototype.onMouseDown.call(this); 87 | 88 | if (this.selectedMarkup) { 89 | return; 90 | } 91 | 92 | var editor = this.editor; 93 | var mousePosition = editor.getMousePosition(); 94 | 95 | this.initialX = mousePosition.x; 96 | this.initialY = mousePosition.y; 97 | 98 | // Calculate center and size. 99 | var position = this.firstPosition = editor.clientToMarkups(this.initialX, this.initialY); 100 | var size = this.size = editor.sizeFromClientToMarkups(1, 1); 101 | 102 | // Create circle. 103 | editor.beginActionGroup(); 104 | 105 | var markupId = editor.getId(); 106 | var create = new CreateCircle( 107 | editor, 108 | markupId, 109 | position, 110 | size, 111 | 0, 112 | this.style); 113 | create.execute(); 114 | 115 | this.selectedMarkup = editor.getMarkup(markupId); 116 | this.creationBegin(); 117 | }; 118 | -------------------------------------------------------------------------------- /Markup/core/MarkupRectangle.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { Markup } from './Markup'; 4 | import * as MarkupTypes from './MarkupTypes'; 5 | import { createMarkupPathSvg, composeRGBAString, createRectanglePath, 6 | setAttributeToMarkupSvg, updateMarkupPathSvgHitarea, addMarkupMetadata } from './MarkupsCoreUtils'; 7 | import { cloneStyle } from './StyleUtils'; 8 | import { EditModeRectangle } from './edit-modes/EditModeRectangle'; 9 | 10 | /** 11 | * Rectangle markup. 12 | * 13 | * Implements a Rectangle {@link Autodesk.Viewing.Extensions.Markups.Core.Markup|Markup}. 14 | * Included in documentation as an example of how to create 15 | * a specific markup type. Developers are encourage to look into this class's source code and copy 16 | * as much code as they need. Find link to source code below. 17 | * 18 | * @tutorial feature_markup 19 | * @constructor 20 | * @memberof Autodesk.Viewing.Extensions.Markups.Core 21 | * @extends Autodesk.Viewing.Extensions.Markups.Core.Markup 22 | * 23 | * @param {number} id 24 | * @param {Autodesk.Viewing.Extensions.Markups.Core.MarkupsCore} editor 25 | * @constructor 26 | */ 27 | export function MarkupRectangle(id, editor) { 28 | 29 | var styleAttributes = ['stroke-width', 'stroke-color', 'stroke-opacity', 'fill-color', 'fill-opacity']; 30 | Markup.call(this, id, editor, styleAttributes); 31 | 32 | // Bind to this to pass this.globalManager 33 | this.addMarkupMetadata = addMarkupMetadata.bind(this); 34 | 35 | this.type = MarkupTypes.MARKUP_TYPE_RECTANGLE; 36 | this.shape = createMarkupPathSvg(); 37 | 38 | this.bindDomEvents(); 39 | } 40 | 41 | MarkupRectangle.prototype = Object.create(Markup.prototype); 42 | MarkupRectangle.prototype.constructor = MarkupRectangle; 43 | 44 | var proto = MarkupRectangle.prototype; 45 | 46 | proto.getEditMode = function() { 47 | 48 | return new EditModeRectangle(this.editor); 49 | }; 50 | 51 | /** 52 | * Sets position and size in markup space coordinates 53 | * @param {Object} position 54 | * @param {Object} size 55 | */ 56 | proto.set = function(position, size) { 57 | 58 | this.position.x = position.x; 59 | this.position.y = position.y; 60 | this.size.x = size.x; 61 | this.size.y = size.y; 62 | 63 | this.updateStyle(); 64 | }; 65 | 66 | /** 67 | * Applies data values into DOM element style/attribute(s) 68 | * 69 | */ 70 | proto.updateStyle = function() { 71 | 72 | var style = this.style; 73 | var shape = this.shape; 74 | var path = this.getPath().join(' '); 75 | 76 | var strokeWidth = this.style['stroke-width']; 77 | var strokeColor = this.highlighted ? this.highlightColor : composeRGBAString(style['stroke-color'], style['stroke-opacity']); 78 | var fillColor = composeRGBAString(style['fill-color'], style['fill-opacity']); 79 | var transform = this.getTransform(); 80 | 81 | setAttributeToMarkupSvg(shape, 'd', path); 82 | setAttributeToMarkupSvg(shape, 'stroke-width', strokeWidth); 83 | setAttributeToMarkupSvg(shape, 'stroke', strokeColor); 84 | setAttributeToMarkupSvg(shape, 'fill', fillColor); 85 | setAttributeToMarkupSvg(shape, 'transform', transform); 86 | updateMarkupPathSvgHitarea(shape, this.editor); 87 | }; 88 | 89 | proto.setMetadata = function() { 90 | 91 | var metadata = cloneStyle(this.style); 92 | 93 | metadata.type = this.type; 94 | metadata.position = [this.position.x, this.position.y].join(" "); 95 | metadata.size = [this.size.x, this.size.y].join(" "); 96 | metadata.rotation = String(this.rotation); 97 | 98 | return this.addMarkupMetadata(this.shape, metadata); 99 | }; 100 | 101 | proto.getPath = function() { 102 | 103 | var strokeWidth = this.style['stroke-width']; 104 | 105 | var w = this.size.x - strokeWidth; 106 | var h = this.size.y - strokeWidth; 107 | var x =-w * 0.5; 108 | var y =-h * 0.5; 109 | 110 | var path = []; 111 | createRectanglePath(x, y, w, h, false, path); 112 | 113 | return path; 114 | }; 115 | -------------------------------------------------------------------------------- /Markup/core/MarkupEvents.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Fired whenever the drawing tool changes. For example, when the Arrow drawing 5 | * tool changes into the Rectangle drawing tool. 6 | * See {@link Autodesk.Viewing.Extensions.Markups.Core.MarkupsCore/#changeEditMode|MarkupsCore.changeEditMode()} 7 | * for a list of all supported drawing tools (EditModes). 8 | * 9 | * @event Autodesk.Viewing.Extensions.Markups.Core.MarkupsCore#EVENT_EDITMODE_CHANGED 10 | * @type {string} 11 | */ 12 | export const EVENT_EDITMODE_CHANGED = "EVENT_EDITMODE_CHANGED"; 13 | 14 | /** 15 | * Fired when Edit mode has been enabled, which allows the end user to start 16 | * drawing markups over the Viewer canvas. 17 | * See also {@link Autodesk.Viewing.Extensions.Markups.Core.MarkupsCore/#enterEditMode|MarkupsCore.enterEditMode()}. 18 | * 19 | * @event Autodesk.Viewing.Extensions.Markups.Core.MarkupsCore#EVENT_EDITMODE_ENTER 20 | * @type {string} 21 | */ 22 | export const EVENT_EDITMODE_ENTER = "EVENT_EDITMODE_ENTER"; 23 | 24 | /** 25 | * Fired when Edit mode has been disabled, preventing the end user from 26 | * drawing markups over the Viewer canvas. 27 | * See also {@link Autodesk.Viewing.Extensions.Markups.Core.MarkupsCore/#leaveEditMode|MarkupsCore.leaveEditMode()}. 28 | * 29 | * @event Autodesk.Viewing.Extensions.Markups.Core.MarkupsCore#EVENT_EDITMODE_LEAVE 30 | * @type {string} 31 | */ 32 | export const EVENT_EDITMODE_LEAVE = "EVENT_EDITMODE_LEAVE"; 33 | 34 | /** 35 | * Fired when a drawn markup has been selected by the end user with a click command. 36 | * 37 | * @event Autodesk.Viewing.Extensions.Markups.Core.MarkupsCore#EVENT_MARKUP_SELECTED 38 | * @type {string} 39 | */ 40 | export const EVENT_MARKUP_SELECTED = "EVENT_MARKUP_SELECTED"; 41 | 42 | /** 43 | * Fired when a drawn markup is being dragged over the Viewer canvas. 44 | * 45 | * @event Autodesk.Viewing.Extensions.Markups.Core.MarkupsCore#EVENT_MARKUP_DRAGGING 46 | * @type {string} 47 | */ 48 | export const EVENT_MARKUP_DRAGGING = "EVENT_MARKUP_DRAGGING"; 49 | 50 | /** 51 | * Internal usage only. 52 | * 53 | * @event Autodesk.Viewing.Extensions.Markups.Core.MarkupsCore#EVENT_MARKUP_ENTER_EDITION 54 | * @type {string} 55 | * @private 56 | */ 57 | export const EVENT_MARKUP_ENTER_EDITION = "EVENT_MARKUP_ENTER_EDITION"; 58 | 59 | /** 60 | * Internal usage only. 61 | * 62 | * @event Autodesk.Viewing.Extensions.Markups.Core.MarkupsCore#EVENT_MARKUP_CANCEL_EDITION 63 | * @type {string} 64 | * @private 65 | */ 66 | export const EVENT_MARKUP_CANCEL_EDITION = "EVENT_MARKUP_CANCEL_EDITION"; 67 | 68 | /** 69 | * Internal usage only. 70 | * 71 | * @event Autodesk.Viewing.Extensions.Markups.Core.MarkupsCore#EVENT_MARKUP_DELETE_EDITION 72 | * @type {string} 73 | * @private 74 | */ 75 | export const EVENT_MARKUP_DELETE_EDITION = "EVENT_MARKUP_DELETE_EDITION"; 76 | 77 | 78 | /** 79 | * Fired whenever a new undo or redo action is available. 80 | */ 81 | export const EVENT_HISTORY_CHANGED = "EVENT_HISTORY_CHANGED"; 82 | 83 | /** 84 | * Fired when a markup creation begins. 85 | * For example, as soon as the user starts dragging with the mouse 86 | * to draw an arrow on the screen. 87 | */ 88 | export const EVENT_EDITMODE_CREATION_BEGIN = "EVENT_EDITMODE_CREATION_BEGIN"; 89 | 90 | /** 91 | * Fired when a markup has been created. 92 | * For example, as soon as the user stops dragging and releases the 93 | * mouse button to finish drawing an arrow on the screen 94 | */ 95 | export const EVENT_EDITMODE_CREATION_END = "EVENT_EDITMODE_CREATION_END"; 96 | 97 | /** 98 | * Fired when a markup is no longer selected. 99 | */ 100 | export const EVENT_MARKUP_DESELECT = "EVENT_MARKUP_DESELECT"; 101 | 102 | /** 103 | * The selected markup is being modified 104 | */ 105 | export const EVENT_EDITFRAME_EDITION_START = "EVENT_EDITFRAME_EDITION_START"; 106 | 107 | /** 108 | * The selected markup is no longer being modified 109 | */ 110 | export const EVENT_EDITFRAME_EDITION_END = "EVENT_EDITFRAME_EDITION_END"; -------------------------------------------------------------------------------- /Markup/core/edit-actions/EditActionGroup.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * This class will group actions edit actions that should be executed as a whole. 5 | * When a group is open actions can be added to it, similar actions will be merged into one during this process. 6 | * This class is not intended to be used by users, it's a helper class of EditActionManager. 7 | * @constructor 8 | */ 9 | export function EditActionGroup() { 10 | 11 | this.actions = []; 12 | this.closed = true; 13 | } 14 | 15 | var proto = EditActionGroup.prototype; 16 | 17 | /** 18 | * 19 | * @returns {boolean} 20 | */ 21 | proto.open = function() { 22 | 23 | if(!this.closed) { 24 | return false; 25 | } 26 | 27 | this.closed = false; 28 | return true; 29 | }; 30 | 31 | /** 32 | * 33 | * @returns {boolean} 34 | */ 35 | proto.close = function() { 36 | 37 | if (this.closed) { 38 | return false; 39 | } 40 | 41 | this.closed = true; 42 | return true; 43 | }; 44 | 45 | /** 46 | * 47 | * @returns {number} targetId 48 | */ 49 | proto.undo = function() { 50 | 51 | var actions = this.actions; 52 | var actionsMaxIndex = actions.length - 1; 53 | 54 | var targetId = -1; 55 | for(var i = actionsMaxIndex; i >= 0; --i) { 56 | 57 | var action = actions[i]; 58 | action.undo(); 59 | 60 | if (action.targetId !== -1) { 61 | targetId = action.targetId; 62 | } 63 | } 64 | 65 | return targetId; 66 | }; 67 | 68 | /** 69 | * 70 | * @returns {number} targetId 71 | */ 72 | proto.redo = function() { 73 | 74 | var actions = this.actions; 75 | var actionsCount = actions.length; 76 | 77 | var targetId = -1; 78 | for(var i = 0; i < actionsCount; ++i) { 79 | 80 | var action = actions[i]; 81 | action.redo(); 82 | 83 | if (action.targetId !== -1) { 84 | targetId = action.targetId; 85 | } 86 | } 87 | 88 | return targetId; 89 | }; 90 | 91 | /** 92 | * 93 | * @returns {boolean} 94 | */ 95 | proto.isOpen = function() { 96 | 97 | return !this.closed; 98 | }; 99 | 100 | /** 101 | * 102 | * @returns {boolean} 103 | */ 104 | proto.isClosed = function() { 105 | 106 | return this.closed; 107 | }; 108 | 109 | /** 110 | * 111 | * @returns {boolean} 112 | */ 113 | proto.isEmpty = function() { 114 | 115 | return this.actions.length === 0; 116 | }; 117 | 118 | /** 119 | * 120 | * @param {EditAction} action 121 | */ 122 | proto.addAction = function(action) { 123 | 124 | if (this.closed) { 125 | return false; 126 | } 127 | 128 | this.actions.push(action); 129 | this.compact(); 130 | 131 | return true; 132 | }; 133 | 134 | /** 135 | * @private 136 | */ 137 | proto.compact = function() { 138 | 139 | var actions = this.actions; 140 | var actionsCount = actions.length; 141 | 142 | for(var i = 0; i < actionsCount; ++i) { 143 | 144 | // If an action does nothing, remove it. 145 | var actionA = actions[i]; 146 | if (actionA.isIdentity()) { 147 | actions.splice(i, 1); 148 | --actionsCount; 149 | --i; 150 | continue; 151 | } 152 | 153 | // If an action can be merged, merge it. 154 | for (var j = i + 1; j < actionsCount; ++j) { 155 | 156 | var actionB = actions[j]; 157 | if (actionA.type === actionB.type && 158 | actionA.merge(actionB)) { 159 | actions.splice(j, 1); 160 | --actionsCount; 161 | --i; 162 | break; 163 | } 164 | } 165 | } 166 | }; 167 | 168 | proto.getTargetId = function() { 169 | var actions = this.actions; 170 | var actionsCount = actions.length; 171 | var targetId = -1; 172 | for(var i = 0; i < actionsCount; ++i) { 173 | var action = actions[i]; 174 | if (action.targetId !== -1) { 175 | targetId = action.targetId; 176 | } 177 | } 178 | return targetId; 179 | }; -------------------------------------------------------------------------------- /Markup/core/MarkupStamp.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { Markup } from './Markup'; 4 | import * as MarkupTypes from './MarkupTypes'; 5 | import { composeRGBAString, addMarkupMetadata, 6 | stringToSvgNode, createSvgElement} from './MarkupsCoreUtils'; 7 | import { cloneStyle, copyStyle, isStyleEqual } from './StyleUtils'; 8 | import { EditModeStamp } from './edit-modes/EditModeStamp'; 9 | 10 | export { MarkupStamp }; 11 | 12 | class MarkupStamp extends Markup { 13 | /** 14 | * @param {number} id 15 | * @param {Autodesk.Viewing.Extensions.Markups.Core.MarkupsCore} editor 16 | */ 17 | constructor(id, editor, svgData) { 18 | const styleAttributes = [ 19 | 'text-data' 20 | ]; 21 | super(id, editor, styleAttributes); 22 | this.type = MarkupTypes.MARKUP_TYPE_STAMP; 23 | this.addMarkupMetadata = addMarkupMetadata.bind(this); 24 | 25 | this.createShapeGroup(); 26 | 27 | this.scriptSvgData = svgData; 28 | this.loadSvgData(); 29 | 30 | this.bindDomEvents(); 31 | } 32 | 33 | createShapeGroup() { 34 | /* 35 | * shape 36 | * group 37 | * customSvg 38 | * hitarea (aka markup) 39 | */ 40 | this.shape = createSvgElement('g'); 41 | this.shape.group = createSvgElement('g'); 42 | this.shape.appendChild(this.shape.group); 43 | 44 | let hitarea = createSvgElement('path'); 45 | hitarea.setAttribute('id', "hitarea"); 46 | hitarea.setAttribute('fill', "none"); 47 | this.shape.appendChild(hitarea); 48 | 49 | this.shape.hitarea = hitarea; 50 | this.shape.markup = hitarea; 51 | } 52 | 53 | loadSvgData() { 54 | let svgString = this.scriptSvgData || this.style['text-data']; 55 | let svgNode = stringToSvgNode(svgString); 56 | 57 | // null if parsing fails, so exit 58 | if (svgNode === null) { 59 | console.warn("SVG data " + svgString + " is invalid, skipping shape update"); 60 | return; 61 | } 62 | 63 | let [width, height] = this.getDimensions(svgNode); 64 | 65 | // update the bounding box when the SVG is changed 66 | let path = `M 0 0 l ${width} 0 l 0 ${height} l ${-width} 0 z`; 67 | this.shape.hitarea.setAttribute('d', path); 68 | 69 | this.shape.group.innerHTML = svgNode.innerHTML; 70 | 71 | // This is to standardize things: 72 | // width and height are 1 unit 73 | // position is in the centre 74 | // have to flip things because of y axis going upwards 75 | this.shape.group.setAttribute('transform', `translate( -0.5 , 0.5 ) scale( ${1/width} , ${-1/height} )`); 76 | // then copy to the hitarea because it's outside the SVG 77 | this.shape.hitarea.setAttribute('transform', this.shape.group.getAttribute('transform')); 78 | } 79 | 80 | getEditMode() { 81 | return new EditModeStamp(this.editor); 82 | } 83 | 84 | set(position, size) { 85 | this.setSize(position, size.x, size.y); 86 | this.updateStyle(); 87 | } 88 | 89 | updateStyle(styleChanged) { 90 | const strokeColor = this.highlighted ? this.highlightColor : composeRGBAString(this.style['stroke-color'], this.style['stroke-opacity']); 91 | this.shape.hitarea.setAttribute('stroke', strokeColor); 92 | 93 | // This only provides translation and rotation, not scale 94 | const transform = this.getTransform() + ` scale( ${this.size.x} , ${this.size.y} )`; 95 | this.shape.setAttribute('transform', transform); 96 | 97 | if (styleChanged) { 98 | this.loadSvgData(); 99 | } 100 | } 101 | 102 | getDimensions(customSvg) { 103 | let vb = customSvg.getAttribute('viewBox'); 104 | if (!vb) { 105 | // if no viewbox is specified, check for width and height 106 | let width = customSvg.getAttribute('width') || 100; 107 | let height = customSvg.getAttribute('height') || 100; 108 | return [width, height]; 109 | } 110 | let strings = vb.split(' '); 111 | let width = parseInt(strings[2]); 112 | let height = parseInt(strings[3]); 113 | 114 | return [width, height]; 115 | } 116 | 117 | setMetadata() { 118 | 119 | var metadata = cloneStyle(this.style); 120 | 121 | metadata.type = this.type; 122 | metadata.position = [this.position.x, this.position.y].join(" "); 123 | metadata.size = [this.size.x, this.size.y].join(" "); 124 | metadata.rotation = String(this.rotation); 125 | 126 | return this.addMarkupMetadata(this.shape, metadata); 127 | } 128 | 129 | setStyle(style) { 130 | let stylesEqual = isStyleEqual(style, this.style); 131 | if (!stylesEqual) { 132 | copyStyle(style, this.style); 133 | } 134 | 135 | this.updateStyle(!stylesEqual); 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /webpack.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | var fs = require('fs'); 3 | var path = require('path'); 4 | 5 | function NullPlugin() { 6 | this.apply = function(){}; 7 | } 8 | 9 | // Give process a more descriptive name than just "npm" 10 | process.title = 'lmv-webpack'; 11 | 12 | /** 13 | * Exports a function that returns an array of webpack configurations to run in parallel. 14 | * 15 | * @param {object} env - Object containing command-line supplied variables 16 | */ 17 | module.exports = function(env) { 18 | 19 | const PROD_BUILD = env.BUILD_PROD; 20 | 21 | // Defaults for local developer builds 22 | var build_version = env.BUILD_VERSION; 23 | var build_type = env.BUILD_TYPE || 'local'; 24 | 25 | /** 26 | * 27 | * @param {boolean} [extractCss=false] - Whether a CSS file will get generated (true) or not (false) 28 | */ 29 | function getModuleConfig(extractCss) { 30 | var moduleConfig = { 31 | rules: [ 32 | { 33 | test: /\.js$/, 34 | include: [ 35 | path.resolve(__dirname, "../extensions"), 36 | ], 37 | exclude: [/\.min.js$/], //the min.js is for zlib pre-built modules 38 | use: { 39 | loader: 'babel-loader', 40 | options: { 41 | cacheDirectory: '.babel', 42 | presets: ['@babel/preset-env'], 43 | compact: false, 44 | retainLines: true 45 | } 46 | } 47 | }, 48 | { 49 | test: /\.svg$/, 50 | loader: 'svg-url-loader' 51 | } 52 | ], 53 | noParse: [ 54 | /\.min.js$/ 55 | ] 56 | }; 57 | 58 | if (extractCss) { 59 | } else { 60 | // CSS styles will be included into the HTML by inserting