ZoomScrollSpec.js 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. /* global sinon */
  2. import {
  3. bootstrapDiagram,
  4. getDiagramJS,
  5. inject
  6. } from 'test/TestHelper';
  7. import {
  8. assign
  9. } from 'min-dash';
  10. import {
  11. domify
  12. } from 'min-dom';
  13. import zoomScrollModule from 'lib/navigation/zoomscroll';
  14. describe('navigation/zoomscroll', function() {
  15. describe('bootstrap', function() {
  16. beforeEach(bootstrapDiagram({
  17. modules: [ zoomScrollModule ],
  18. canvas: { deferUpdate: false }
  19. }));
  20. it('should bootstrap', inject(function(zoomScroll, canvas) {
  21. canvas.addShape({
  22. id: 'test',
  23. width: 100,
  24. height: 100,
  25. x: 100,
  26. y: 100
  27. });
  28. expect(zoomScroll).to.exist;
  29. expect(zoomScroll._enabled).to.be.true;
  30. }));
  31. });
  32. describe('zoom', function() {
  33. beforeEach(bootstrapDiagram({
  34. modules: [ zoomScrollModule ],
  35. canvas: { deferUpdate: false }
  36. }));
  37. it('should zoom back to 1', inject(function(zoomScroll, canvas) {
  38. // when
  39. // should only zoom in 19 times
  40. for (var i = 0; i < 20; i++) {
  41. zoomScroll.zoom(0.1);
  42. }
  43. for (var j = 0; j < 19; j++) {
  44. zoomScroll.zoom(-0.1);
  45. }
  46. // then
  47. expect(canvas.zoom()).to.equal(1);
  48. }));
  49. it('should only zoom in once threshold is reached', inject(function(zoomScroll, canvas) {
  50. var zoomSpy = sinon.spy(canvas, 'zoom');
  51. // when
  52. zoomScroll.zoom(0.06);
  53. zoomScroll.zoom(0.06);
  54. // then
  55. // called as getter and setter
  56. expect(zoomSpy).to.have.been.calledTwice;
  57. }));
  58. });
  59. describe('step zoom', function() {
  60. beforeEach(bootstrapDiagram({
  61. modules: [ zoomScrollModule ],
  62. canvas: { deferUpdate: false }
  63. }));
  64. it('should zoom in along fixed zoom steps', inject(function(zoomScroll, canvas) {
  65. // when
  66. zoomScroll.stepZoom(1);
  67. // then
  68. expect(canvas.zoom()).to.equal(1.349);
  69. }));
  70. it('should zoom out along fixed zoom steps', inject(function(zoomScroll, canvas) {
  71. // when
  72. zoomScroll.stepZoom(-1);
  73. // then
  74. expect(canvas.zoom()).to.equal(0.741);
  75. }));
  76. it('should snap to a proximate zoom step', inject(function(zoomScroll, canvas) {
  77. // given
  78. // a zoom level in between two fixed zoom steps
  79. canvas.zoom(1.1);
  80. // when
  81. zoomScroll.stepZoom(1);
  82. // then
  83. expect(canvas.zoom()).to.equal(1.349);
  84. }));
  85. it('should snap to default zoom level (1.00) when zooming in from the minimum zoom level',
  86. inject(function(zoomScroll, canvas) {
  87. // given
  88. // zoom to the minimun level
  89. canvas.zoom(0.2);
  90. // when
  91. // zoom in along fixed steps 5 times
  92. for (var i = 0; i < 5; i++) {
  93. zoomScroll.stepZoom(1);
  94. }
  95. // then
  96. expect(canvas.zoom()).to.equal(1);
  97. })
  98. );
  99. it('should snap to default zoom level (1.00) when zooming out from the maximum zoom level',
  100. inject(function(zoomScroll, canvas) {
  101. // given
  102. // zoom to the maximum level
  103. canvas.zoom(4);
  104. // when
  105. // zoom out along fixed steps 5 times
  106. for (var i = 0; i < 5; i++) {
  107. zoomScroll.stepZoom(-1);
  108. }
  109. // then
  110. expect(canvas.zoom()).to.equal(1);
  111. })
  112. );
  113. });
  114. describe('toggle', function() {
  115. beforeEach(bootstrapDiagram({
  116. modules: [ zoomScrollModule ],
  117. canvas: { deferUpdate: false },
  118. zoomScroll: {
  119. enabled: false
  120. }
  121. }));
  122. it('should force enable', inject(function(zoomScroll) {
  123. // when
  124. var newEnabled = zoomScroll.toggle(true);
  125. // then
  126. expect(newEnabled).to.be.true;
  127. }));
  128. it('should force disable', inject(function(zoomScroll) {
  129. // when
  130. var newEnabled = zoomScroll.toggle(false);
  131. // then
  132. expect(newEnabled).to.be.false;
  133. }));
  134. it('should toggle on', inject(function(zoomScroll) {
  135. // assume
  136. expect(zoomScroll._enabled).to.be.false;
  137. // when
  138. var newEnabled = zoomScroll.toggle();
  139. // then
  140. expect(newEnabled).to.be.true;
  141. }));
  142. it('should toggle enabled state on diagram click',
  143. inject(function(canvas, elementRegistry, zoomScroll) {
  144. // given
  145. canvas.addShape({
  146. id: 'test',
  147. width: 100,
  148. height: 100,
  149. x: 100,
  150. y: 100
  151. });
  152. var rootNode = canvas.getContainer();
  153. // when
  154. rootNode.addEventListener('click', function() {
  155. var newState = zoomScroll.toggle();
  156. rootNode.style.background = newState ? 'lightgreen' : 'none';
  157. });
  158. // then
  159. // test manually if zoom scroll is actually toggled...
  160. })
  161. );
  162. });
  163. describe('handle wheel events', function() {
  164. beforeEach(bootstrapDiagram({
  165. modules: [ zoomScrollModule ],
  166. canvas: { deferUpdate: false }
  167. }));
  168. describe('should mute', function() {
  169. it('on .djs-scrollable target', inject(function(zoomScroll) {
  170. // given
  171. var zoomSpy = sinon.spy(zoomScroll, 'zoom');
  172. var scrollSpy = sinon.spy(zoomScroll, 'scroll');
  173. var event = wheelEvent({
  174. target: domify('<div class="djs-scrollable" />')
  175. });
  176. // when
  177. zoomScroll._handleWheel(event);
  178. // then
  179. expect(zoomSpy).not.to.have.been.called;
  180. expect(scrollSpy).not.to.have.been.called;
  181. }));
  182. });
  183. describe('should scroll', function() {
  184. it('two-dimensional', expectScroll({
  185. expectedDelta: {
  186. dx: -25.5,
  187. dy: -10.5
  188. },
  189. onWheel: {
  190. deltaMode: 0,
  191. deltaX: 34,
  192. deltaY: 14
  193. }
  194. }));
  195. it('in line mode (Firefox)', expectScroll({
  196. expectedDelta: {
  197. dx: -12,
  198. dy: 36
  199. },
  200. onWheel: {
  201. deltaMode: 1,
  202. deltaX: 1,
  203. deltaY: -3
  204. }
  205. }));
  206. it('axis inverted via shiftKey', expectScroll({
  207. expectedDelta: {
  208. dx: -10.5,
  209. dy: 0
  210. },
  211. onWheel: {
  212. deltaMode: 0,
  213. deltaX: 34,
  214. deltaY: 14,
  215. shiftKey: true
  216. }
  217. }));
  218. });
  219. describe('should zoom', function() {
  220. it('with scroll + ctrlKey', expectZoom({
  221. expectedDelta: 0.7949999999999999,
  222. expectedPosition: { x: 100, y: 70 },
  223. onWheel: {
  224. x: 100,
  225. y: 70,
  226. deltaMode: 0,
  227. deltaX: -0,
  228. deltaY: -53,
  229. ctrlKey: true
  230. }
  231. }));
  232. it('in line mode (Firefox)', expectZoom({
  233. expectedDelta: -0.7589466384404111,
  234. expectedPosition: { x: -100, y: -70 },
  235. onWheel: {
  236. x: -100,
  237. y: -70,
  238. deltaMode: 1,
  239. deltaX: -3,
  240. deltaY: 1,
  241. ctrlKey: true
  242. }
  243. }));
  244. });
  245. });
  246. describe('handle wheel events / scale', function() {
  247. beforeEach(bootstrapDiagram({
  248. modules: [ zoomScrollModule ],
  249. canvas: { deferUpdate: false },
  250. zoomScroll: {
  251. scale: 0.5
  252. }
  253. }));
  254. it('should adapt scroll', expectScroll({
  255. expectedDelta: {
  256. dx: -17,
  257. dy: -7
  258. },
  259. onWheel: {
  260. deltaMode: 0,
  261. deltaX: 34,
  262. deltaY: 14
  263. }
  264. }));
  265. it('should adapt zoom', expectZoom({
  266. expectedDelta: 0.53,
  267. expectedPosition: { x: 100, y: 70 },
  268. onWheel: {
  269. x: 100,
  270. y: 70,
  271. deltaMode: 0,
  272. deltaX: -0,
  273. deltaY: -53,
  274. ctrlKey: true
  275. }
  276. }));
  277. });
  278. });
  279. /**
  280. * Mock wheel event factory.
  281. */
  282. function wheelEvent(opts) {
  283. var x = opts.x || 50;
  284. var y = opts.y || 50;
  285. var target = opts.target || document.body;
  286. var offset = getDiagramJS().invoke(function(canvas) {
  287. var clientRect = canvas._container.getBoundingClientRect();
  288. return {
  289. left: clientRect.left,
  290. top: clientRect.top
  291. };
  292. });
  293. return assign({
  294. deltaMode: 0,
  295. shiftKey: false,
  296. ctrlKey: false,
  297. preventDefault: function() { },
  298. stopPropagataion: function() { }
  299. }, opts, {
  300. clientX: offset.left + x,
  301. clientY: offset.top + y,
  302. target: target
  303. });
  304. }
  305. function expectZoom(opts) {
  306. return function() {
  307. var expectedDelta = opts.expectedDelta,
  308. expectedPosition = opts.expectedPosition,
  309. event = opts.onWheel;
  310. getDiagramJS().invoke(function(zoomScroll) {
  311. // given
  312. var zoomSpy = sinon.spy(zoomScroll, 'zoom');
  313. var scrollSpy = sinon.spy(zoomScroll, 'scroll');
  314. // when
  315. zoomScroll._handleWheel(wheelEvent(event));
  316. // then
  317. expect(zoomSpy).to.have.been.calledWith(expectedDelta, expectedPosition);
  318. expect(scrollSpy).not.to.have.been.called;
  319. });
  320. };
  321. }
  322. function expectScroll(opts) {
  323. return function() {
  324. var expectedDelta = opts.expectedDelta,
  325. event = opts.onWheel;
  326. getDiagramJS().invoke(function(zoomScroll) {
  327. // given
  328. var zoomSpy = sinon.spy(zoomScroll, 'zoom');
  329. var scrollSpy = sinon.spy(zoomScroll, 'scroll');
  330. // when
  331. zoomScroll._handleWheel(wheelEvent(event));
  332. // then
  333. expect(scrollSpy).to.have.been.calledWith(expectedDelta);
  334. expect(zoomSpy).not.to.have.been.called;
  335. });
  336. };
  337. }