<template>
    <div class="content-main">
        <div class="tool-container">
            <el-button type="primary" text @click="copy">复制</el-button>
            <el-divider direction="vertical" />
            <el-button type="primary" text @click="paste">粘贴</el-button>
            <el-divider direction="vertical" />
            <el-button type="primary" text @click="del">删除</el-button>
            <el-divider direction="vertical" />
            <el-button type="primary" text @click="save">保存</el-button>
            <!-- <el-divider direction="vertical" />
      <el-button type="primary" text @click="exportPng">导出PNG</el-button> -->
        </div>
        <div id="" class="content-container">
            <div class="content">
                <div ref="stencilContainer" class="stencil"></div>
                <div id="graphContainer" ref="graphContainer" class="graph-content"></div>
                <!-- <img src="@/assets/images/road.png" class="roadback" alt="" /> -->
            </div>
        </div>
    </div>
</template>

<script setup lang="ts">
import { Graph, Path, Edge, StringExt, Node, Cell, Model, DataUri } from '@antv/x6';
import { Transform } from '@antv/x6-plugin-transform';
import { Selection } from '@antv/x6-plugin-selection';
import { Snapline } from '@antv/x6-plugin-snapline';
import { Keyboard } from '@antv/x6-plugin-keyboard';
import { Clipboard } from '@antv/x6-plugin-clipboard';
import { Stencil } from '@antv/x6-plugin-stencil';
import { Export } from '@antv/x6-plugin-export';

const stencilContainer = ref();
const graphContainer = ref();

let graph: any = null;

const state = reactive({
    data: {
        nodes: [
            {
                id: 'ac51fb2f-2753-4852-8239-53672a29bb14',
                position: {
                    x: 160,
                    y: 250
                },
                data: {
                    name: '烟感系统'
                }
            },
            {
                id: '81004c2f-0413-4cc6-8622-127004b3befa',
                position: {
                    x: 220,
                    y: 110
                },
                data: {
                    name: '烟感系统'
                }
            },
            {
                id: 'f2db8c64-6ffe-4c9b-83a2-037c9154e599',
                position: {
                    x: 50,
                    y: 120
                },
                data: {
                    name: '摄像头'
                }
            }
        ]
    }
});
const imageShapes = [
    {
        label: '摄像头',
        image: new URL('@/assets/images/camera.svg', import.meta.url).href
    },
    {
        label: '风机',
        image: new URL('@/assets/images/fan.svg', import.meta.url).href
    },
    {
        label: '照明设施',
        image: new URL('@/assets/images/lighting.svg', import.meta.url).href
    },
    {
        label: '烟感系统',
        image: new URL('@/assets/images/smoke.svg', import.meta.url).href
    }
];
const getNodeAttrs = (label) => {
    const [{ image }] = imageShapes.filter((item) => item.label === label);
    return {
        image: {
            'xlink:href': image
        }
    };
};
const init = () => {
    graph = new Graph({
        container: graphContainer.value,
        grid: true,
        mousewheel: {
            enabled: true,
            zoomAtMousePosition: true,
            modifiers: 'ctrl',
            minScale: 0.5,
            maxScale: 3
        },
        highlighting: {
            magnetAdsorbed: {
                name: 'stroke',
                args: {
                    attrs: {
                        fill: '#fff',
                        stroke: '#31d0c6',
                        strokeWidth: 4
                    }
                }
            }
        }
    });
    // graph.centerContent();

    // #region 使用插件
    graph
        .use(
            new Transform({
                resizing: true,
                rotating: true
            })
        )
        .use(
            new Selection({
                rubberband: true,
                showNodeSelectionBox: true
            })
        )
        .use(new Snapline())
        .use(new Keyboard())
        .use(new Clipboard())
        .use(new Export());
    Graph.registerNode(
        'custom-image',
        {
            inherit: 'rect',
            width: 52,
            height: 52,
            markup: [
                {
                    tagName: 'rect',
                    selector: 'body'
                },
                {
                    tagName: 'image'
                },
                {
                    tagName: 'text',
                    selector: 'label'
                }
            ],
            attrs: {
                body: {
                    stroke: '#5F95FF',
                    fill: 'transparent',
                    strokeWidth: 0
                },
                image: {
                    width: 45,
                    height: 45,
                    refX: 5,
                    refY: 5
                },
                label: {
                    refX: 3,
                    refY: 2,
                    textAnchor: 'left',
                    textVerticalAnchor: 'top',
                    fontSize: 12,
                    fill: 'transparent'
                }
            }
        },
        true
    );
    const stencil = new Stencil({
        title: '道路元器',
        target: graph,
        stencilGraphWidth: 200,
        stencilGraphHeight: 180,
        collapsable: true,
        groups: [
            {
                title: '基础元器',
                name: 'processLibrary',
                graphHeight: 250,
                layoutOptions: {
                    rowHeight: 70
                }
            }
        ],
        layoutOptions: {
            columns: 2,
            columnWidth: 80,
            rowHeight: 55
        }
    });
    stencilContainer.value.appendChild(stencil.container);
    graph.drawBackground({
        color: '#ccc',
        position: 'center',
        size: {
            width: '100%'
            // height: 100
        },
        image: new URL('@/assets/images/road.png', import.meta.url).href // 设置背景图片
    });
    // #region 快捷键与事件
    graph.bindKey(['meta+c', 'ctrl+c'], () => {
        copy();
    });
    graph.bindKey(['meta+x', 'ctrl+x'], () => {
        const cells = graph.getSelectedCells();
        if (cells.length) {
            graph.cut(cells);
        }
        return false;
    });
    graph.bindKey(['meta+v', 'ctrl+v'], () => {
        paste();
    });
    // select all
    graph.bindKey(['meta+a', 'ctrl+a'], () => {
        const nodes = graph.getNodes();
        if (nodes) {
            graph.select(nodes);
        }
    });

    // delete
    graph.bindKey('backspace', () => {
        del();
    });

    // zoom
    graph.bindKey(['ctrl+1', 'meta+1'], () => {
        const zoom = graph.zoom();
        if (zoom < 1.5) {
            graph.zoom(0.1);
        }
    });
    graph.bindKey(['ctrl+2', 'meta+2'], () => {
        const zoom = graph.zoom();
        if (zoom > 0.5) {
            graph.zoom(-0.1);
        }
    });

    //节点被取消选中时触发。
    graph.on('node:unselected', (args: { cell: Cell; node: Node; options: Model.SetOptions }) => {
        args.node.removeTools();
    });

    //边选中事件
    graph.on('edge:selected', (args: { cell: Cell; edge: Edge; options: Model.SetOptions }) => {
        args.edge.attr('line/strokeWidth', 3);
    });

    //边被取消选中时触发。
    graph.on('edge:unselected', (args: { cell: Cell; edge: Edge; options: Model.SetOptions }) => {
        args.edge.attr('line/strokeWidth', 1);
    });

    const nodes = imageShapes.map((item) => {
        const node = {
            shape: 'custom-image',
            label: item.label,
            attrs: getNodeAttrs(item.label)
        };
        const newNode = graph.addNode(node);
        return newNode;
    });
    stencil.load(nodes, 'processLibrary');
};

