From 9459800e6e3bb56bfc8821b009dcc175e9181e4c Mon Sep 17 00:00:00 2001 From: Sean Doyle Date: Sun, 26 May 2019 22:12:01 -0400 Subject: [PATCH] Add panning and zooming to SVG map element This commit adds a dependency on the [`svg-pan-zoom` package][svg-pan-zoom]. The plus and minus buttons introduced in the previous commit are decorated with `data-action` declarations which route `click` events to the `seats#zoomIn` and `seats#zoomOut` actions, respectively. When navigating to other floors (i.e. navigations that trigger `seats#discardMap`), [destroy the `svg-pan-zoom` provided instance] during Stimulus' [`disconnect` lifecycle method][disconnect], which is invoked during Turbolinks-initiated page visits, even for elements annotated with `data-turbolinks-permanent`. This commit wraps the collection of `` elements in an outer [`` element][g-element] (as suggested by [aritutta/svg-pan-zoom#146]). [svg-pan-zoom]: https://github.com/ariutta/svg-pan-zoom/tree/3.6.0 [g-element]: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/g [aritutta/svg-pan-zoom#146]: https://github.com/ariutta/svg-pan-zoom/issues/146 [destroy]: https://github.com/ariutta/svg-pan-zoom/tree/3.6.0#public-api [disconnect]: https://stimulusjs.org/reference/lifecycle-callbacks#disconnection --- .../controllers/seats_controller.js | 24 +++++++ app/views/seats/_frame.html.erb | 66 ++++++++++--------- package.json | 1 + yarn.lock | 5 ++ 4 files changed, 65 insertions(+), 31 deletions(-) diff --git a/app/javascript/controllers/seats_controller.js b/app/javascript/controllers/seats_controller.js index b40260ab..35b26ce8 100644 --- a/app/javascript/controllers/seats_controller.js +++ b/app/javascript/controllers/seats_controller.js @@ -1,12 +1,28 @@ import { Controller } from "stimulus" +import svgPanZoom from "svg-pan-zoom" export default class extends Controller { static targets = [ "map", "seat", "section", "selection" ] connect() { + this.map = svgPanZoom(this.mapTarget, { + viewportSelector: "#map-viewport", + center: true, + fit: true, + zoomEnabled: false, + zoomScaleSensitivity: 0.75, + minZoom: 1.0, + maxZoom: 8, + }) this.selectSeats() } + disconnect() { + if (!this.mapTarget.hasAttribute("data-turbolinks-permanent")) { + this.map.destroy() + } + } + discardMap() { this.mapTarget.removeAttribute("data-turbolinks-permanent") } @@ -46,4 +62,12 @@ export default class extends Controller { section.removeAttribute("aria-hidden") }) } + + zoomIn() { + this.map.zoomIn() + } + + zoomOut() { + this.map.zoomOut() + } } diff --git a/app/views/seats/_frame.html.erb b/app/views/seats/_frame.html.erb index 27793ded..891b8e6e 100644 --- a/app/views/seats/_frame.html.erb +++ b/app/views/seats/_frame.html.erb @@ -91,42 +91,45 @@ - <% sections.each do |section| %> - = section.price %> - opacity="1.0" - <% else %> - opacity="0.3" - aria-hidden="true" - <% end %> - data-target="seats.section" - data-price="<%= section.price %>" - data-included-opacity="1.0" - data-excluded-opacity="0.3" - > - <% section.seats.each do |seat| %> - - - - - <% end %> - - <% end %> + + <% sections.each do |section| %> + = section.price %> + opacity="1.0" + <% else %> + opacity="0.3" + aria-hidden="true" + <% end %> + data-target="seats.section" + data-price="<%= section.price %>" + data-included-opacity="1.0" + data-excluded-opacity="0.3" + > + <% section.seats.each do |seat| %> + + + + + <% end %> + + <% end %> +