Skip to content

Commit

Permalink
Merge pull request #334 from jp7677/svg-pan-zoom2
Browse files Browse the repository at this point in the history
Add pan and zoom for diagrams
  • Loading branch information
jp7677 authored Oct 21, 2023
2 parents df225cc + d485ffe commit 86da272
Show file tree
Hide file tree
Showing 10 changed files with 137 additions and 15 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"lunr": "2.3.9",
"lunr-languages": "1.14.0",
"mermaid": "10.5.1",
"svg-pan-zoom": "3.6.1",
"webfontloader": "1.6.28"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import java.security.MessageDigest
fun copySiteWideAssets(exportDir: File) {
copySiteWideAsset(exportDir, "/css/style.css")
copySiteWideAsset(exportDir, "/js/header.js")
copySiteWideAsset(exportDir, "/js/svg-modal.js")
copySiteWideAsset(exportDir, "/js/search.js")
copySiteWideAsset(exportDir, "/js/auto-reload.js")
copySiteWideAsset(exportDir, "/css/admonition.css")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ class CDN {
"${it.baseUrl()}/dist/mermaid.esm.min.mjs"
}

fun svgpanzoomJs() = dependencies.single { it.name == "svg-pan-zoom" }.let {
"${it.baseUrl()}/dist/svg-pan-zoom.min.js"
}

fun webfontloaderJs() = dependencies.single { it.name == "webfontloader" }.let {
"${it.baseUrl()}/webfontloader.js"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,58 @@ import kotlinx.html.*
import nl.avisi.structurizr.site.generatr.site.model.DiagramViewModel

fun FlowContent.diagram(viewModel: DiagramViewModel) {
if (viewModel.svg != null)
if (viewModel.svg != null) {
val dialogId = "${viewModel.key}-modal"
val svgId = "${viewModel.key}-svg"

figure {
style = "width: min(100%, ${viewModel.diagramWidthInPixels}px);"

rawHtml(viewModel.svg)
figcaption {
+viewModel.name
+" ["
a(href = viewModel.svgLocation.relativeHref) { +"svg" }
+"|"
a(href = viewModel.pngLocation.relativeHref) { +"png" }
+"|"
a(href = viewModel.pumlLocation.relativeHref) { +"puml" }
+"]"
a {
onClick = "openModal(\"$dialogId\", \"$svgId\")"
+viewModel.name
}
}
}
else
svgModal(dialogId, svgId, viewModel)
} else
div(classes = "notification is-danger") {
+"No view with key"
span(classes = "has-text-weight-bold") { +" ${viewModel.key} " }
+"found!"
}
}

private fun FlowContent.svgModal(
dialogId: String,
svgId: String,
viewModel: DiagramViewModel
) {
div(classes = "modal") {
id = dialogId

div(classes = "modal-background") {
onClick = "closeModal(\"$dialogId\")"
}
div(classes = "modal-content") {
div(classes = "box") {
rawHtml(viewModel.svg!!, svgId, "modal-box-content")
div(classes = "has-text-centered") {
+" ["
a(href = viewModel.svgLocation.relativeHref, target = "_blank") { +"svg" }
+"|"
a(href = viewModel.pngLocation.relativeHref, target = "_blank") { +"png" }
+"|"
a(href = viewModel.pumlLocation.relativeHref, target = "_blank") { +"puml" }
+"]"
}
}
}
button(classes = "modal-close is-large") {
attributes["aria-label"] = "close"
onClick = "closeModal(\"$dialogId\")"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ private fun HTML.headFragment(viewModel: PageViewModel) {
link(rel = "stylesheet", href = CDN.bulmaCss())
link(rel = "stylesheet", href = "../" + "/style.css".asUrlToFile(viewModel.url))
link(rel = "stylesheet", href = "./" + "/style-branding.css".asUrlToFile(viewModel.url))
script(type = ScriptType.textJavaScript, src = "../" + "/svg-modal.js".asUrlToFile(viewModel.url)) { }
script(type = ScriptType.textJavaScript, src = CDN.svgpanzoomJs()) { }

if (viewModel.includeTreeview)
link(rel = "stylesheet", href = "../" + "/treeview.css".asUrlToFile(viewModel.url))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package nl.avisi.structurizr.site.generatr.site.views

import kotlinx.html.FlowContent
import kotlinx.html.div
import kotlinx.html.unsafe
import kotlinx.html.*

fun FlowContent.rawHtml(html: String) {
fun FlowContent.rawHtml(html: String, contentId: String? = null, contentClass: String? = null) {
div {
if (contentId != null) id = contentId
if (contentClass != null) classes = setOf(contentClass)

unsafe {
+html
}
Expand Down
19 changes: 19 additions & 0 deletions src/main/resources/assets/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,22 @@
svg a:hover {
opacity: 90%;
}

.modal-content {
width: calc(100vw - 120px);
}

.modal-box-content {
width: 100%;
height: calc(100vh - 120px);
}

.modal-svg {
display: inline;
width: inherit;
min-width: inherit;
max-width: inherit;
height: inherit;
min-height: inherit;
max-height: inherit;
}
48 changes: 48 additions & 0 deletions src/main/resources/assets/js/svg-modal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
let pz = undefined;

function resetPz() {
if (pz) {
pz.resize();
pz.center();
pz.reset();
}
}

function openModal(id, svgId) {
document.getElementById(id).classList.add('is-active')

const svgElement = document.getElementById(svgId).firstElementChild;
svgElement.classList.add('modal-svg')

pz = svgPanZoom(svgElement, {
zoomEnabled: true,
controlIconsEnabled: true,
fit: true,
center: true,
minZoom: 1,
maxZoom: 5
});
resetPz();

// Reset position on window resize
window.addEventListener('resize', resetPz);
}

function closeModal(id) {
if (pz) {
pz.destroy();
}
window.removeEventListener('resize', resetPz);
document.getElementById(id).classList.remove('is-active');
}

// Add a keyboard event to close all modals
document.addEventListener('keydown', (event) => {
if (event.code === 'Escape') {
(document.querySelectorAll('.modal') || []).forEach((modal) => {
if (modal.classList.contains('is-active')) {
closeModal(modal.id);
}
});
}
});
Original file line number Diff line number Diff line change
Expand Up @@ -263,9 +263,22 @@ class MarkdownToHtmlTest : ViewModelTest() {
<svg viewBox="0 0 800 900"></svg>
</div>
<figcaption>
System Landscape Diagram [<a href="svg/SystemLandscape.svg">svg</a>|<a href="png/SystemLandscape.png">png</a>|<a href="puml/SystemLandscape.puml">puml</a>]
<a onclick="openModal(&quot;SystemLandscape-modal&quot;, &quot;SystemLandscape-svg&quot;)">System Landscape Diagram</a>
</figcaption>
</figure>
<div class="modal" id="SystemLandscape-modal">
<div class="modal-background" onclick="closeModal(&quot;SystemLandscape-modal&quot;)"></div>
<div class="modal-content">
<div class="box">
<div id="SystemLandscape-svg" class="modal-box-content">
<svg viewBox="0 0 800 900"></svg>
</div>
<div class="has-text-centered">
[<a href="svg/SystemLandscape.svg" target="_blank">svg</a>|<a href="png/SystemLandscape.png" target="_blank">png</a>|<a href="puml/SystemLandscape.puml" target="_blank">puml</a>]
</div>
</div>
</div><button class="modal-close is-large" aria-label="close" onclick="closeModal(&quot;SystemLandscape-modal&quot;)"></button>
</div>
</div></p>
""".trimIndent()
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class CDNTest {
CDN.lunrLanguagesStemmerJs() to "/min/lunr.stemmer.support.min.js",
CDN.lunrLanguagesJs("en") to "/min/lunr.en.min.js",
CDN.mermaidJs() to "/dist/mermaid.esm.min.mjs",
CDN.svgpanzoomJs() to "/dist/svg-pan-zoom.min.js",
CDN.webfontloaderJs() to "/webfontloader.js"
).map { (url, suffix) ->
DynamicTest.dynamicTest(url) {
Expand Down

0 comments on commit 86da272

Please sign in to comment.