mxOutline.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764
  1. /**
  2. * Copyright (c) 2006-2015, JGraph Ltd
  3. * Copyright (c) 2006-2015, Gaudenz Alder
  4. */
  5. /**
  6. * Class: mxOutline
  7. *
  8. * Implements an outline (aka overview) for a graph. Set <updateOnPan> to true
  9. * to enable updates while the source graph is panning.
  10. *
  11. * Example:
  12. *
  13. * (code)
  14. * var outline = new mxOutline(graph, div);
  15. * (end)
  16. *
  17. * If an outline is used in an <mxWindow> in IE8 standards mode, the following
  18. * code makes sure that the shadow filter is not inherited and that any
  19. * transparent elements in the graph do not show the page background, but the
  20. * background of the graph container.
  21. *
  22. * (code)
  23. * if (document.documentMode == 8)
  24. * {
  25. * container.style.filter = 'progid:DXImageTransform.Microsoft.alpha(opacity=100)';
  26. * }
  27. * (end)
  28. *
  29. * To move the graph to the top, left corner the following code can be used.
  30. *
  31. * (code)
  32. * var scale = graph.view.scale;
  33. * var bounds = graph.getGraphBounds();
  34. * graph.view.setTranslate(-bounds.x / scale, -bounds.y / scale);
  35. * (end)
  36. *
  37. * To toggle the suspended mode, the following can be used.
  38. *
  39. * (code)
  40. * outline.suspended = !outln.suspended;
  41. * if (!outline.suspended)
  42. * {
  43. * outline.update(true);
  44. * }
  45. * (end)
  46. *
  47. * Constructor: mxOutline
  48. *
  49. * Constructs a new outline for the specified graph inside the given
  50. * container.
  51. *
  52. * Parameters:
  53. *
  54. * source - <mxGraph> to create the outline for.
  55. * container - DOM node that will contain the outline.
  56. */
  57. function mxOutline(source, container)
  58. {
  59. this.source = source;
  60. if (container != null)
  61. {
  62. this.init(container);
  63. }
  64. };
  65. /**
  66. * Function: source
  67. *
  68. * Reference to the source <mxGraph>.
  69. */
  70. mxOutline.prototype.source = null;
  71. /**
  72. * Function: outline
  73. *
  74. * Reference to the <mxGraph> that renders the outline.
  75. */
  76. mxOutline.prototype.outline = null;
  77. /**
  78. * Function: graphRenderHint
  79. *
  80. * Renderhint to be used for the outline graph. Default is faster.
  81. */
  82. mxOutline.prototype.graphRenderHint = mxConstants.RENDERING_HINT_FASTER;
  83. /**
  84. * Variable: enabled
  85. *
  86. * Specifies if events are handled. Default is true.
  87. */
  88. mxOutline.prototype.enabled = true;
  89. /**
  90. * Variable: showViewport
  91. *
  92. * Specifies a viewport rectangle should be shown. Default is true.
  93. */
  94. mxOutline.prototype.showViewport = true;
  95. /**
  96. * Variable: border
  97. *
  98. * Border to be added at the bottom and right. Default is 10.
  99. */
  100. mxOutline.prototype.border = 10;
  101. /**
  102. * Variable: enabled
  103. *
  104. * Specifies the size of the sizer handler. Default is 8.
  105. */
  106. mxOutline.prototype.sizerSize = 8;
  107. /**
  108. * Variable: labelsVisible
  109. *
  110. * Specifies if labels should be visible in the outline. Default is false.
  111. */
  112. mxOutline.prototype.labelsVisible = false;
  113. /**
  114. * Variable: updateOnPan
  115. *
  116. * Specifies if <update> should be called for <mxEvent.PAN> in the source
  117. * graph. Default is false.
  118. */
  119. mxOutline.prototype.updateOnPan = false;
  120. /**
  121. * Variable: sizerImage
  122. *
  123. * Optional <mxImage> to be used for the sizer. Default is null.
  124. */
  125. mxOutline.prototype.sizerImage = null;
  126. /**
  127. * Variable: minScale
  128. *
  129. * Minimum scale to be used. Default is 0.0001.
  130. */
  131. mxOutline.prototype.minScale = 0.0001;
  132. /**
  133. * Variable: suspended
  134. *
  135. * Optional boolean flag to suspend updates. Default is false. This flag will
  136. * also suspend repaints of the outline. To toggle this switch, use the
  137. * following code.
  138. *
  139. * (code)
  140. * nav.suspended = !nav.suspended;
  141. *
  142. * if (!nav.suspended)
  143. * {
  144. * nav.update(true);
  145. * }
  146. * (end)
  147. */
  148. mxOutline.prototype.suspended = false;
  149. /**
  150. * Variable: forceVmlHandles
  151. *
  152. * Specifies if VML should be used to render the handles in this control. This
  153. * is true for IE8 standards mode and false for all other browsers and modes.
  154. * This is a workaround for rendering issues of HTML elements over elements
  155. * with filters in IE 8 standards mode.
  156. */
  157. mxOutline.prototype.forceVmlHandles = document.documentMode == 8;
  158. /**
  159. * Function: createGraph
  160. *
  161. * Creates the <mxGraph> used in the outline.
  162. */
  163. mxOutline.prototype.createGraph = function(container)
  164. {
  165. var graph = new mxGraph(container, this.source.getModel(), this.graphRenderHint, this.source.getStylesheet());
  166. graph.foldingEnabled = false;
  167. graph.autoScroll = false;
  168. return graph;
  169. };
  170. /**
  171. * Function: init
  172. *
  173. * Initializes the outline inside the given container.
  174. */
  175. mxOutline.prototype.init = function(container)
  176. {
  177. this.outline = this.createGraph(container);
  178. // Do not repaint when suspended
  179. var outlineGraphModelChanged = this.outline.graphModelChanged;
  180. this.outline.graphModelChanged = mxUtils.bind(this, function(changes)
  181. {
  182. if (!this.suspended && this.outline != null)
  183. {
  184. outlineGraphModelChanged.apply(this.outline, arguments);
  185. }
  186. });
  187. // Enables faster painting in SVG
  188. if (mxClient.IS_SVG)
  189. {
  190. var node = this.outline.getView().getCanvas().parentNode;
  191. node.setAttribute('shape-rendering', 'optimizeSpeed');
  192. node.setAttribute('image-rendering', 'optimizeSpeed');
  193. }
  194. // Hides cursors and labels
  195. this.outline.labelsVisible = this.labelsVisible;
  196. this.outline.setEnabled(false);
  197. this.updateHandler = mxUtils.bind(this, function(sender, evt)
  198. {
  199. if (!this.suspended && !this.active)
  200. {
  201. this.update();
  202. }
  203. });
  204. // Updates the scale of the outline after a change of the main graph
  205. this.source.getModel().addListener(mxEvent.CHANGE, this.updateHandler);
  206. this.outline.addMouseListener(this);
  207. // Adds listeners to keep the outline in sync with the source graph
  208. var view = this.source.getView();
  209. view.addListener(mxEvent.SCALE, this.updateHandler);
  210. view.addListener(mxEvent.TRANSLATE, this.updateHandler);
  211. view.addListener(mxEvent.SCALE_AND_TRANSLATE, this.updateHandler);
  212. view.addListener(mxEvent.DOWN, this.updateHandler);
  213. view.addListener(mxEvent.UP, this.updateHandler);
  214. // Updates blue rectangle on scroll
  215. mxEvent.addListener(this.source.container, 'scroll', this.updateHandler);
  216. this.panHandler = mxUtils.bind(this, function(sender)
  217. {
  218. if (this.updateOnPan)
  219. {
  220. this.updateHandler.apply(this, arguments);
  221. }
  222. });
  223. this.source.addListener(mxEvent.PAN, this.panHandler);
  224. // Refreshes the graph in the outline after a refresh of the main graph
  225. this.refreshHandler = mxUtils.bind(this, function(sender)
  226. {
  227. this.outline.setStylesheet(this.source.getStylesheet());
  228. this.outline.refresh();
  229. });
  230. this.source.addListener(mxEvent.REFRESH, this.refreshHandler);
  231. // Creates the blue rectangle for the viewport
  232. this.bounds = new mxRectangle(0, 0, 0, 0);
  233. this.selectionBorder = new mxRectangleShape(this.bounds, null,
  234. mxConstants.OUTLINE_COLOR, mxConstants.OUTLINE_STROKEWIDTH);
  235. this.selectionBorder.dialect = this.outline.dialect;
  236. if (this.forceVmlHandles)
  237. {
  238. this.selectionBorder.isHtmlAllowed = function()
  239. {
  240. return false;
  241. };
  242. }
  243. this.selectionBorder.init(this.outline.getView().getOverlayPane());
  244. // Handles event by catching the initial pointer start and then listening to the
  245. // complete gesture on the event target. This is needed because all the events
  246. // are routed via the initial element even if that element is removed from the
  247. // DOM, which happens when we repaint the selection border and zoom handles.
  248. var handler = mxUtils.bind(this, function(evt)
  249. {
  250. var t = mxEvent.getSource(evt);
  251. var redirect = mxUtils.bind(this, function(evt)
  252. {
  253. this.outline.fireMouseEvent(mxEvent.MOUSE_MOVE, new mxMouseEvent(evt));
  254. });
  255. var redirect2 = mxUtils.bind(this, function(evt)
  256. {
  257. mxEvent.removeGestureListeners(t, null, redirect, redirect2);
  258. this.outline.fireMouseEvent(mxEvent.MOUSE_UP, new mxMouseEvent(evt));
  259. });
  260. mxEvent.addGestureListeners(t, null, redirect, redirect2);
  261. this.outline.fireMouseEvent(mxEvent.MOUSE_DOWN, new mxMouseEvent(evt));
  262. });
  263. mxEvent.addGestureListeners(this.selectionBorder.node, handler);
  264. // Creates a small blue rectangle for sizing (sizer handle)
  265. this.sizer = this.createSizer();
  266. if (this.forceVmlHandles)
  267. {
  268. this.sizer.isHtmlAllowed = function()
  269. {
  270. return false;
  271. };
  272. }
  273. this.sizer.init(this.outline.getView().getOverlayPane());
  274. if (this.enabled)
  275. {
  276. this.sizer.node.style.cursor = 'nwse-resize';
  277. }
  278. mxEvent.addGestureListeners(this.sizer.node, handler);
  279. this.selectionBorder.node.style.display = (this.showViewport) ? '' : 'none';
  280. this.sizer.node.style.display = this.selectionBorder.node.style.display;
  281. this.selectionBorder.node.style.cursor = 'move';
  282. this.update(false);
  283. };
  284. /**
  285. * Function: isEnabled
  286. *
  287. * Returns true if events are handled. This implementation
  288. * returns <enabled>.
  289. */
  290. mxOutline.prototype.isEnabled = function()
  291. {
  292. return this.enabled;
  293. };
  294. /**
  295. * Function: setEnabled
  296. *
  297. * Enables or disables event handling. This implementation
  298. * updates <enabled>.
  299. *
  300. * Parameters:
  301. *
  302. * value - Boolean that specifies the new enabled state.
  303. */
  304. mxOutline.prototype.setEnabled = function(value)
  305. {
  306. this.enabled = value;
  307. };
  308. /**
  309. * Function: setZoomEnabled
  310. *
  311. * Enables or disables the zoom handling by showing or hiding the respective
  312. * handle.
  313. *
  314. * Parameters:
  315. *
  316. * value - Boolean that specifies the new enabled state.
  317. */
  318. mxOutline.prototype.setZoomEnabled = function(value)
  319. {
  320. this.sizer.node.style.visibility = (value) ? 'visible' : 'hidden';
  321. };
  322. /**
  323. * Function: refresh
  324. *
  325. * Invokes <update> and revalidate the outline. This method is deprecated.
  326. */
  327. mxOutline.prototype.refresh = function()
  328. {
  329. this.update(true);
  330. };
  331. /**
  332. * Function: createSizer
  333. *
  334. * Creates the shape used as the sizer.
  335. */
  336. mxOutline.prototype.createSizer = function()
  337. {
  338. if (this.sizerImage != null)
  339. {
  340. var sizer = new mxImageShape(new mxRectangle(0, 0, this.sizerImage.width, this.sizerImage.height), this.sizerImage.src);
  341. sizer.dialect = this.outline.dialect;
  342. return sizer;
  343. }
  344. else
  345. {
  346. var sizer = new mxRectangleShape(new mxRectangle(0, 0, this.sizerSize, this.sizerSize),
  347. mxConstants.OUTLINE_HANDLE_FILLCOLOR, mxConstants.OUTLINE_HANDLE_STROKECOLOR);
  348. sizer.dialect = this.outline.dialect;
  349. return sizer;
  350. }
  351. };
  352. /**
  353. * Function: getSourceContainerSize
  354. *
  355. * Returns the size of the source container.
  356. */
  357. mxOutline.prototype.getSourceContainerSize = function()
  358. {
  359. return new mxRectangle(0, 0, this.source.container.scrollWidth, this.source.container.scrollHeight);
  360. };
  361. /**
  362. * Function: getOutlineOffset
  363. *
  364. * Returns the offset for drawing the outline graph.
  365. */
  366. mxOutline.prototype.getOutlineOffset = function(scale)
  367. {
  368. return null;
  369. };
  370. /**
  371. * Function: getSourceGraphBounds
  372. *
  373. * Returns the graph bound boxing of the source.
  374. */
  375. mxOutline.prototype.getSourceGraphBounds = function()
  376. {
  377. return this.source.getGraphBounds();
  378. };
  379. /**
  380. * Function: update
  381. *
  382. * Updates the outline.
  383. */
  384. mxOutline.prototype.update = function(revalidate)
  385. {
  386. if (this.source != null && this.source.container != null &&
  387. this.outline != null && this.outline.container != null)
  388. {
  389. var sourceScale = this.source.view.scale;
  390. var scaledGraphBounds = this.getSourceGraphBounds();
  391. var unscaledGraphBounds = new mxRectangle(scaledGraphBounds.x / sourceScale + this.source.panDx,
  392. scaledGraphBounds.y / sourceScale + this.source.panDy, scaledGraphBounds.width / sourceScale,
  393. scaledGraphBounds.height / sourceScale);
  394. var unscaledFinderBounds = new mxRectangle(0, 0,
  395. this.source.container.clientWidth / sourceScale,
  396. this.source.container.clientHeight / sourceScale);
  397. var union = unscaledGraphBounds.clone();
  398. union.add(unscaledFinderBounds);
  399. // Zooms to the scrollable area if that is bigger than the graph
  400. var size = this.getSourceContainerSize();
  401. var completeWidth = Math.max(size.width / sourceScale, union.width);
  402. var completeHeight = Math.max(size.height / sourceScale, union.height);
  403. var availableWidth = Math.max(0, this.outline.container.clientWidth - this.border);
  404. var availableHeight = Math.max(0, this.outline.container.clientHeight - this.border);
  405. var outlineScale = Math.min(availableWidth / completeWidth, availableHeight / completeHeight);
  406. var scale = (isNaN(outlineScale)) ? this.minScale : Math.max(this.minScale, outlineScale);
  407. if (scale > 0)
  408. {
  409. if (this.outline.getView().scale != scale)
  410. {
  411. this.outline.getView().scale = scale;
  412. revalidate = true;
  413. }
  414. var navView = this.outline.getView();
  415. if (navView.currentRoot != this.source.getView().currentRoot)
  416. {
  417. navView.setCurrentRoot(this.source.getView().currentRoot);
  418. }
  419. var t = this.source.view.translate;
  420. var tx = t.x + this.source.panDx;
  421. var ty = t.y + this.source.panDy;
  422. var off = this.getOutlineOffset(scale);
  423. if (off != null)
  424. {
  425. tx += off.x;
  426. ty += off.y;
  427. }
  428. if (unscaledGraphBounds.x < 0)
  429. {
  430. tx = tx - unscaledGraphBounds.x;
  431. }
  432. if (unscaledGraphBounds.y < 0)
  433. {
  434. ty = ty - unscaledGraphBounds.y;
  435. }
  436. if (navView.translate.x != tx || navView.translate.y != ty)
  437. {
  438. navView.translate.x = tx;
  439. navView.translate.y = ty;
  440. revalidate = true;
  441. }
  442. // Prepares local variables for computations
  443. var t2 = navView.translate;
  444. scale = this.source.getView().scale;
  445. var scale2 = scale / navView.scale;
  446. var scale3 = 1.0 / navView.scale;
  447. var container = this.source.container;
  448. // Updates the bounds of the viewrect in the navigation
  449. this.bounds = new mxRectangle(
  450. (t2.x - t.x - this.source.panDx) / scale3,
  451. (t2.y - t.y - this.source.panDy) / scale3,
  452. (container.clientWidth / scale2),
  453. (container.clientHeight / scale2));
  454. // Adds the scrollbar offset to the finder
  455. this.bounds.x += this.source.container.scrollLeft * navView.scale / scale;
  456. this.bounds.y += this.source.container.scrollTop * navView.scale / scale;
  457. var b = this.selectionBorder.bounds;
  458. if (b.x != this.bounds.x || b.y != this.bounds.y || b.width != this.bounds.width || b.height != this.bounds.height)
  459. {
  460. this.selectionBorder.bounds = this.bounds;
  461. this.selectionBorder.redraw();
  462. }
  463. // Updates the bounds of the zoom handle at the bottom right
  464. var b = this.sizer.bounds;
  465. var b2 = new mxRectangle(this.bounds.x + this.bounds.width - b.width / 2,
  466. this.bounds.y + this.bounds.height - b.height / 2, b.width, b.height);
  467. if (b.x != b2.x || b.y != b2.y || b.width != b2.width || b.height != b2.height)
  468. {
  469. this.sizer.bounds = b2;
  470. // Avoids update of visibility in redraw for VML
  471. if (this.sizer.node.style.visibility != 'hidden')
  472. {
  473. this.sizer.redraw();
  474. }
  475. }
  476. if (revalidate)
  477. {
  478. this.outline.view.revalidate();
  479. }
  480. }
  481. }
  482. };
  483. /**
  484. * Function: mouseDown
  485. *
  486. * Handles the event by starting a translation or zoom.
  487. */
  488. mxOutline.prototype.mouseDown = function(sender, me)
  489. {
  490. if (this.enabled && this.showViewport)
  491. {
  492. var tol = (!mxEvent.isMouseEvent(me.getEvent())) ? this.source.tolerance : 0;
  493. var hit = (this.source.allowHandleBoundsCheck && (mxClient.IS_IE || tol > 0)) ?
  494. new mxRectangle(me.getGraphX() - tol, me.getGraphY() - tol, 2 * tol, 2 * tol) : null;
  495. this.zoom = me.isSource(this.sizer) || (hit != null && mxUtils.intersects(shape.bounds, hit));
  496. this.startX = me.getX();
  497. this.startY = me.getY();
  498. this.active = true;
  499. if (this.source.useScrollbarsForPanning && mxUtils.hasScrollbars(this.source.container))
  500. {
  501. this.dx0 = this.source.container.scrollLeft;
  502. this.dy0 = this.source.container.scrollTop;
  503. }
  504. else
  505. {
  506. this.dx0 = 0;
  507. this.dy0 = 0;
  508. }
  509. }
  510. me.consume();
  511. };
  512. /**
  513. * Function: mouseMove
  514. *
  515. * Handles the event by previewing the viewrect in <graph> and updating the
  516. * rectangle that represents the viewrect in the outline.
  517. */
  518. mxOutline.prototype.mouseMove = function(sender, me)
  519. {
  520. if (this.active)
  521. {
  522. this.selectionBorder.node.style.display = (this.showViewport) ? '' : 'none';
  523. this.sizer.node.style.display = this.selectionBorder.node.style.display;
  524. var delta = this.getTranslateForEvent(me);
  525. var dx = delta.x;
  526. var dy = delta.y;
  527. var bounds = null;
  528. if (!this.zoom)
  529. {
  530. // Previews the panning on the source graph
  531. var scale = this.outline.getView().scale;
  532. bounds = new mxRectangle(this.bounds.x + dx,
  533. this.bounds.y + dy, this.bounds.width, this.bounds.height);
  534. this.selectionBorder.bounds = bounds;
  535. this.selectionBorder.redraw();
  536. dx /= scale;
  537. dx *= this.source.getView().scale;
  538. dy /= scale;
  539. dy *= this.source.getView().scale;
  540. this.source.panGraph(-dx - this.dx0, -dy - this.dy0);
  541. }
  542. else
  543. {
  544. // Does *not* preview zooming on the source graph
  545. var container = this.source.container;
  546. var viewRatio = container.clientWidth / container.clientHeight;
  547. dy = dx / viewRatio;
  548. bounds = new mxRectangle(this.bounds.x,
  549. this.bounds.y,
  550. Math.max(1, this.bounds.width + dx),
  551. Math.max(1, this.bounds.height + dy));
  552. this.selectionBorder.bounds = bounds;
  553. this.selectionBorder.redraw();
  554. }
  555. // Updates the zoom handle
  556. var b = this.sizer.bounds;
  557. this.sizer.bounds = new mxRectangle(
  558. bounds.x + bounds.width - b.width / 2,
  559. bounds.y + bounds.height - b.height / 2,
  560. b.width, b.height);
  561. // Avoids update of visibility in redraw for VML
  562. if (this.sizer.node.style.visibility != 'hidden')
  563. {
  564. this.sizer.redraw();
  565. }
  566. me.consume();
  567. }
  568. };
  569. /**
  570. * Function: getTranslateForEvent
  571. *
  572. * Gets the translate for the given mouse event. Here is an example to limit
  573. * the outline to stay within positive coordinates:
  574. *
  575. * (code)
  576. * outline.getTranslateForEvent = function(me)
  577. * {
  578. * var pt = new mxPoint(me.getX() - this.startX, me.getY() - this.startY);
  579. *
  580. * if (!this.zoom)
  581. * {
  582. * var tr = this.source.view.translate;
  583. * pt.x = Math.max(tr.x * this.outline.view.scale, pt.x);
  584. * pt.y = Math.max(tr.y * this.outline.view.scale, pt.y);
  585. * }
  586. *
  587. * return pt;
  588. * };
  589. * (end)
  590. */
  591. mxOutline.prototype.getTranslateForEvent = function(me)
  592. {
  593. return new mxPoint(me.getX() - this.startX, me.getY() - this.startY);
  594. };
  595. /**
  596. * Function: mouseUp
  597. *
  598. * Handles the event by applying the translation or zoom to <graph>.
  599. */
  600. mxOutline.prototype.mouseUp = function(sender, me)
  601. {
  602. if (this.active)
  603. {
  604. var delta = this.getTranslateForEvent(me);
  605. var dx = delta.x;
  606. var dy = delta.y;
  607. if (Math.abs(dx) > 0 || Math.abs(dy) > 0)
  608. {
  609. if (!this.zoom)
  610. {
  611. // Applies the new translation if the source
  612. // has no scrollbars
  613. if (!this.source.useScrollbarsForPanning ||
  614. !mxUtils.hasScrollbars(this.source.container))
  615. {
  616. this.source.panGraph(0, 0);
  617. dx /= this.outline.getView().scale;
  618. dy /= this.outline.getView().scale;
  619. var t = this.source.getView().translate;
  620. this.source.getView().setTranslate(t.x - dx, t.y - dy);
  621. }
  622. }
  623. else
  624. {
  625. // Applies the new zoom
  626. var w = this.selectionBorder.bounds.width;
  627. var scale = this.source.getView().scale;
  628. this.source.zoomTo(Math.max(this.minScale, scale - (dx * scale) / w), false);
  629. }
  630. this.update();
  631. me.consume();
  632. }
  633. // Resets the state of the handler
  634. this.index = null;
  635. this.active = false;
  636. }
  637. };
  638. /**
  639. * Function: destroy
  640. *
  641. * Destroy this outline and removes all listeners from <source>.
  642. */
  643. mxOutline.prototype.destroy = function()
  644. {
  645. if (this.source != null)
  646. {
  647. this.source.removeListener(this.panHandler);
  648. this.source.removeListener(this.refreshHandler);
  649. this.source.getModel().removeListener(this.updateHandler);
  650. this.source.getView().removeListener(this.updateHandler);
  651. mxEvent.removeListener(this.source.container, 'scroll', this.updateHandler);
  652. this.source = null;
  653. }
  654. if (this.outline != null)
  655. {
  656. this.outline.removeMouseListener(this);
  657. this.outline.destroy();
  658. this.outline = null;
  659. }
  660. if (this.selectionBorder != null)
  661. {
  662. this.selectionBorder.destroy();
  663. this.selectionBorder = null;
  664. }
  665. if (this.sizer != null)
  666. {
  667. this.sizer.destroy();
  668. this.sizer = null;
  669. }
  670. };
  671. __mxOutput.mxOutline = typeof mxOutline !== 'undefined' ? mxOutline : undefined;