function FlowDisplay (diagramDiv,event) {
    var G = go.GraphObject.make;
    var _this = {};
    var _displayer = {};

    /** 处理传入事件 */
    if(!event){
        event = {
            showEditNode:()=>{},
            SelectionDeleted:() => {},
            LinkDrawn:() => {},
            externalobjectsdropped: () => {}
        }
    }
    if(event.showEditNode){  //编辑节点
        _this.showEditNode = event.showEditNode
    }
    if(event.SelectionDeleted){  //删除事件
        _this.SelectionDeleted = event.SelectionDeleted
    }
    if(event.LinkDrawn){  //线的生成事件
        _this.LinkDrawn = event.LinkDrawn
    }
    if(event.externalobjectsdropped){  //节点的生成事件
        _this.externalobjectsdropped = event.externalobjectsdropped
    }

    /** --------public method----------------------------------------**/

    /**
     * 显示流程图
     * @param flowData  流程图json数据
     */
    this.loadFlow = function (flowData) {
        if(!flowData) return;

        _displayer.model = go.Model.fromJson(flowData);

        var pos = _displayer.model.modelData.position;
        // if (pos) _displayer.initialPosition = go.Point.parse(pos);


        this.diagram = _displayer

        // 更改所有连线中间的文本背景色
        setLinkTextBg();
    };

    /**
     * 获取流程图数据
     * @returns {*}
     */
    this.getFlowData = function () {
        _displayer.model.modelData.position = go.Point.stringify(_displayer.position);
        return _displayer.model.toJson();
    };

    /**
     * 动画显示流程路径状态
     * strStepKeys 已经通过的流程节点key
     * isCompleted 流程是否已完成
     * isEnd 是否是已关闭流程，已关闭流程的待处理节点则为关闭状态
     */
    this.animateFlowPath = function(strStepKeys, errorPathIds, isCompleted, isEnd) {
        if(!strStepKeys){
            return
        }
        var stepKeys = strStepKeys.split(',');
 
        // 查找所有【已完成】步骤：【开始】-> 【已完成】（N个）
        var steps = findFinishedSteps(stepKeys, isCompleted);
        // 高亮所有“已完成”步骤
        showFinishedNodes(steps);

        //【开始】-> 【已完成】（N个）->【待处理】
        // 或
        //【开始】-> 【已完成】（N个）->【结束】
        var lastStep = findLastStep(stepKeys, steps, isCompleted,isEnd);
        steps.push(lastStep);
        if (!isCompleted) {
            // “待处理”步骤，加上闪烁动画
            loopRunningNode(lastStep,isEnd);
        }

        // 在连线上加闪烁动画
        if(errorPathIds && errorPathIds.length > 0){
            var links = findFinishedLinks(lastStep);
            loopLinks(links);
        }
        
    };

    // 当前画布实例
    /** --------public method-------------end---------------------------**/

    this.diagram =  init(diagramDiv);

    /** --------private method----------------------------------------**/

    /**
     * 初始化流程设计器
     * @param divId 设计器Div
     */
    function init(divId) {
        _displayer = G(go.Diagram, divId,
            {
                allowDrop: false,
                allowSelect: false,
                allowHorizontalScroll: true,
                allowVerticalScroll: true,
                allowMove: false,
                allowLink: false,
                allowRelink: false,
                "draggingTool.dragsLink": false
            });

        // 流程步骤的样式模板
        _displayer.nodeTemplate = makeNodeTemplate();

        // 双击事件
        _displayer.addDiagramListener("ObjectDoubleClicked", onObjectDoubleClicked);
        

        // 添加开始节点
        _displayer.nodeTemplateMap.add("Start",
            G(go.Node, "Spot",
            { locationSpot: go.Spot.Center },
                new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
            { selectable: true, selectionAdornmentTemplate: makeNodeSelectionAdornmentTemplate() },
                new go.Binding("angle").makeTwoWay(),
            G(go.Panel, "Auto",
                    { name: "PANEL" },
                    new go.Binding("desiredSize", "size", go.Size.parse).makeTwoWay(go.Size.stringify),
                G(go.Shape, "Circle", // default figure
                        {
                            portId: "", // the default port: if no spot on link data, use closest side
                            name: "PIPE",
                            fromLinkable: true,
                            toLinkable: true,
                            cursor: "pointer",
                            fill: "#5F7790", // default color
                            strokeWidth: 1,
                            stroke: "#5F7790"
                        },
                        new go.Binding("figure"),
                        new go.Binding("stroke"),
                        new go.Binding("strokeDashArray"),
                        new go.Binding("strokeWidth"),
                        new go.Binding("fill")),
                G(go.TextBlock,
                        {
                            font: "bold 11pt Helvetica, Arial, sans-serif",
                            margin:8,
                            wrap: go.TextBlock.WrapFit,
                            stroke: "white",
                            overflow:go.TextBlock.OverflowEllipsis
                        },
                        new go.Binding("text").makeTwoWay()),
                    // {
                    //     toolTip: G(go.Adornment, "Auto",
                    //         G(go.Shape, { fill: "#FFFFCC" }),
                    //         G(go.TextBlock, { margin: 4 },
                    //             new go.Binding("text", "", nodeInfo))
                    //     )
                    // }
                )
        ));
        
        // 添加结束节点
        _displayer.nodeTemplateMap.add("End",
            G(go.Node, "Spot",
            { locationSpot: go.Spot.Center },
                new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
            { selectable: true, selectionAdornmentTemplate: makeNodeSelectionAdornmentTemplate() },
                new go.Binding("angle").makeTwoWay(),
            G(go.Panel, "Auto",
                    { name: "PANEL" },
                    new go.Binding("desiredSize", "size", go.Size.parse).makeTwoWay(go.Size.stringify),
                G(go.Shape, "Circle", // default figure
                        {
                            portId: "", // the default port: if no spot on link data, use closest side
                            name: "PIPE",
                            fromLinkable: true,
                            toLinkable: true,
                            cursor: "pointer",
                            fill: "#5F7790", // default color
                            strokeWidth: 1,
                            stroke: "#5F7790"
                        },
                        new go.Binding("figure"),
                        new go.Binding("stroke"),
                        new go.Binding("strokeDashArray"),
                        new go.Binding("strokeWidth"),
                        new go.Binding("fill")),
                G(go.TextBlock,
                        {
                            font: "bold 11pt Helvetica, Arial, sans-serif",
                            margin: 8,
                            wrap: go.TextBlock.WrapFit,
                            stroke: "white"
                        },
                        new go.Binding("text").makeTwoWay()),
                    // {
                    //     toolTip: G(go.Adornment, "Auto",
                    //         G(go.Shape, { fill: "#FFFFCC" }),
                    //         G(go.TextBlock, { margin: 4 },
                    //             new go.Binding("text", "", nodeInfo))
                    //     )
                    // }
                )
        ));

        // 流程连接线的样式模板
        _displayer.linkTemplate = makeLinkTemplate();

        return _displayer
    }


    /**
     * 步骤图的样式模板
     * @returns {*}
     */
    function makeNodeTemplate(){
        return G(go.Node, "Spot",
            { locationSpot: go.Spot.Center },
                new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
            { selectable: true, selectionAdornmentTemplate: makeNodeSelectionAdornmentTemplate() },
                new go.Binding("angle").makeTwoWay(),
            G(go.Panel, "Auto",
                    { name: "PANEL" },
                    new go.Binding("desiredSize", "size", go.Size.parse).makeTwoWay(go.Size.stringify),
                G(go.Shape, "RoundedRectangle", // default figure
                        {
                            portId: "", // the default port: if no spot on link data, use closest side
                            name: "PIPE",
                            fromLinkable: true,
                            toLinkable: true,
                            cursor: "pointer",
                            fill: "white", // default color
                            strokeWidth: 1,
                            stroke: "#DCDEE2"
                        },
                        new go.Binding("figure"),
                        new go.Binding("stroke"),
                        new go.Binding("strokeDashArray"),
                        new go.Binding("strokeWidth"),
                        new go.Binding("fill")),
                G(go.TextBlock,
                        {
                            font: "bold 11pt Helvetica, Arial, sans-serif",
                            margin: 8,
                            wrap: go.TextBlock.WrapFit,
                            stroke: "#343434",
                            textAlign: "center",
                            alignment: go.Spot.Center,
                            verticalAlignment: go.Spot.Center,
                            wrap: go.TextBlock.WrapFit,
                            minSize: new go.Size(126, 27),
                            maxSize: new go.Size(126, NaN)
                        },
                        new go.Binding("text").makeTwoWay()),
                    // {
                    //     toolTip: G(go.Adornment, "Auto",
                    //         G(go.Shape, { fill: "#FFFFCC" }),
                    //         G(go.TextBlock, { margin: 4 },
                    //             new go.Binding("text", "", nodeInfo))
                    //     )
                    // }
                )
        );
    }

    /**
     * 选中节点的样式
     * @returns {*}
     */
    function makeNodeSelectionAdornmentTemplate(){
        return G(go.Adornment, "Auto",
            G(go.Shape, { fill: null, stroke: "deepskyblue", strokeWidth: 1.5, strokeDashArray: [4, 2] }),
            G(go.Placeholder)
        );
    }

    /**
     * 流程图元素的双击事件
     * @param ev
     */
    function onObjectDoubleClicked(ev) {
        var part = ev.subject.part;
        showEditNode(part);
    }

    /**
     * 编辑节点信息
     */
    function showEditNode(node) {
        _this.showEditNode(node)
        return node
    }

    /**
     * tooltip上显示的信息
     * @param d
     * @returns {string}
     */
    function nodeInfo(d) {
        if (!d.key) return "无key";
        return "编号：" + d.key;
    }

    /**
     * 定义连接线的样式模板
     * @returns {*}
     */
    function makeLinkTemplate(){
        return G(go.Link,
            { selectable: false },
            { relinkableFrom: true, relinkableTo: true, reshapable: true },
            {
                routing: go.Link.AvoidsNodes,
                curve: go.Link.JumpOver,
                corner: 5,
                toShortLength: 4
            },
            new go.Binding("layerName", "color"),
            new go.Binding("zOrder"),
            // G(go.Shape, { isPanelMain: true, stroke: "black", strokeWidth: 3 }, new go.Binding("stroke"),new go.Binding("zOrder")),
            G(go.Shape, { isPanelMain: true, stroke: "#D5D5D5", strokeWidth: 2 }),
            G(go.Shape, { isPanelMain: true, stroke: "#D5D5D5", strokeWidth: 1, name: "PIPE",  }),
            G(go.Shape,
                { toArrow: "standard", stroke: null, fill: '#D5D5D5' }, new go.Binding("stroke"), new go.Binding("fill"), new go.Binding("zOrder")),
            G(go.Panel, "Auto",
                G(go.Shape, {
                    fill: null,
                    stroke: null
                }, new go.Binding("fill", "pFill"), new go.Binding("zOrder")),
                G(go.TextBlock,
                    {
                        textAlign: "center",
                        font: "10pt helvetica, arial, sans-serif",
                        stroke: "#555555",
                        margin: 4
                    },
                    new go.Binding("text", "text"), new go.Binding("zOrder"))
            )
        );
    }

    /**
     * 返回所有【已完成】的步骤
     * @param stepKeys
     * @param isCompleted
     * @returns {Array}
     */
    function findFinishedSteps(stepKeys, isCompleted) {

        var arrStep = [];

        if (!stepKeys) return arrStep;

        var startStep = findStartStep();// 【开始】步骤
        arrStep.push(startStep);

        // 【已完成】的步骤
        var finishedCount = stepKeys.length - 1;// 不包含最后一个“待处理“步骤
        if (isCompleted) {
            finishedCount = stepKeys.length;// 包含所有步骤
        }
        for (var i = 0; i < finishedCount; i++) {
            var stepKey = stepKeys[i];
            var step = _displayer.findNodeForKey(stepKey);
            if (!step) continue;

            arrStep.push(step);
        }
        return arrStep;
    }

    /**
     * 高亮“已完成”步骤
     * @param steps
     */
    function showFinishedNodes(steps) {

        if (!steps) return;
        for (var i = 0; i < steps.length; i++) {
            var step = steps[i];
            // 步骤(去除开始和结束节点)
            if(step.data.type !== 1 && step.data.type !== 2){
                _displayer.startTransaction("vacate");
                _displayer.model.setDataProperty(step.data, "fill", "rgba(9,161,85,0.04)");
                _displayer.model.setDataProperty(step.data, "stroke", "rgba(9,161,85,1)");
                _displayer.model.setDataProperty(step.data, "strokeWidth", 1);
                _displayer.commitTransaction("vacate");
            }
            
            
        }
    }

    /**
     *
     * 查找【开始】节点
     * @param {} steps
     * @returns {}
     */
    function findStartStep() {
        var startStep = null;
        _displayer.nodes.each(function(step) {
            if (step.data.hasOwnProperty('key') && step.data.key == -1) {
                startStep = step;
                return false;
            }
        });
        return startStep;
    }

    /**
     * 循环闪烁“已完成”步骤之间的连线
     * @param links
     */
    function loopLinks(links) {
        setTimeout(function () {
            showFinishedLinks(links);// “已完成”连线
        }, 300);
    }

    /**
     * 循环闪烁“待处理”步骤
     * @param node
     */
    function loopRunningNode(node,isEnd) {
        setTimeout(function () {
            showRunningNode(node,isEnd);
            // loopRunningNode(node);
        }, 200);
    }

    /**
     * 高亮“待处理”步骤
     * @param node
     */
    function showRunningNode(node,isEnd) {
        if (!node) return;
        // 去除结束节点和开始节点
        if(node.data.type === 1 || node.data.type === 2){
            return
        }
        if(!isEnd){
            _displayer.startTransaction("vacate");
            _displayer.model.setDataProperty(node.data, "fill", (node.data.fill === "#ff9001") ? "#ffB001" : "rgba(255,153,0,0.04)");
            _displayer.commitTransaction("vacate");
        }else{
            _displayer.startTransaction("vacate");
            _displayer.model.setDataProperty(node.data, "fill", (node.data.fill === "#ff9001") ? "#ffB001" : "rgba(237,64,20,0.04)");
            _displayer.commitTransaction("vacate");
        }
        
        

        // 边框加上流水动画
        // var shape = node.findObject("PIPE");
        // var off = shape.strokeDashOffset - 2;
        // shape.strokeDashOffset = (off <= 0) ? 20 : off;
    }

    /**
     * 获取最后一个步骤（【待处理】或【结束】）
     * @param stepKeys
     * @param steps
     * @param isCompleted
     * @returns {*}
     */
    function findLastStep(stepKeys, steps, isCompleted, isEnd) {
        var lastStep;
        if (!isCompleted) {
             // 获取“待处理”步骤
             var lastKey = stepKeys[stepKeys.length - 1];
             var step = _displayer.findNodeForKey(lastKey);
             if(step.data.type === 1 || step.data.type === 2){

                return step
            }
            if(!isEnd){
                _displayer.startTransaction("vacate");
                _displayer.model.setDataProperty(step.data, "stroke", "#FF9900");
                _displayer.model.setDataProperty(step.data, "strokeWidth", 1);
                // _displayer.model.setDataProperty(step.data, "strokeDashArray", [10, 10]);
                _displayer.commitTransaction("vacate");
            }else{
                _displayer.startTransaction("vacate");
                _displayer.model.setDataProperty(step.data, "stroke", "#ED4014");
                _displayer.model.setDataProperty(step.data, "strokeWidth", 1);
                // _displayer.model.setDataProperty(step.data, "strokeDashArray", [10, 10]);
                _displayer.commitTransaction("vacate");
            }
            

            //【开始】-> 【已完成】（N个）->【待处理】
            lastStep = step;
        } else {
            // 用最后一根连线获取【结束】步骤
            var lastFinishedStep = steps[steps.length - 1];

            var it = lastFinishedStep.findLinksOutOf();
            var lastLink = it.first();
            var endStep = lastLink.toNode;

            //【开始】-> 【已完成】（N个）->【结束】
            lastStep = endStep;
        }

        return lastStep;
    }

    /**
     * 查找错误连线
     * @param steps
     * @returns {Array}
     */
    function findFinishedLinks(lastStep) {

        var arrLinks = [];
        lastStep.findLinksOutOf().map(item => {
            arrLinks.push(item)
        })

        return arrLinks;
    }

    /**
     * 高亮所有“已完成”步骤的连线
     * @param links
     */
    function showFinishedLinks(links) {

        if (!links) return;

        for (var i = 0; i < links.length; i++) {
            // 连线
            var link = links[i];
            _displayer.startTransaction("vacate");
            _displayer.model.setDataProperty(link.data, "stroke", (link.data.stroke === "#4fba4f" ? "#4fba4f" : "#ED4014"));
            _displayer.model.setDataProperty(link.data, "fill", (link.data.fill === "#4fba4f" ? "#4fba4f" : "#ED4014"));
            _displayer.model.setDataProperty(link.data, "zOrder", 999);
            _displayer.commitTransaction("vacate");

            // 置于最上层，防止被遮挡
            _displayer.startTransaction('modified zOrder');
            _displayer.model.setDataProperty(link.data, "zOrder", 1);
            _displayer.commitTransaction('modified zOrder');

            // 连线加上流水动画
            var shape = link.findObject("PIPE");
            shape.stroke = '#ED4014'
            var off = shape.strokeDashOffset - 2;
            shape.strokeDashOffset = (off <= 0) ? 20 : off;
        }
    }

    /**
     * 更改所有连线中间的文本背景色
     */
    function setLinkTextBg() {
        _displayer.links.each(function (link) {
            _displayer.startTransaction("vacate");
            if (link.data.text) {
                _displayer.model.setDataProperty(link.data, "pFill", window.go.GraphObject.make(go.Brush, "Radial", {
                    0: "rgb(240, 240, 240)",
                    0.3: "rgb(240, 240, 240)",
                    1: "rgba(240, 240, 240, 0)"
                }));
            }
            _displayer.commitTransaction("vacate");
        });
    }

    /** --------private method------------------end----------------------**/

    return this;
}

export default FlowDisplay
