JS使用gojs图表流程图

效果图

html代码

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body {
            margin: 0;
        }

        .vessel {
            position: absolute;
            top: 0;
            right: 0;
            z-index: 3;
        }

        .vessel .row1 {
            display: flex;
            justify-content: flex-end;
        }
    </style>
</head>

<body>
    <script>
        window.addEventListener("DOMContentLoaded", function () {
            // topnav
            var topButton = document.getElementById("topnavButton");
            var topnavList = document.getElementById("topnavList");
            if (topButton && topnavList) {
                topButton.addEventListener("click", function (e) {
                    topnavList
                        .classList
                        .toggle("hidden");
                    e.stopPropagation();
                });
                document.addEventListener("click", function (e) {
                    // if the clicked element isn't the list, close the list
                    if (!topnavList.classList.contains("hidden") && !e.target.closest("#topnavList")) {
                        topButton.click();
                    }
                });

                // set active <a> element
                var url = window
                    .location
                    .href
                    .toLowerCase();
                var aTags = topnavList.getElementsByTagName('a');
                for (var i = 0; i < aTags.length; i++) {
                    var lowerhref = aTags[i]
                        .href
                        .toLowerCase();
                    if (url.startsWith(lowerhref)) {
                        aTags[i]
                            .classList
                            .add('active');
                        break;
                    }
                }
            }
        });
    </script>
    <!-- 引入GoJS JavaScript库 -->
    <script src="https://unpkg.com/gojs/release/go-debug.js"></script>

    <script id="code">
        function init() {
            if (window.goSamples) goSamples(); // init for these samples -- you don't need to call this

            myDiagram = new go.Diagram(
                'myDiagramDiv', // must name or refer to the DIV HTML element
                {
                    'undoManager.isEnabled': true, // enable undo & redo
                    'themeManager.changesDivBackground': true,
                    'themeManager.currentTheme': "dark",
                }
            );

            // when the document is modified, add a "*" to the title and enable the "Save" button
            myDiagram.addDiagramListener('Modified', (e) => {
                const button = document.getElementById('SaveButton');
                if (button) button.disabled = !myDiagram.isModified;
                const idx = document.title.indexOf('*');
                if (myDiagram.isModified) {
                    if (idx < 0) document.title += '*';
                } else {
                    if (idx >= 0) document.title = document.title.slice(0, idx);
                }
            });

            // set up some colors/fonts for the default ('light') and dark Themes
            myDiagram.themeManager.set('light', {
                colors: {
                    text: '#fff',
                    start: '#064e3b',
                    step: '#49939e',
                    conditional: '#6a9a8a',
                    end: '#7f1d1d',
                    comment: '#a691cc',
                    bgText: '#000',
                    link: '#dcb263',
                    linkOver: '#cbd5e1',
                    div: '#ede9e0',
                },
            });

            myDiagram.themeManager.set('dark', {
                colors: {
                    text: '#fff',
                    step: '#414a8d',
                    conditional: '#88afa2',
                    comment: '#bfb674',
                    bgText: '#fff',
                    link: '#fdb71c',
                    linkOver: '#475569',
                    div: '#141e37',
                },
            });

            defineFigures();

            // helper definitions for node templates
            function nodeStyle(node) {
                node
                    // the Node.location is at the center of each node
                    .set({ locationSpot: go.Spot.Center })
                    // The Node.location comes from the "loc" property of the node data,
                    // converted by the Point.parse static method.
                    // If the Node.location is changed, it updates the "loc" property of the node data,
                    // converting back using the Point.stringify static method.
                    .bindTwoWay('location', 'loc', go.Point.parse, go.Point.stringify);
            }

            function shapeStyle(shape) {
                // make the whole node shape a port
                shape.set({ strokeWidth: 0, portId: '', cursor: 'pointer' });
            }

            function textStyle(textblock) {
                textblock.set({ font: 'bold 11pt Figtree, sans-serif' }).theme('stroke', 'text');
            }

            // define the Node templates for regular nodes
            myDiagram.nodeTemplateMap.add(
                '', // the default category
                new go.Node('Auto').apply(nodeStyle).add(
                    new go.Shape('Rectangle', {
                        fromLinkable: true,
                        toLinkable: true,
                        fromSpot: go.Spot.AllSides,
                        toSpot: go.Spot.AllSides,
                    })
                        .apply(shapeStyle)
                        .theme('fill', 'step'),
                    new go.TextBlock({
                        margin: 12,
                        maxSize: new go.Size(160, NaN),
                        wrap: go.Wrap.Fit,
                        editable: true,
                    })
                        .apply(textStyle)
                        .bindTwoWay('text')
                )
            );

            myDiagram.nodeTemplateMap.add(
                'Conditional',
                new go.Node('Auto').apply(nodeStyle).add(
                    new go.Shape('Conditional', { fromLinkable: true, toLinkable: true }).apply(shapeStyle).theme('fill', 'conditional'),
                    new go.TextBlock({
                        margin: 8,
                        maxSize: new go.Size(160, NaN),
                        wrap: go.Wrap.Fit,
                        textAlign: 'center',
                        editable: true,
                    })
                        .apply(textStyle)
                        .bindTwoWay('text')
                )
            );

            myDiagram.nodeTemplateMap.add(
                'Start',
                new go.Node('Auto')
                    .apply(nodeStyle)
                    .add(
                        new go.Shape('Capsule', { fromLinkable: true }).apply(shapeStyle).theme('fill', 'start'),
                        new go.TextBlock('Start', { margin: new go.Margin(5, 6) }).apply(textStyle).bind('text')
                    )
            );

            myDiagram.nodeTemplateMap.add(
                'End',
                new go.Node('Auto')
                    .apply(nodeStyle)
                    .add(
                        new go.Shape('Capsule', { toLinkable: true }).apply(shapeStyle).theme('fill', 'end'),
                        new go.TextBlock('End', { margin: new go.Margin(5, 6) }).apply(textStyle).bind('text')
                    )
            );

            myDiagram.nodeTemplateMap.add(
                'Comment',
                new go.Node('Auto').apply(nodeStyle).add(
                    new go.Shape('File', { strokeWidth: 3 }).theme('fill', 'div').theme('stroke', 'comment'),
                    new go.TextBlock({
                        font: '9pt Figtree, sans-serif',
                        margin: 8,
                        maxSize: new go.Size(200, NaN),
                        wrap: go.Wrap.Fit,
                        textAlign: 'center',
                        editable: true,
                    })
                        .theme('stroke', 'bgText')
                        .bindTwoWay('text')
                    // no ports, because no links are allowed to connect with a comment
                )
            );

            // replace the default Link template in the linkTemplateMap
            myDiagram.linkTemplate = new go.Link({
                routing: go.Routing.AvoidsNodes,
                curve: go.Curve.JumpOver,
                corner: 5,
                toShortLength: 4,
                relinkableFrom: true,
                relinkableTo: true,
                reshapable: true,
                resegmentable: true,
                // mouse-overs subtly highlight links:
                mouseEnter: (e, link) => (link.findObject('HIGHLIGHT').stroke = link.diagram.themeManager.findValue('linkOver', 'colors')),
                mouseLeave: (e, link) => (link.findObject('HIGHLIGHT').stroke = 'transparent'),
                // context-click creates an editable link label
                contextClick: (e, link) => {
                    e.diagram.model.commit((m) => {
                        m.set(link.data, 'text', 'Label');
                    });
                },
            })
                .bindTwoWay('points')
                .add(
                    // the highlight shape, normally transparent
                    new go.Shape({
                        isPanelMain: true,
                        strokeWidth: 8,
                        stroke: 'transparent',
                        name: 'HIGHLIGHT',
                    }),
                    // the link path shape
                    new go.Shape({ isPanelMain: true, strokeWidth: 2 }).theme('stroke', 'link'),
                    // the arrowhead
                    new go.Shape({ toArrow: 'standard', strokeWidth: 0, scale: 1.5 }).theme('fill', 'link'),
                    // the link label
                    new go.Panel('Auto', { visible: false })
                        .bind('visible', 'text', (t) => typeof t === 'string' && t.length > 0) // only shown if there is text
                        .add(
                            // a gradient that fades into the background
                            new go.Shape('Ellipse', { strokeWidth: 0 }).theme('fill', 'div', null, null, (c) => {
                                return new go.Brush(go.BrushType.Radial, {
                                    colorStops: new go.Map([
                                        { key: 0, value: c },
                                        { key: 0.5, value: `${c}00` },
                                    ]),
                                });
                            }),
                            new go.TextBlock({
                                name: 'LABEL',
                                font: '9pt Figtree, sans-serif',
                                margin: 3,
                                editable: true,
                            })
                                .theme('stroke', 'bgText')
                                .bindTwoWay('text')
                        )
                );

            // temporary links used by LinkingTool and RelinkingTool are also orthogonal:

            myDiagram.toolManager.linkingTool.temporaryLink.routing = go.Routing.Orthogonal;
            myDiagram.toolManager.relinkingTool.temporaryLink.routing = go.Routing.Orthogonal;

            load(); // load an initial diagram from some JSON text

            // initialize the Palette that is on the left side of the page
            myPalette = new go.Palette(
                'myPaletteDiv', // must name or refer to the DIV HTML element
                {
                    nodeTemplateMap: myDiagram.nodeTemplateMap, // share the templates used by myDiagram
                    themeManager: myDiagram.themeManager, // share the ThemeManager used by myDiagram
                    model: new go.GraphLinksModel([
                        // specify the contents of the Palette
                        { category: 'Start', text: 'Start' },
                        { text: 'Step' },
                        { category: 'Conditional', text: '???' },
                        { category: 'End', text: 'End' },
                        { category: 'Comment', text: 'Comment' },
                    ]),
                }
            );
        } // end init

        // define some custom shapes for node templates
        function defineFigures() {
            go.Shape.defineFigureGenerator('Conditional', (shape, w, h) => {
                const geo = new go.Geometry();
                const fig = new go.PathFigure(w * 0.15, 0, true);
                geo.add(fig);
                fig.add(new go.PathSegment(go.SegmentType.Line, w * 0.85, 0));
                fig.add(new go.PathSegment(go.SegmentType.Line, w, 0.5 * h));
                fig.add(new go.PathSegment(go.SegmentType.Line, w * 0.85, h));
                fig.add(new go.PathSegment(go.SegmentType.Line, w * 0.15, h));
                fig.add(new go.PathSegment(go.SegmentType.Line, 0, 0.5 * h).close());
                geo.spot1 = new go.Spot(0.15, 0);
                geo.spot2 = new go.Spot(0.85, 1);
                return geo;
            });

            // taken from ../extensions/Figures.js:
            go.Shape.defineFigureGenerator('File', (shape, w, h) => {
                const geo = new go.Geometry();
                const fig = new go.PathFigure(0, 0, true); // starting point
                geo.add(fig);
                fig.add(new go.PathSegment(go.SegmentType.Line, 0.75 * w, 0));
                fig.add(new go.PathSegment(go.SegmentType.Line, w, 0.25 * h));
                fig.add(new go.PathSegment(go.SegmentType.Line, w, h));
                fig.add(new go.PathSegment(go.SegmentType.Line, 0, h).close());
                const fig2 = new go.PathFigure(0.75 * w, 0, false);
                geo.add(fig2);
                // The Fold
                fig2.add(new go.PathSegment(go.SegmentType.Line, 0.75 * w, 0.25 * h));
                fig2.add(new go.PathSegment(go.SegmentType.Line, w, 0.25 * h));
                geo.spot1 = new go.Spot(0, 0.25);
                geo.spot2 = go.Spot.BottomRight;
                return geo;
            });
        }

        let data = {
            "class": "GraphLinksModel",
            "nodeDataArray": [
                { "key": -1, "category": "Start", "loc": "-237 41", "text": "Start" },
                { "key": -2, "category": "End", "loc": "277 696", "text": "End" },
                { "category": "Conditional", "text": "Is data\ntree-like?", "key": -14, "loc": "40 165" },
                { "text": "Use a TreeModel", "key": -5, "loc": "-100 230" },
                { "text": "Use a GraphLinksModel", "key": -6, "loc": "180 230" },
                { "category": "Comment", "text": "GraphLinksModel\nalso allows Groups", "key": -7, "loc": "362 230" },
                { "text": "Create DIV for Diagram", "key": -8, "loc": "-64 41" },
                { "text": "Create new Diagram associated with DIV", "key": -9, "loc": "164 41" },
                { "text": "Style node templates", "key": -10, "loc": "40 617" },
                { "text": "Add data to node/linkDataArray", "key": -12, "loc": "180 320" },
                { "text": "Add data to nodeDataArray, including parent", "key": -13, "loc": "-100 320" },
                { "text": "Style link templates", "key": -15, "loc": "277 617" },
                { "category": "Conditional", "text": "Should nodes be auto-positioned?", "key": -16, "loc": "40 460" },
                { "text": "Choose a layout", "key": -18, "loc": "-100 525" },
                { "text": "Set location in node data and bind", "key": -17, "loc": "180 525" }
            ],
            "linkDataArray": [
                { "from": -1, "to": -8 },
                { "from": -8, "to": -9 },
                { "from": -5, "to": -13 },
                { "from": -6, "to": -12 },
                { "from": -15, "to": -2 },
                { "from": -14, "to": -5, "text": "Yes" },
                { "from": -14, "to": -6, "text": "No" },
                { "from": -9, "to": -14 },
                { "from": -13, "to": -16 },
                { "from": -12, "to": -16 },
                { "from": -16, "to": -18, "text": "Yes" },
                { "from": -16, "to": -17, "text": "No" },
                { "from": -18, "to": -10 },
                { "from": -17, "to": -10 },
                { "from": -10, "to": -15 }
            ]
        }

        // Show the diagram's model in JSON format that the user may edit
        function save() {
            document.getElementById('mySavedModel').value = myDiagram.model.toJson();
            myDiagram.isModified = false;
        }

        function load() {
            myDiagram.model = go.Model.fromJson(data);
            document.getElementById('mySavedModel').value = myDiagram.model.toJson()
        }
        function empty() {
            myDiagram.model.nodeDataArray = [];
            myDiagram.model.linkDataArray = [];
            document.getElementById('mySavedModel').value = ''
        }

        // print the diagram by opening a new window holding SVG images of the diagram contents for each page
        function printDiagram() {
            const svgWindow = window.open();
            if (!svgWindow) return; // failure to open a new Window
            svgWindow.document.title = "GoJS Flowchart";
            svgWindow.document.body.style.margin = "0px";
            const printSize = new go.Size(700, 960);
            const bnds = myDiagram.documentBounds;
            let x = bnds.x;
            let y = bnds.y;
            while (y < bnds.bottom) {
                while (x < bnds.right) {
                    const svg = myDiagram.makeSvg({
                        scale: 1.0,
                        position: new go.Point(x, y),
                        size: printSize,
                        background: myDiagram.themeManager.findValue('div', 'colors'),
                    });
                    svgWindow.document.body.appendChild(svg);
                    x += printSize.width;
                }
                x = bnds.x;
                y += printSize.height;
            }
            setTimeout(() => { svgWindow.print(); svgWindow.close(); }, 1);
        }

        function changeTheme() {
            const myDiagram = go.Diagram.fromDiv('myDiagramDiv');
            if (myDiagram) {
                myDiagram.themeManager.currentTheme = document.getElementById('theme').value;
            }
        }

        window.addEventListener('DOMContentLoaded', () => {
            // setTimeout only to ensure font is loaded before loading diagram
            // you may want to use an asset loading library for this
            // to keep this sample simple, it does not
            setTimeout(() => {
                init();
            }, 300);
        });
    </script>

    <div class="sampleWrapper">
        <div style="width: 100%; height: fit-content; display: flex; flex: 2">
            <div id="myPaletteDiv" style="width: 100px; margin-right: 2px"></div>
            <div id="myDiagramDiv" style="flex-grow: 1; height: 100vh"></div>
        </div>

        <div class="vessel">
            <div class="row1">
                <select id="theme" onchange="changeTheme()">
                    <option value="light">Light</option>
                    <option value="dark" selected>Dark</option>
                </select>
                <button onclick="printDiagram()">打印</button>
                <button onclick="empty()">清空</button>
                <button id="SaveButton" onclick="save()">保存</button>
                <button onclick="load()">重新加载</button>
            </div>
            <textarea id="mySavedModel" style="width: 400px; height: 400px"></textarea>
        </div>
    </div>

</body>

</html>

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值