//保存
function save() {
    console.log('save');
    const graphData = graph.toJSON();
    console.log(graphData);
}
//复制
function copy() {
    const cells = graph.getSelectedCells();
    if (cells.length) {
        graph.copy(cells);
    }
    return false;
}
//粘贴
function paste() {
    if (!graph.isClipboardEmpty()) {
        const cells = graph.paste({ offset: 32 });
        graph.cleanSelection();
        graph.select(cells);
    }
    return false;
}
//删除
function del() {
    const cells = graph.getSelectedCells();
    if (cells.length) {
        graph.removeCells(cells);
    }
}

//导出PNG
function exportPng() {
    graph.toPNG(
        (dataUri: string) => {
            // 下载
            DataUri.downloadDataUri(dataUri, 'chart.png');
        },
        {
            padding: {
                top: 20,
                right: 20,
                bottom: 20,
                left: 20
            }
        }
    );
}

//加载初始节点
function getData() {
    let cells = [] as any;
    const location = state.data;
    location.nodes.map((node) => {
        cells.push(
            graph.addNode({
                id: node.id,
                x: node.position.x,
                y: node.position.y,
                shape: 'custom-image',
                attrs: getNodeAttrs(node.data.name),
                label: node.data.name,
                data: node.data
            })
        );
    });
    graph.resetCells(cells);
}

onMounted(() => {
    init();
    getData();
});

onUnmounted(() => {
    graph.dispose();
});
</script>

<style lang="scss" scoped>
.content-main {
    display: flex;
    width: 100%;
    flex-direction: column;
    height: calc(100vh - 85px - 40px);
    background-color: #ffffff;
    position: relative;

    .tool-container {
        padding: 8px;
        display: flex;
        align-items: center;
        color: rgba(0, 0, 0, 0.45);
    }
}
.content-container {
    position: relative;
    width: 100%;
    height: 100%;
    .content {
        width: 100%;
        height: 100%;
        position: relative;
        min-width: 400px;
        min-height: 600px;
        display: flex;
        border: 1px solid #dfe3e8;
        flex-direction: row;
        flex: 1;
        .stencil {
            width: 200px;
            height: 100%;
            border-right: 1px solid #dfe3e8;
            position: relative;

            :deep(.x6-widget-stencil) {
                background-color: #fff;
            }
            :deep(.x6-widget-stencil-title) {
                background-color: #fff;
                display: none;
            }
            :deep(.x6-widget-stencil-content) {
                top: 0;
            }
            :deep(.x6-widget-stencil-group-title) {
                background-color: #fff !important;
            }
        }
        .graph-content {
            width: calc(100% - 180px);
            height: 100%;
        }

        .editor-sidebar {
            display: flex;
            flex-direction: column;
            border-left: 1px solid #e6f7ff;
            background: #fafafa;
            z-index: 9;

            .el-card {
                border: none;
            }
            .edit-panel {
                flex: 1 1;
                background-color: #fff;
            }

            :deep(.x6-widget-minimap-viewport) {
                border: 1px solid #8f8f8f;
            }

            :deep(.x6-widget-minimap-viewport-zoom) {
                border: 1px solid #8f8f8f;
            }
        }
    }
}

:deep(.x6-widget-transform) {
    margin: -1px 0 0 -1px;
    padding: 0px;
    border: 1px solid #239edd;
}
:deep(.x6-widget-transform > div) {
    border: 1px solid #239edd;
}
:deep(.x6-widget-transform > div:hover) {
    background-color: #3dafe4;
}
:deep(.x6-widget-transform-active-handle) {
    background-color: #3dafe4;
}
:deep(.x6-widget-transform-resize) {
    border-radius: 0;
}
:deep(.x6-widget-selection-inner) {
    border: 1px solid #239edd;
}
:deep(.x6-widget-selection-box) {
    opacity: 0;
}

.topic-image {
    visibility: hidden;
    cursor: pointer;
}
.x6-node:hover .topic-image {
    visibility: visible;
}
.x6-node-selected rect {
    stroke-width: 2px;
}
.roadback {
    position: absolute;
    bottom: 0;
    left: 200px;
}
</style>
