mermaid-js / mermaid

Generation of diagrams like flowcharts or sequence diagrams from text in a similar manner as markdown
https://mermaid.js.org
MIT License
72.43k stars 6.6k forks source link

Ability to zoom HTML diagram #2162

Open DrGriff opened 3 years ago

DrGriff commented 3 years ago

Is your feature request related to a problem? Please describe. I've created quite a large complicated flowchart with multiple subgraphs. I embed the diagram in the HTML (as described in the documentation) and am able to pass that to my colleagues. However....the webpage always fit the diagram to the page. As it's become more complex, it requires more space but the page keeps shrinking it to fit, making it harder to see, particularly on a small screen. The Zoom feature in the browser doesn't make the diagram larger.

Describe the solution you'd like Zooming the webpage should allow me to zoom in on the diagram (with horizontal and vertical scroll bars to allow navigation around the diagram).

Describe alternatives you've considered A larger monitor, and updating to glasses 1.1....?

Additional context

go2null commented 3 years ago

This has caused me to break up diagrams

kokizzu commented 2 years ago

indeed, zoom in, zoom out, and panning is really important especially when diagram too large or screen resolution too small

imkarrer commented 2 years ago

++ after all the work to do the documentation of our complicated system to demonstrate where our tech debt is, I cannot effectively leverage the created diagrams without taking a screenshot, and using an image viewer to zoom in 😭

I use the github integration which is a dream otherwise.

artfulrobot commented 2 years ago

This already seems to be a feature on the live editor but I can't find out how to enable it! https://mermaid-js.github.io/mermaid-live-editor/

kkkkkxiaofei commented 1 year ago

The similar issue has been posted since 2019, I'm hesitating to reinvent the wheel to pan my large graph or give mermaid up. 😢

ThomasG77 commented 1 year ago

Dirty code sample to do it. Borrowed code from svg-pan-zoom used in the Live Editor (e.g https://github.com/mermaid-js/mermaid-live-editor/blob/master/src/lib/components/View.svelte#L4 and https://github.com/mermaid-js/mermaid-live-editor/blob/master/package.json#L80)

<html>
  <head>
    <style type="text/css">
      #mySvgId {
        height: 90%;
        width: 90%;
      }
    </style>
  </head>
  <body>
    <div id="graphDiv"></div>
    <script src="https://bumbu.me/svg-pan-zoom/dist/svg-pan-zoom.js"></script>
    <script type="module">
      import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs';
      mermaid.initialize({ startOnLoad: false });
      // Example of using the render function
      const drawDiagram = async function () {
        const element = document.querySelector('#graphDiv');
        const graphDefinition = `
          flowchart TD
          A[Christmas] -->|Get money| B(Go shopping)
          B --> C{Let me think}
          C -->|One| D[Laptop]
          C -->|Two| E[iPhone]
          C -->|Three| F[fa:fa-car Car]
        `;
        const { svg } = await mermaid.render('mySvgId', graphDefinition);
        element.innerHTML = svg.replace(/[ ]*max-width:[ 0-9\.]*px;/i , '');
        var panZoomTiger = svgPanZoom('#mySvgId', {
          zoomEnabled: true,
          controlIconsEnabled: true,
          fit: true,
          center: true
        })
      };
      await drawDiagram();
    </script>
  </body>
</html>
samsmithnz commented 7 months ago

This worked for me, but I had to add some code to make the SVG bigger - it kept defaulting to 150px high:

            document.getElementById('mySvgId').setAttribute("height", "1000px");
            document.getElementById('mySvgId').setAttribute("width", "2000px");
manugarri commented 2 months ago

@ThomasG77 thanks a ton for your snippet, it works perfectly. Do you know how hard it would be to enable the hover tooltip on top of it?

viktorprogger commented 1 month ago

My solution is JS, which is generated by ChatGPT:

        let panX = 0;
        let panY = 0;
        let scale = 1;

            window.onload = function () {
                svgContainer = document.getElementById('mermaid')

                mermaid.initialize({
                    startOnLoad: true,
                });
                svgElement = svgContainer.firstChild
                initControls()
            };

            initControls = () => {
                let isDragging = false;
                let startX, startY;

                svgContainer.addEventListener('mousedown', function (e) {
                    isDragging = true;
                    startX = e.clientX - panX;
                    startY = e.clientY - panY;
                    svgContainer.style.cursor = 'grabbing';
                });

                window.addEventListener('mousemove', function (e) {
                    if (isDragging) {
                        panX = e.clientX - startX;
                        panY = e.clientY - startY;
                        updateTransform();
                    }
                });

                window.addEventListener('mouseup', function () {
                    isDragging = false;
                    svgContainer.style.cursor = 'grab';
                });

                svgContainer.addEventListener('wheel', function (e) {
                    e.preventDefault();
                    const zoomAmount = 1.05;
                    if (e.deltaY < 0) {
                        scale *= zoomAmount;
                    } else {
                        scale /= zoomAmount;
                    }
                    updateTransform();
                });
            }
        })();

        function updateTransform() {
            svgElement.style.transform = `translate(${panX}px, ${panY}px) scale(${scale})`;
        }

You will also like to set overflow:hidden for your svgContainer element.

grappler commented 3 hours ago

Here is another solution using https://github.com/timmywil/panzoom

<div class="diagram-container" id="diagram-container">
    <pre class="mermaid">
        flowchart TD
            A[Christmas] -->|Get money| B(Go shopping)
            B --> C{Let me think}
            C -->|One| D[Laptop]
            C -->|Two| E[iPhone]
            C -->|Three| F[fa:fa-car Car]
    </pre>
</div>
mermaid.initialize({ startOnLoad: false });
await mermaid.run({
    querySelector: '.mermaid',
    postRenderCallback: (id) => {
        const container = document.getElementById("diagram-container");
        const svgElement = container.querySelector("svg");

        // Initialize Panzoom
        const panzoomInstance = Panzoom(svgElement, {
            maxScale: 5,
            minScale: 0.5,
            step: 0.1,
        });

        // Add mouse wheel zoom
        container.addEventListener("wheel", (event) => {
            panzoomInstance.zoomWithWheel(event);
        });
    }
});
.diagram-container {
    width: 100%;
    height: 100%;
    overflow: hidden;
    border: 1px solid #ccc;
    position: relative;
    margin-bottom: 10px;
}
svg {
    cursor: grab;
}