From 2344212ea624feb8788eaab1c8ab48d9d6b92aa9 Mon Sep 17 00:00:00 2001 From: Declan Lynch Date: Mon, 9 Oct 2023 12:17:35 -0400 Subject: [PATCH] SVG Pan/Zoom functionality is now restricted to the modal view of the diagram --- docs/example/workspace.dsl | 1 + .../site/generatr/site/SiteGenerator.kt | 1 + .../site/generatr/site/model/PageViewModel.kt | 2 +- .../site/generatr/site/views/Diagram.kt | 54 +++++++------------ .../site/generatr/site/views/Page.kt | 11 ++-- src/main/resources/assets/css/style.css | 4 ++ .../resources/assets/js/svg-pan-zoom-modal.js | 16 ++++++ 7 files changed, 49 insertions(+), 40 deletions(-) diff --git a/docs/example/workspace.dsl b/docs/example/workspace.dsl index 7b3260c9..04979ea4 100644 --- a/docs/example/workspace.dsl +++ b/docs/example/workspace.dsl @@ -171,6 +171,7 @@ workspace "Big Bank plc" "This is an example workspace to illustrate the key fea // * it's not possible to use "GitLab" and "ResizableImage" extensions together // default behaviour, if no generatr.markdown.flexmark.extensions property is specified, is to load the Tables extension only "generatr.markdown.flexmark.extensions" "Abbreviation,Admonition,AnchorLink,Attributes,Autolink,Definition,Emoji,Footnotes,GfmTaskList,GitLab,MediaTags,Tables,TableOfContents,Typographic" + "generatr.site.enableZoom" "true" } systemlandscape "SystemLandscape" { diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/SiteGenerator.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/SiteGenerator.kt index 515843c3..9e3ca27d 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/SiteGenerator.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/SiteGenerator.kt @@ -20,6 +20,7 @@ fun copySiteWideAssets(exportDir: File) { copySiteWideAsset(exportDir, "/js/admonition.js") copySiteWideAsset(exportDir, "/js/reformat-mermaid.js") copySiteWideAsset(exportDir, "/js/svg-pan-zoom.js") + copySiteWideAsset(exportDir, "/js/svg-pan-zoom-modal.js") } private fun copySiteWideAsset(exportDir: File, asset: String) { diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/PageViewModel.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/PageViewModel.kt index f33ea234..989a2d62 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/PageViewModel.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/model/PageViewModel.kt @@ -24,7 +24,7 @@ abstract class PageViewModel(protected val generatorContext: GeneratorContext) { val configuration = generatorContext.workspace.views.configuration.properties - val includeZoom = configuration.getOrDefault("generatr.nav.enableZoom", "false").toBoolean() + val includeZoom = configuration.getOrDefault("generatr.site.enableZoom", "false").toBoolean() abstract val url: String abstract val pageSubTitle: String diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/Diagram.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/Diagram.kt index e4e6df0f..8af4c9e6 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/Diagram.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/Diagram.kt @@ -10,30 +10,12 @@ fun FlowContent.diagram(viewModel: DiagramViewModel, includeZoom: Boolean) { .map { Random.nextInt(0, charPool.size).let { charPool[it] } } .joinToString("") - if (viewModel.svg != null) + if (viewModel.svg != null) { figure { style = "width: min(100%, ${viewModel.diagramWidthInPixels}px);" - rawHtml(viewModel.svg, diagramId) + rawHtml(viewModel.svg) - script(type = ScriptType.textJavaScript) { - unsafe { - raw(""" - var elm = document.getElementById("${diagramId}"); - elm.setAttribute("style","width: min(100%, ${viewModel.diagramWidthInPixels}px); height: ${viewModel.diagramHeightInPixels}px;"); - var svgElement = elm.firstElementChild; - svgElement.setAttribute("style","display: inline; width: inherit; min-width: inherit; max-width: inherit; height: inherit; min-height: inherit; max-height: inherit; "); - var panZoomBox_${diagramId} = svgPanZoom(svgElement, { - zoomEnabled: true, - controlIconsEnabled: true, - fit: true, - center: true, - minZoom: 1, - maxZoom: 5 - }); - """) - } - } figcaption { +viewModel.name +" [" @@ -45,27 +27,29 @@ fun FlowContent.diagram(viewModel: DiagramViewModel, includeZoom: Boolean) { +"]" } - if (includeZoom){ - div(classes = "modal") { - attributes["id"] = viewModel.name + "_modal" - div(classes = "modal-background") {} - div(classes = "modal-content") { - div(classes = "box") { - p{+"hello world"} - } - } - button(classes = "modal-close is-large") { - attributes["aria-label"] = "close" + + } + if (includeZoom) { + div(classes = "modal") { + attributes["id"] = diagramId + div(classes = "modal-background") {} + div(classes = "modal-content") { + div(classes = "box") { + rawHtml(viewModel.svg, "$diagramId-svg") } } - - button(classes = "js-modal-trigger") { - attributes["data-target"] = viewModel.name + "_modal" - +"Zoom SVG" + button(classes = "modal-close is-large") { + attributes["aria-label"] = "close" } } + button(classes = "js-modal-trigger") { + attributes["data-target"] = diagramId + +"Zoom SVG" + } + } + } else div(classes = "notification is-danger") { +"No view with key" diff --git a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/Page.kt b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/Page.kt index f84d3f9a..a768a5f6 100644 --- a/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/Page.kt +++ b/src/main/kotlin/nl/avisi/structurizr/site/generatr/site/views/Page.kt @@ -42,6 +42,13 @@ private fun HTML.headFragment(viewModel: PageViewModel) { if (viewModel.includeAutoReloading) autoReloadScript(viewModel) + + if (viewModel.includeZoom) { + script( + type = ScriptType.textJavaScript, + src = "../" + "/svg-pan-zoom.js".asUrlToFile(viewModel.url) + ) { } + } } } @@ -71,10 +78,6 @@ private fun HTML.bodyFragment(viewModel: PageViewModel, block: DIV.() -> Unit) { type = ScriptType.textJavaScript, src = "../" + "/svg-pan-zoom-modal.js".asUrlToFile(viewModel.url) ) { } - script( - type = ScriptType.textJavaScript, - src = "../" + "/svg-pan-zoom.js".asUrlToFile(viewModel.url) - ) { } } } diff --git a/src/main/resources/assets/css/style.css b/src/main/resources/assets/css/style.css index 1add5e00..e77ae090 100644 --- a/src/main/resources/assets/css/style.css +++ b/src/main/resources/assets/css/style.css @@ -21,3 +21,7 @@ svg a:hover { opacity: 90%; } + +.modal-content { + width: calc(100vw - 100px); +} diff --git a/src/main/resources/assets/js/svg-pan-zoom-modal.js b/src/main/resources/assets/js/svg-pan-zoom-modal.js index 2ea07f64..8b1354a1 100644 --- a/src/main/resources/assets/js/svg-pan-zoom-modal.js +++ b/src/main/resources/assets/js/svg-pan-zoom-modal.js @@ -1,10 +1,26 @@ document.addEventListener('DOMContentLoaded', () => { // Functions to open and close a modal function openModal($el) { + document.documentElement.classList.add('is-clipped'); $el.classList.add('is-active'); + + console.log($el.id); + const elm = document.getElementById($el.id + "-svg"); + elm.setAttribute("style","width: 100%; height: calc(100vh - 80px);"); + var svgElement = elm.firstElementChild; + svgElement.setAttribute("style","display: inline; width: inherit; min-width: inherit; max-width: inherit; height: inherit; min-height: inherit; max-height: inherit; "); + svgPanZoom(svgElement, { + zoomEnabled: true, + controlIconsEnabled: true, + fit: true, + center: true, + minZoom: 1, + maxZoom: 5 + }); } function closeModal($el) { + document.documentElement.classList.remove('is-clipped'); $el.classList.remove('is-active'); }