OverlaysSpec.js 24 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253
  1. import {
  2. bootstrapDiagram,
  3. getDiagramJS,
  4. inject
  5. } from 'test/TestHelper';
  6. import {
  7. forEach,
  8. assign
  9. } from 'min-dash';
  10. import {
  11. domify
  12. } from 'min-dom';
  13. import overlayModule from 'lib/features/overlays';
  14. describe('features/overlays', function() {
  15. describe('bootstrap', function() {
  16. beforeEach(bootstrapDiagram({ modules: [ overlayModule ] }));
  17. it('should expose api', inject(function(overlays) {
  18. expect(overlays).to.exist;
  19. expect(overlays.get).to.exist;
  20. expect(overlays.add).to.exist;
  21. expect(overlays.remove).to.exist;
  22. }));
  23. });
  24. describe('#add', function() {
  25. beforeEach(bootstrapDiagram({ modules: [ overlayModule ] }));
  26. it('should add <div>', inject(function(overlays, canvas) {
  27. // given
  28. var shape = canvas.addShape({
  29. id: 'test',
  30. x: 10,
  31. y: 10,
  32. width: 100,
  33. height: 100
  34. });
  35. // when
  36. var id = overlays.add(shape, {
  37. position: {
  38. left: 0,
  39. top: 0
  40. },
  41. html: '<div class="overlay"></div>'
  42. });
  43. // then
  44. expect(id).to.exist;
  45. expect(overlays.get(id)).to.exist;
  46. expect(queryOverlay(id)).to.exist;
  47. }));
  48. it('should add element overlay', inject(function(overlays, canvas) {
  49. // given
  50. var shape = canvas.addShape({
  51. id: 'test',
  52. x: 10,
  53. y: 10,
  54. width: 100,
  55. height: 100
  56. });
  57. // when
  58. var id = overlays.add(shape, {
  59. position: {
  60. left: 0,
  61. top: 0
  62. },
  63. html: highlight(domify('<div class="overlay" />'))
  64. });
  65. // then
  66. var overlay = overlays.get(id);
  67. expect(overlay).to.exist;
  68. expect(isVisible(overlays._overlayRoot)).to.be.true;
  69. expect(isVisible(overlay.html)).to.be.true;
  70. expect(queryOverlay(id)).to.exist;
  71. }));
  72. it('should add overlay on shape (by id)', inject(function(overlays, canvas) {
  73. // given
  74. canvas.addShape({
  75. id: 'test',
  76. x: 10,
  77. y: 10,
  78. width: 100,
  79. height: 100
  80. });
  81. // when
  82. var id = overlays.add('test', {
  83. position: {
  84. left: 0,
  85. top: 0
  86. },
  87. html: highlight(domify('<div class="overlay" />'))
  88. });
  89. // then
  90. expect(overlays.get(id)).to.exist;
  91. expect(queryOverlay(id)).to.exist;
  92. }));
  93. });
  94. describe('#remove', function() {
  95. beforeEach(bootstrapDiagram({ modules: [ overlayModule ] }));
  96. it('should remove overlay', inject(function(overlays, canvas) {
  97. // given
  98. var shape = canvas.addShape({
  99. id: 'shape',
  100. x: 10,
  101. y: 10,
  102. width: 100,
  103. height: 100
  104. });
  105. var id = overlays.add(shape, {
  106. position: {
  107. left: 0,
  108. top: 0
  109. },
  110. html: highlight(domify('<div class="overlay"></div>'))
  111. });
  112. // when
  113. overlays.remove(id);
  114. // then
  115. expect(overlays.get(id)).not.to.exist;
  116. expect(overlays.get({ element: shape })).to.be.empty;
  117. expect(queryOverlay(id)).not.to.exist;
  118. }));
  119. it('should remove multiple by filter', inject(function(overlays, canvas) {
  120. // given
  121. var shape = canvas.addShape({
  122. id: 'shape',
  123. x: 10,
  124. y: 10,
  125. width: 100,
  126. height: 100
  127. });
  128. overlays.add(shape, 'badge', {
  129. position: {
  130. left: 0,
  131. top: 0
  132. },
  133. html: highlight(domify('<div class="badge">1</div>'))
  134. });
  135. overlays.add(shape, 'badge', {
  136. position: {
  137. right: 0,
  138. top: 0
  139. },
  140. html: highlight(domify('<div class="badge">2</div>'))
  141. });
  142. // when
  143. overlays.remove({ element: shape, type: 'badge' });
  144. // then
  145. expect(overlays.get({ element: shape, type: 'badge' })).to.be.empty;
  146. expect(overlays.get({ element: shape })).to.be.empty;
  147. expect(overlays._getOverlayContainer(shape, true).html.textContent).to.equal('');
  148. }));
  149. it('should remove automatically on <*.remove>', inject(function(eventBus, overlays, canvas) {
  150. // given
  151. var shape = canvas.addShape({
  152. id: 'test',
  153. x: 10,
  154. y: 10,
  155. width: 100,
  156. height: 100
  157. });
  158. var id = overlays.add(shape, {
  159. position: {
  160. left: 0,
  161. top: 0
  162. },
  163. html: '<div class="overlay"></div>'
  164. });
  165. // when
  166. eventBus.fire('shape.remove', { element: shape });
  167. // then
  168. expect(overlays.get(id)).not.to.exist;
  169. expect(queryOverlay(id)).not.to.exist;
  170. expect(overlays._overlayContainers).to.be.empty;
  171. }));
  172. it('should remove cached container on <*.remove>', inject(function(eventBus, overlays, canvas) {
  173. // given
  174. var shape1 = canvas.addShape({
  175. id: 'test1',
  176. x: 10,
  177. y: 10,
  178. width: 100,
  179. height: 100
  180. });
  181. overlays.add(shape1, {
  182. position: {
  183. left: 0,
  184. top: 0
  185. },
  186. html: '<div class="overlay"></div>'
  187. });
  188. var shape2 = canvas.addShape({
  189. id: 'test2',
  190. x: 150,
  191. y: 10,
  192. width: 100,
  193. height: 100
  194. });
  195. overlays.add(shape2, {
  196. position: {
  197. left: 0,
  198. top: 0
  199. },
  200. html: '<div class="overlay"></div>'
  201. });
  202. var shape3 = canvas.addShape({
  203. id: 'test3',
  204. x: 300,
  205. y: 10,
  206. width: 100,
  207. height: 100
  208. });
  209. overlays.add(shape3, {
  210. position: {
  211. left: 0,
  212. top: 0
  213. },
  214. html: '<div class="overlay"></div>'
  215. });
  216. // when
  217. eventBus.fire('shape.remove', { element: shape2 });
  218. // then
  219. expect(overlays._getOverlayContainer(shape1, true)).to.exist;
  220. expect(overlays._getOverlayContainer(shape2, true)).not.to.exist;
  221. expect(overlays._getOverlayContainer(shape3, true)).to.exist;
  222. }));
  223. it('should reattach overlays on element ID change', inject(function(overlays, canvas, elementRegistry) {
  224. // given
  225. var oldId = 'old',
  226. newId = 'new';
  227. var shape = canvas.addShape({
  228. id: oldId,
  229. x: 10,
  230. y: 10,
  231. width: 100,
  232. height: 100
  233. });
  234. var id = overlays.add(shape, {
  235. position: {
  236. left: 0,
  237. top: 0
  238. },
  239. html: '<div class="overlay"></div>'
  240. });
  241. var overlay = overlays.get(id);
  242. // when
  243. elementRegistry.updateId(shape, newId);
  244. // then
  245. expect(overlays.get(id)).to.eql(overlay);
  246. expect(queryOverlay(id)).to.exist;
  247. expect(overlays.get({ element: shape })).to.eql([ overlay ]);
  248. }));
  249. });
  250. describe('#get', function() {
  251. beforeEach(bootstrapDiagram({ modules: [ overlayModule ] }));
  252. var shape1, shape2, overlay1, overlay2, overlay3;
  253. beforeEach(inject(function(canvas, overlays) {
  254. shape1 = canvas.addShape({
  255. id: 'shape1',
  256. x: 100,
  257. y: 100,
  258. width: 100,
  259. height: 100
  260. });
  261. shape2 = canvas.addShape({
  262. id: 'shape2',
  263. x: 300,
  264. y: 100,
  265. width: 50,
  266. height: 50
  267. });
  268. overlay1 = {
  269. position: {
  270. top: 10,
  271. left: 20
  272. },
  273. html: createOverlay()
  274. };
  275. overlay1.id = overlays.add(shape1, 'badge', overlay1);
  276. overlay2 = {
  277. position: {
  278. bottom: 50,
  279. right: 0
  280. },
  281. html: createOverlay()
  282. };
  283. overlay2.id = overlays.add(shape1, overlay2);
  284. overlay3 = {
  285. position: {
  286. top: 10,
  287. left: 20
  288. },
  289. html: createOverlay()
  290. };
  291. overlay3.id = overlays.add(shape2, 'badge', overlay3);
  292. }));
  293. it('should return overlays by element', inject(function(overlays) {
  294. // when
  295. var filteredOverlays = overlays.get({ element: shape1 });
  296. // then
  297. expect(filteredOverlays.length).to.equal(2);
  298. }));
  299. it('should return overlays by element + type', inject(function(overlays) {
  300. // when
  301. var filteredOverlays = overlays.get({ element: shape2, type: 'badge' });
  302. // then
  303. expect(filteredOverlays.length).to.equal(1);
  304. }));
  305. it('should return overlays by type', inject(function(overlays) {
  306. // when
  307. var filteredOverlays = overlays.get({ type: 'badge' });
  308. // then
  309. expect(filteredOverlays.length).to.equal(2);
  310. }));
  311. });
  312. describe('positioning', function() {
  313. beforeEach(bootstrapDiagram({ modules: [ overlayModule ] }));
  314. var shape;
  315. beforeEach(inject(function(canvas) {
  316. shape = canvas.addShape({
  317. id: 'shape',
  318. x: 100,
  319. y: 100,
  320. width: 100,
  321. height: 100
  322. });
  323. }));
  324. function position(overlayHtml) {
  325. var parent = overlayHtml.parentNode;
  326. var result = {};
  327. forEach([ 'left', 'right', 'top', 'bottom' ], function(pos) {
  328. var p = parseInt(parent.style[pos]);
  329. if (!isNaN(p)) {
  330. result[pos] = p;
  331. }
  332. });
  333. return result;
  334. }
  335. it('should position top left of shape', inject(function(overlays) {
  336. var html = createOverlay();
  337. // when
  338. overlays.add(shape, {
  339. position: {
  340. left: 40,
  341. top: 40
  342. },
  343. html: html
  344. });
  345. // then
  346. expect(position(html)).to.eql({
  347. top: 40,
  348. left: 40
  349. });
  350. }));
  351. it('should position bottom left of shape', inject(function(overlays) {
  352. var html = createOverlay();
  353. // when
  354. overlays.add(shape, {
  355. position: {
  356. bottom: 40,
  357. left: 40
  358. },
  359. html: html
  360. });
  361. // then
  362. expect(position(html)).to.eql({
  363. top: 60,
  364. left: 40
  365. });
  366. }));
  367. it('should position top left of shape', inject(function(overlays, canvas) {
  368. var html = createOverlay();
  369. var connection = canvas.addConnection({ id: 'select1', waypoints: [ { x: 10, y: 10 }, { x: 110, y: 10 } ] });
  370. // when
  371. overlays.add(connection, {
  372. position: {
  373. left: 100,
  374. top: 0
  375. },
  376. html: html
  377. });
  378. // then
  379. expect(position(html)).to.eql({
  380. top: 0,
  381. left: 100
  382. });
  383. }));
  384. it('should position bottom right of shape', inject(function(overlays) {
  385. var html = createOverlay();
  386. // when
  387. overlays.add(shape, {
  388. position: {
  389. bottom: 40,
  390. right: 40
  391. },
  392. html: html
  393. });
  394. // then
  395. expect(position(html)).to.eql({
  396. top: 60,
  397. left: 60
  398. });
  399. }));
  400. it('should position top right of shape', inject(function(overlays) {
  401. var html = createOverlay();
  402. // when
  403. overlays.add(shape, {
  404. position: {
  405. top: 40,
  406. right: 40
  407. },
  408. html: html
  409. });
  410. // then
  411. expect(position(html)).to.eql({
  412. top: 40,
  413. left: 60
  414. });
  415. }));
  416. });
  417. describe('show behavior', function() {
  418. describe('default', function() {
  419. beforeEach(bootstrapDiagram({
  420. modules: [ overlayModule ],
  421. canvas: { deferUpdate: false }
  422. }));
  423. var shape;
  424. beforeEach(inject(function(canvas) {
  425. shape = canvas.addShape({
  426. id: 'shape',
  427. x: 100,
  428. y: 100,
  429. width: 100,
  430. height: 100
  431. });
  432. }));
  433. function isVisible(element) {
  434. return element.parentNode.style.display !== 'none';
  435. }
  436. it('should always show overlays', inject(function(overlays, canvas) {
  437. // given
  438. var html = createOverlay();
  439. overlays.add(shape, {
  440. html: html,
  441. position: { left: 20, bottom: 0 }
  442. });
  443. // when zoom in visibility range
  444. canvas.zoom(0.7);
  445. // then
  446. expect(isVisible(html)).to.be.true;
  447. // when zoom below visibility range
  448. canvas.zoom(0.6);
  449. // then
  450. expect(isVisible(html)).to.be.true;
  451. // when zoom in visibility range
  452. canvas.zoom(3.0);
  453. // then
  454. expect(isVisible(html)).to.be.true;
  455. // when zoom above visibility range
  456. canvas.zoom(6.0);
  457. // then
  458. expect(isVisible(html)).to.be.true;
  459. }));
  460. });
  461. describe('overriding defaults', function() {
  462. beforeEach(bootstrapDiagram({
  463. modules: [ overlayModule ],
  464. canvas: { deferUpdate: false },
  465. overlays: {
  466. defaults: {
  467. show: {
  468. minZoom: 0.7,
  469. maxZoom: 5.0
  470. }
  471. }
  472. }
  473. }));
  474. var shape;
  475. beforeEach(inject(function(canvas) {
  476. shape = canvas.addShape({
  477. id: 'shape',
  478. x: 100,
  479. y: 100,
  480. width: 100,
  481. height: 100
  482. });
  483. }));
  484. function isVisible(element) {
  485. return element.parentNode.style.display !== 'none';
  486. }
  487. it('should conditionally hide overlays', inject(function(overlays, canvas) {
  488. // given
  489. var html = createOverlay();
  490. overlays.add(shape, {
  491. html: html,
  492. position: { left: 20, bottom: 0 }
  493. });
  494. // when zoom in visibility range
  495. canvas.zoom(0.7);
  496. // then
  497. expect(isVisible(html)).to.be.true;
  498. // when zoom below visibility range
  499. canvas.zoom(0.6);
  500. // then
  501. expect(isVisible(html)).to.be.false;
  502. // when zoom in visibility range
  503. canvas.zoom(3.0);
  504. // then
  505. expect(isVisible(html)).to.be.true;
  506. // when zoom above visibility range
  507. canvas.zoom(6.0);
  508. // then
  509. expect(isVisible(html)).to.be.false;
  510. }));
  511. });
  512. });
  513. describe('conditional hide behavior', function() {
  514. beforeEach(bootstrapDiagram({
  515. modules: [ overlayModule ],
  516. canvas: { deferUpdate: false },
  517. overlays: {
  518. defaults: {
  519. show: {
  520. minZoom: 0.7,
  521. maxZoom: 5.0
  522. }
  523. }
  524. }
  525. }));
  526. var shape;
  527. beforeEach(inject(function(canvas) {
  528. shape = canvas.addShape({
  529. id: 'shape',
  530. x: 100,
  531. y: 100,
  532. width: 100,
  533. height: 100
  534. });
  535. }));
  536. function zoom(level) {
  537. getDiagramJS().invoke(function(canvas) {
  538. canvas.zoom(level);
  539. });
  540. }
  541. function isVisible(element) {
  542. return element.parentNode.style.display !== 'none';
  543. }
  544. function expectVisible(el, visible) {
  545. expect(isVisible(el)).to.equal(visible);
  546. }
  547. it('should respect min show rules when overlay is added', inject(function(overlays) {
  548. // given
  549. var html = createOverlay();
  550. // when zoom below visibility range
  551. zoom(0.6);
  552. overlays.add(shape, {
  553. html: html,
  554. position: { left: 20, bottom: 0 }
  555. });
  556. // then
  557. expectVisible(html, false);
  558. // when zoom in visibility range
  559. zoom(0.7);
  560. // then
  561. expectVisible(html, true);
  562. }));
  563. it('should respect max show rules when overlay is added', inject(function(overlays, canvas) {
  564. // given
  565. var html = createOverlay();
  566. // when zoom above visibility range
  567. zoom(6.0);
  568. overlays.add(shape, {
  569. html: html,
  570. position: { left: 20, bottom: 0 }
  571. });
  572. // then
  573. expectVisible(html, false);
  574. // when zoom in visibility range
  575. zoom(3.0);
  576. // then
  577. expectVisible(html, true);
  578. }));
  579. it('should respect overlay specific min/max rules', inject(function(overlays, canvas) {
  580. // given
  581. var html = createOverlay();
  582. overlays.add(shape, {
  583. html: html,
  584. position: { left: 20, bottom: 0 },
  585. show: {
  586. minZoom: 0.7,
  587. maxZoom: 1.3
  588. }
  589. });
  590. // when
  591. // zoom below configured minZoom
  592. zoom(0.5);
  593. // then
  594. expectVisible(html, false);
  595. // when
  596. // zoom on configured minZoom
  597. zoom(0.7);
  598. // then
  599. expectVisible(html, true);
  600. // when
  601. // zoom into visibility range
  602. zoom(0.9);
  603. // then
  604. expectVisible(html, true);
  605. // when
  606. // zoom on configured maxZoom
  607. zoom(1.3);
  608. // then
  609. expectVisible(html, true);
  610. // when
  611. // zoom above maxZoom
  612. zoom(1.4);
  613. // then
  614. expectVisible(html, false);
  615. }));
  616. it('should respect overlay specific min rule', inject(function(overlays, canvas) {
  617. // given
  618. var html = createOverlay();
  619. overlays.add(shape, {
  620. html: html,
  621. position: { left: 20, bottom: 0 },
  622. show: {
  623. minZoom: 0.7
  624. }
  625. });
  626. // when
  627. // zoom below configured minZoom
  628. zoom(0.5);
  629. // then
  630. expectVisible(html, false);
  631. // when zoom on configured minZoom
  632. zoom(0.7);
  633. // then
  634. expectVisible(html, true);
  635. }));
  636. it('should respect overlay specific max rule', inject(function(overlays, canvas) {
  637. // given
  638. var html = createOverlay();
  639. overlays.add(shape, {
  640. html: html,
  641. position: { left: 20, bottom: 0 },
  642. show: {
  643. maxZoom: 1.3
  644. }
  645. });
  646. // when
  647. // zoom on configured maxZoom
  648. zoom(1.3);
  649. // then
  650. expectVisible(html, true);
  651. // when
  652. // zoom above maxZoom
  653. zoom(1.4);
  654. // then
  655. expectVisible(html, false);
  656. }));
  657. });
  658. describe('scroll/zoom behavior', function() {
  659. beforeEach(bootstrapDiagram({
  660. modules: [ overlayModule ],
  661. canvas: { deferUpdate: false }
  662. }));
  663. var shape, overlay;
  664. beforeEach(inject(function(canvas, overlays) {
  665. shape = canvas.addShape({
  666. id: 'shape',
  667. x: 100,
  668. y: 100,
  669. width: 100,
  670. height: 100
  671. });
  672. overlay = {
  673. html: createOverlay(),
  674. position: {
  675. left: 20,
  676. top: 20
  677. }
  678. };
  679. overlays.add(shape, overlay);
  680. }));
  681. it('should not be transformed initially', inject(function(overlays, canvas) {
  682. // given
  683. // diagram got newly created
  684. // then
  685. expect(transformMatrix(overlays._overlayRoot)).not.to.exist;
  686. }));
  687. it('should transform overlay container on scroll', inject(function(overlays, canvas) {
  688. // when
  689. canvas.scroll({
  690. dx: 100,
  691. dy: 50
  692. });
  693. var mtrx = transformMatrix(overlays._overlayRoot);
  694. // then
  695. expect(mtrx).to.eql({
  696. a : 1, b : 0,
  697. c : 0, d : 1,
  698. e : 100, f : 50
  699. });
  700. }));
  701. it('should transform overlay container on zoom', inject(function(overlays, canvas) {
  702. // when
  703. canvas.zoom(2);
  704. var mtrx = transformMatrix(overlays._overlayRoot);
  705. // then
  706. expect(mtrx.a).to.eql(2);
  707. expect(mtrx.d).to.eql(2);
  708. }));
  709. it('should add css prefixes to the overlay container on zoom', inject(function(overlays, canvas) {
  710. // given
  711. var containerStyle = overlays._overlayRoot.style;
  712. // when
  713. canvas.zoom(2);
  714. // then
  715. expect(containerStyle['-webkit-transform']).to.match(/matrix/);
  716. expect(containerStyle['-ms-transform']).to.match(/matrix/);
  717. }));
  718. it('should transform overlay container on zoom (with position)', inject(function(overlays, canvas) {
  719. // when
  720. canvas.zoom(2, { x: 300, y: 300 });
  721. // then
  722. expect(transformMatrix(overlays._overlayRoot)).to.eql({
  723. a : 2, b : 0,
  724. c : 0, d : 2,
  725. e : -300, f : -300
  726. });
  727. }));
  728. });
  729. describe('overlay scaling behavior', function() {
  730. beforeEach(bootstrapDiagram({
  731. modules: [ overlayModule ],
  732. canvas: { deferUpdate: false }
  733. }));
  734. function scaleVector(element) {
  735. return asVector(element.style.transform);
  736. }
  737. function verifyScale(overlayConfig, expectedScales) {
  738. var test = inject(function(canvas, overlays) {
  739. // given
  740. var shape = canvas.addShape({
  741. id: 'shape',
  742. x: 100,
  743. y: 100,
  744. width: 100,
  745. height: 100
  746. });
  747. var overlay = assign({
  748. html: createOverlay(),
  749. position: {
  750. left: 20,
  751. top: 20
  752. }
  753. }, overlayConfig);
  754. overlays.add(shape, overlay);
  755. var overlayParent = overlay.html.parentNode;
  756. // test multiple zoom steps
  757. [ 1.0, 1.5, 3.5, 10, 0.5 ].forEach(function(zoom, idx) {
  758. var expectedScale = expectedScales[idx];
  759. // when
  760. canvas.zoom(zoom);
  761. var actualScale = scaleVector(overlayParent) || { x: 1, y: 1 };
  762. var effectiveScale = zoom * actualScale.x;
  763. // then
  764. expect(actualScale.x).to.eql(actualScale.y);
  765. expect(effectiveScale).to.be.closeTo(expectedScale, 0.00001);
  766. });
  767. });
  768. test();
  769. }
  770. it('should scale per default', function() {
  771. // given
  772. var overlay = { };
  773. var expectedScales = [
  774. 1.0, 1.5, 3.5, 10, 0.5
  775. ];
  776. // expect
  777. verifyScale(overlay, expectedScales);
  778. });
  779. it('should scale with explicit scale = true', function() {
  780. // given
  781. var overlay = {
  782. scale: true
  783. };
  784. var expectedScales = [
  785. 1.0, 1.5, 3.5, 10, 0.5
  786. ];
  787. // expect
  788. verifyScale(overlay, expectedScales);
  789. });
  790. it('should not scale with scale = false', function() {
  791. // given
  792. var overlay = {
  793. scale: false
  794. };
  795. var expectedScales = [
  796. 1.0, 1.0, 1.0, 1.0, 1.0
  797. ];
  798. // expect
  799. verifyScale(overlay, expectedScales);
  800. });
  801. it('should configure scale with min / max', function() {
  802. // given
  803. var overlay = {
  804. scale: {
  805. min: 0.9,
  806. max: 1.6
  807. }
  808. };
  809. var expectedScales = [
  810. 1.0, 1.5, 1.6, 1.6, 0.9
  811. ];
  812. // expect
  813. verifyScale(overlay, expectedScales);
  814. });
  815. });
  816. describe('#clear', function() {
  817. beforeEach(bootstrapDiagram({ modules: [ overlayModule ] }));
  818. it('should add <div>', inject(function(overlays, eventBus, canvas) {
  819. // given
  820. var shape = canvas.addShape({
  821. id: 'test',
  822. x: 10,
  823. y: 10,
  824. width: 100,
  825. height: 100
  826. });
  827. var id = overlays.add(shape, {
  828. position: {
  829. left: 0,
  830. top: 0
  831. },
  832. html: '<div class="overlay"></div>'
  833. });
  834. // when
  835. eventBus.fire('diagram.clear');
  836. // then
  837. expect(overlays.get(id)).not.to.exist;
  838. expect(queryOverlay(id)).not.to.exist;
  839. }));
  840. });
  841. });
  842. // helpers //////////////////////
  843. var NUM_REGEX = /([+-]?\d*[.]?\d+)(?=,|\))/g;
  844. var overlaysCounter = 0;
  845. function asMatrix(transformStr) {
  846. if (transformStr && transformStr !== 'none') {
  847. var m = transformStr.match(NUM_REGEX);
  848. return {
  849. a: parseFloat(m[0], 10),
  850. b: parseFloat(m[1], 10),
  851. c: parseFloat(m[2], 10),
  852. d: parseFloat(m[3], 10),
  853. e: parseFloat(m[4], 10),
  854. f: parseFloat(m[5], 10)
  855. };
  856. }
  857. }
  858. function asVector(scaleStr) {
  859. if (scaleStr && scaleStr !== 'none') {
  860. var m = scaleStr.match(NUM_REGEX);
  861. var x = parseFloat(m[0], 10);
  862. var y = m[1] ? parseFloat(m[1], 10) : x;
  863. return {
  864. x: x,
  865. y: y
  866. };
  867. }
  868. }
  869. function isVisible(element) {
  870. return window.getComputedStyle(element).display !== 'none';
  871. }
  872. function highlight(element) {
  873. assign(element.style, { background: 'fuchsia', minWidth: '10px', minHeight: '10px' });
  874. return element;
  875. }
  876. function queryOverlay(id) {
  877. return document.querySelector('[data-overlay-id=' + id + ']');
  878. }
  879. function createOverlay() {
  880. var element = highlight(domify('<div>OV<br/>#' + (overlaysCounter++) + '</div>'));
  881. assign(element.style, { width: 40, height: 40 });
  882. return element;
  883. }
  884. function transformMatrix(element) {
  885. return asMatrix(element.style.transform);
  886. }