UNPKG

markgojs

Version:

Interactive diagrams, charts, and graphs, such as trees, flowcharts, orgcharts, UML, BPMN, or business diagrams

385 lines (384 loc) 17.3 kB
var __extends = (this && this.__extends) || (function () { var extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); (function (factory) { if (typeof module === "object" && typeof module.exports === "object") { var v = factory(require, exports); if (v !== undefined) module.exports = v; } else if (typeof define === "function" && define.amd) { define(["require", "exports", "../release/go"], factory); } })(function (require, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); /* * Copyright (C) 1998-2019 by Northwoods Software Corporation. All Rights Reserved. */ // A custom Tool for drawing polygons or polylines var go = require("../release/go"); /** * @constructor * @extends Tool * @class * This tool allows the user to draw a new polygon or polyline shape by clicking where the corners should go. * Right click or type ENTER to finish the operation. * <p/> * Set {@link #isPolygon} to false if you want this tool to draw open unfilled polyline shapes. * Set {@link #archetypePartData} to customize the node data object that is added to the model. * Data-bind to those properties in your node template to customize the appearance and behavior of the part. * <p/> * This tool uses a temporary {@link Shape}, {@link #temporaryShape}, held by a {@link Part} in the "Tool" layer, * to show interactively what the user is drawing. */ var PolygonDrawingTool = /** @class */ (function (_super) { __extends(PolygonDrawingTool, _super); function PolygonDrawingTool() { var _this = _super.call(this) || this; _this._isPolygon = true; _this._hasArcs = false; _this._archetypePartData = {}; // the data to copy for a new polygon Part // this is the Shape that is shown during a drawing operation _this._temporaryShape = go.GraphObject.make(go.Shape, { name: "SHAPE", fill: "lightgray", strokeWidth: 1.5 }); // the Shape has to be inside a temporary Part that is used during the drawing operation _this.temp = go.GraphObject.make(go.Part, { layerName: "Tool" }, _this._temporaryShape); _this.name = "PolygonDrawing"; return _this; } /** * Don't start this tool in a mode-less fashion when the user's mouse-down is on an existing Part. * When this tool is a mouse-down tool, it requires using the left mouse button in the background of a modifiable Diagram. * Modal uses of this tool will not call this canStart predicate. * @this {PolygonDrawingTool} */ PolygonDrawingTool.prototype.canStart = function () { if (!this.isEnabled) return false; var diagram = this.diagram; if (diagram === null || diagram.isReadOnly || diagram.isModelReadOnly) return false; var model = diagram.model; if (model === null) return false; // require left button if (!diagram.firstInput.left) return false; // can't start when mouse-down on an existing Part var obj = diagram.findObjectAt(diagram.firstInput.documentPoint, null, null); return (obj === null); }; ; /** * Start a transaction, capture the mouse, use a "crosshair" cursor, * and start accumulating points in the geometry of the {@link #temporaryShape}. * @this {PolygonDrawingTool} */ PolygonDrawingTool.prototype.doActivate = function () { _super.prototype.doActivate.call(this); var diagram = this.diagram; this.startTransaction(this.name); if (!diagram.lastInput.isTouchEvent) diagram.isMouseCaptured = true; diagram.currentCursor = "crosshair"; // the first point if (!diagram.lastInput.isTouchEvent) this.addPoint(diagram.lastInput.documentPoint); }; ; /** * Stop the transaction and clean up. * @this {PolygonDrawingTool} */ PolygonDrawingTool.prototype.doDeactivate = function () { _super.prototype.doDeactivate.call(this); var diagram = this.diagram; if (this.temporaryShape !== null) { diagram.remove(this.temporaryShape.part); } diagram.currentCursor = ""; if (diagram.isMouseCaptured) diagram.isMouseCaptured = false; this.stopTransaction(); }; ; /** * This internal method adds a segment to the geometry of the {@link #temporaryShape}. * @this {PolygonDrawingTool} */ PolygonDrawingTool.prototype.addPoint = function (p) { var shape = this.temporaryShape; if (shape === null) return; // for the temporary Shape, normalize the geometry to be in the viewport var viewpt = this.diagram.viewportBounds.position; var q = new go.Point(p.x - viewpt.x, p.y - viewpt.y); var part = shape.part; // if it's not in the Diagram, re-initialize the Shape's geometry and add the Part to the Diagram if (part.diagram === null) { var fig = new go.PathFigure(q.x, q.y, true); // possibly filled, depending on Shape.fill var geo = new go.Geometry().add(fig); // the Shape.geometry consists of a single PathFigure this.temporaryShape.geometry = geo; // position the Shape's Part, accounting for the stroke width part.position = viewpt.copy().offset(-shape.strokeWidth / 2, -shape.strokeWidth / 2); this.diagram.add(part); } else { // must copy whole Geometry in order to add a PathSegment var geo = shape.geometry.copy(); var fig = geo.figures.first(); if (this.hasArcs) { var lastseg = fig.segments.last(); if (lastseg === null) { fig.add(new go.PathSegment(go.PathSegment.QuadraticBezier, q.x, q.y, (fig.startX + q.x) / 2, (fig.startY + q.y) / 2)); } else { fig.add(new go.PathSegment(go.PathSegment.QuadraticBezier, q.x, q.y, (lastseg.endX + q.x) / 2, (lastseg.endY + q.y) / 2)); } } else { fig.add(new go.PathSegment(go.PathSegment.Line, q.x, q.y)); } } shape.geometry = geo; }; ; /** * This internal method changes the last segment of the geometry of the {@link #temporaryShape} to end at the given point. * @this {PolygonDrawingTool} */ PolygonDrawingTool.prototype.moveLastPoint = function (p) { // must copy whole Geometry in order to change a PathSegment var shape = this.temporaryShape; var geo = shape.geometry.copy(); var fig = geo.figures.first(); var segs = fig.segments; if (segs.count > 0) { // for the temporary Shape, normalize the geometry to be in the viewport var viewpt = this.diagram.viewportBounds.position; var seg = segs.elt(segs.count - 1); // modify the last PathSegment to be the given Point p seg.endX = p.x - viewpt.x; seg.endY = p.y - viewpt.y; if (seg.type === go.PathSegment.QuadraticBezier) { var prevx = 0.0; var prevy = 0.0; if (segs.count > 1) { var prevseg = segs.elt(segs.count - 2); prevx = prevseg.endX; prevy = prevseg.endY; } else { prevx = fig.startX; prevy = fig.startY; } seg.point1X = (seg.endX + prevx) / 2; seg.point1Y = (seg.endY + prevy) / 2; } shape.geometry = geo; } }; ; /** * This internal method removes the last segment of the geometry of the {@link #temporaryShape}. * @this {PolygonDrawingTool} */ PolygonDrawingTool.prototype.removeLastPoint = function () { // must copy whole Geometry in order to remove a PathSegment var shape = this.temporaryShape; var geo = shape.geometry.copy(); var segs = geo.figures.first().segments; if (segs.count > 0) { segs.removeAt(segs.count - 1); shape.geometry = geo; } }; ; /** * Add a new node data JavaScript object to the model and initialize the Part's * position and its Shape's geometry by copying the {@link #temporaryShape}'s {@link Shape#geometry}. * @this {PolygonDrawingTool} */ PolygonDrawingTool.prototype.finishShape = function () { var diagram = this.diagram; var shape = this.temporaryShape; if (shape !== null && this.archetypePartData !== null) { // remove the temporary point, which is last, except on touch devices if (!diagram.lastInput.isTouchEvent) this.removeLastPoint(); var tempgeo = shape.geometry; // require 3 points (2 segments) if polygon; 2 points (1 segment) if polyline if (tempgeo.figures.first().segments.count >= (this.isPolygon ? 2 : 1)) { // normalize geometry and node position var viewpt = diagram.viewportBounds.position; var geo = tempgeo.copy(); if (this.isPolygon) { // if polygon, close the last segment var segs = geo.figures.first().segments; var seg = segs.elt(segs.count - 1); seg.isClosed = true; } // create the node data for the model var d = diagram.model.copyNodeData(this.archetypePartData); // adding data to model creates the actual Part diagram.model.addNodeData(d); var part = diagram.findPartForData(d); // assign the position for the whole Part var pos = geo.normalize(); pos.x = viewpt.x - pos.x - shape.strokeWidth / 2; pos.y = viewpt.y - pos.y - shape.strokeWidth / 2; part.position = pos; // assign the Shape.geometry var shape = part.findObject("SHAPE"); if (shape !== null) shape.geometry = geo; this.transactionResult = this.name; } } this.stopTool(); }; ; /** * Add another point to the geometry of the {@link #temporaryShape}. * @this {PolygonDrawingTool} */ PolygonDrawingTool.prototype.doMouseDown = function () { if (!this.isActive) { this.doActivate(); } // a new temporary end point, the previous one is now "accepted" this.addPoint(this.diagram.lastInput.documentPoint); if (!this.diagram.lastInput.left) { // e.g. right mouse down this.finishShape(); } else if (this.diagram.lastInput.clickCount > 1) { // e.g. double-click this.removeLastPoint(); this.finishShape(); } }; ; /** * Move the last point of the {@link #temporaryShape}'s geometry to follow the mouse point. * @this {PolygonDrawingTool} */ PolygonDrawingTool.prototype.doMouseMove = function () { if (this.isActive) { this.moveLastPoint(this.diagram.lastInput.documentPoint); } }; ; /** * Do not stop this tool, but continue to accumulate Points via mouse-down events. * @this {PolygonDrawingTool} */ PolygonDrawingTool.prototype.doMouseUp = function () { // don't stop this tool (the default behavior is to call stopTool) }; ; /** * Typing the "ENTER" key accepts the current geometry (excluding the current mouse point) * and creates a new part in the model by calling {@link #finishShape}. * <p/> * Typing the "Z" key causes the previous point to be discarded. * <p/> * Typing the "ESCAPE" key causes the temporary Shape and its geometry to be discarded and this tool to be stopped. * @this {PolygonDrawingTool} */ PolygonDrawingTool.prototype.doKeyDown = function () { if (!this.isActive) return; var e = this.diagram.lastInput; if (e.key === '\r') { // accept this.finishShape(); // all done! } else if (e.key === 'Z') { // undo this.undo(); } else { _super.prototype.doKeyDown.call(this); } }; ; /** * Undo: remove the last point and continue the drawing of new points. * @this {PolygonDrawingTool} */ PolygonDrawingTool.prototype.undo = function () { // remove a point, and then treat the last one as a temporary one this.removeLastPoint(); var lastInput = this.diagram.lastInput; if (lastInput.event instanceof MouseEvent) this.moveLastPoint(lastInput.documentPoint); }; ; Object.defineProperty(PolygonDrawingTool.prototype, "isPolygon", { // Public properties /** * Gets or sets whether this tools draws a filled polygon or an unfilled open polyline. * The default value is true. * @name PolygonDrawingTool#isPolygon * @function. * @return {boolean} */ get: function () { return this._isPolygon; }, set: function (val) { this._isPolygon = val; }, enumerable: true, configurable: true }); Object.defineProperty(PolygonDrawingTool.prototype, "hasArcs", { /** * Gets or sets whether this tools draws shapes with quadratic bezier curves for each segment, or just straight lines. * The default value is false -- only use straight lines. * @name PolygonDrawingTool#hasArcs * @function. * @return {boolean} */ get: function () { return this._hasArcs; }, set: function (val) { this._hasArcs = val; }, enumerable: true, configurable: true }); Object.defineProperty(PolygonDrawingTool.prototype, "temporaryShape", { /** * Gets or sets the Shape that is used to hold the line as it is being drawn. * The default value is a simple Shape drawing an unfilled open thin black line. * @name PolygonDrawingTool#temporaryShape * @function. * @return {Shape} */ get: function () { return this._temporaryShape; }, set: function (val) { if (this._temporaryShape !== val && val !== null) { val.name = "SHAPE"; var panel = this._temporaryShape.panel; panel.remove(this._temporaryShape); this._temporaryShape = val; panel.add(this._temporaryShape); } }, enumerable: true, configurable: true }); Object.defineProperty(PolygonDrawingTool.prototype, "archetypePartData", { /** * Gets or sets the node data object that is copied and added to the model * when the drawing operation completes. * @name PolygonDrawingTool#archetypePartData * @function. * @return {Object} */ get: function () { return this._archetypePartData; }, set: function (val) { this._archetypePartData = val; }, enumerable: true, configurable: true }); return PolygonDrawingTool; }(go.Tool)); exports.PolygonDrawingTool = PolygonDrawingTool; });