Home > Web Front-end > JS Tutorial > Detailed explanation of the core technology of constructing flow charts in js JsPlumb (2)_javascript skills

Detailed explanation of the core technology of constructing flow charts in js JsPlumb (2)_javascript skills

WBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWB
Release: 2016-05-16 15:27:11
Original
2222 people have browsed it

Foreword: The previous article explains in detail the core technology of constructing flow charts in js JsPlumb introduces the effect of JsPlumb on drawing flow charts in the browser, as well as a simple JsPlumb code example . In this article, let’s take a look at the code descriptions of each effect.

1. Code examples for setting the style and color effects of connections
The approximate effect is as shown in the figure:

These effects look very simple, so how do we use code to achieve it. In the last chapter, we said that the connection style of JsPlumb is determined by certain attributes of the points. In this case, we can dynamically change the connection style by setting the point style. Let’s look at the code:

First let’s take a look at the connection type selection

1

2

3

4

5

6

7

8

<div id="btn_linetype" class="divMenuBtn btn-default btn">

  连线类型:

  <select id="sel_linetype" style="width:80px;height:20px">

    <option value="2">直线</option>

    <option value="1">折线</option>

    <option value="3">曲线</option>

  </select>

</div>

Copy after login

Register the change event of select when the page is initialized

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

//全局的空心圆端点样式设置

var hollowCircle = {

  DragOptions: { cursor: 'pointer', zIndex: 2000 },

  endpoint: ["Dot", { radius: 7 }], //端点的形状

  connectorStyle: connectorPaintStyle,//连接线的颜色,大小样式

  connectorHoverStyle: connectorHoverStyle,

  paintStyle: {

    strokeStyle: "#1e8151",

    fillStyle: "transparent",

    radius: 5,

    lineWidth: 2

  },    //端点的颜色样式

  //anchor: "AutoDefault",

  isSource: true,  //是否可以拖动(作为连线起点)

  connector: ["Straight", { stub: [0, 0], gap: 10, cornerRadius: 5, alwaysRespectStubs: true }], //连接线的样式种类有[Bezier],[Flowchart],[StateMachine ],[Straight ]

  isTarget: true,  //是否可以放置(连线终点)

  maxConnections: -1,  // 设置连接点最多可以连接几条线

  connectorOverlays: [["Arrow", { width: 10, length: 10, location: 1 }]]

};

 

//页面初始化完成之后

$(function () {

  //连线样式下拉框的change事件

  $("#sel_linetype").change(function () {

    var strlinetype = "";

    var strlinecolor = "";

    //设置新添加元素的节点的连线样式

    //直线的样式和样色

    if ($(this).val() == "1") {

      strlinetype = "Flowchart";

      strlinecolor = "red";

      hollowCircle.connector = ["Flowchart", { stub: [0, 0], gap: 10, cornerRadius: 5, alwaysRespectStubs: true }];

    }

    //折线的样式和颜色

    else if ($(this).val() == "2") {

      strlinetype = "Straight";

      strlinecolor = "green";

      hollowCircle.connector = ["Straight", { stub: [0, 0], gap: 10, cornerRadius: 5, alwaysRespectStubs: true }];

    }

    //曲线的样式和颜色

    else if ($(this).val() == "3") {

      strlinetype = "Bezier";

      strlinecolor = "orange";

      hollowCircle.connector = ["Bezier", { stub: [0, 0], gap: 10, cornerRadius: 5, alwaysRespectStubs: true }];

    }

    //设置已经存在的所有的连接点的连线样式

    var arrnode = $("#divCenter").find(".node");

    for (var i = 0; i < arrnode.length; i++) {

      var arrendpoints = jsPlumb.getEndpoints($(arrnode[i]).attr("id"));

      if (arrendpoints == undefined || arrendpoints == null) {

        return;

      }

      var oconnector = arrendpoints[0].connector;

      if (oconnector == null || oconnector == undefined) {

        return;

      }

      oconnector[0] = strlinetype;

      var oconnectstyle = arrendpoints[0].connectorStyle;

      if (oconnectstyle == null || oconnectstyle == undefined) {

        return;

      }

      oconnectstyle.strokeStyle = strlinecolor;

    }

  });

});

Copy after login

In fact, it only takes a few lines of code to set the connection style of the endpoints that already exist and will be dragged to the interface.
2. Select all, select all drag effect code examples
You can select elements and drag elements and connections in batches. The approximate effect is:

Look at the implementation code:
1. Registration can be selected during initialization

1

2

3

4

5

6

7

8

$(function () {

  var oRegionSelect = new RegionSelect({

    region: '#divCenter div.node',

    selectedClass: 'seled',

    parentId: "divCenter"

  });

  oRegionSelect.select();

});

Copy after login

2. Select relevant methods

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

var _selectedRegions = [];

//var selProp;

 

function RegionSelect(selRegionProp) {

  //selProp = selRegionProp;

  this.regions = [];

  this.selProp = selRegionProp;

  this.InitRegions(selRegionProp);

  this.selectedClass = selRegionProp["selectedClass"];

  this.selectedRegion = [];

  this.selectDiv = null;

  this.startX = null;

  this.startY = null;

  this.parentId = selRegionProp["parentId"];

}

 

RegionSelect.prototype.InitRegions = function () {

  var _self = this;

  _self.regions = [];

  var _regions = document.getElementsBySelector(_self.selProp["region"]);//$("#divCenter > .node");//

 

  var bSelect = true;

  if (_regions && _regions.length > 0) {

    for (var i = 0; i < _regions.length; i++) {

      _regions[i].onmousedown = function () {

        bSelect = false;

        var evt = window.event || arguments[0];

        if (!evt.shiftKey && !evt.ctrlKey) {

          if ($.inArray(this, _selectedRegions) === -1) {

            // 清空所有select样式

            _self.clearSelections(_regions);

            this.className += " " + _self.selectedClass;

            // 清空selected数组,并加入当前select中的元素

            _selectedRegions = [];

            _selectedRegions.push(this);

          }

        } else {

          if (this.className.indexOf(_self.selectedClass) == -1) {

            this.className += " " + _self.selectedClass;

            _selectedRegions.push(this);

          } else {

            this.className = this.className.replaceAll(_self.selectedClass, "");

            _selectedRegions.remove(this);

          }

        }

        clearEventBubble(evt);

      }

      this.regions.push(_regions[i]);

    }

  }

 

  if (bSelect) {

    // 清空所有select样式

    _self.clearSelections(_regions);

    // 清空selected数组,并加入当前select中的元素

    _selectedRegions = [];

  }

}

 

RegionSelect.prototype.select = function () {

  var _self = this;

  var sDivId = _self.parentId;

  var intMousePosition = [0, 0];

  var intOriginalPosition = [0, 0];

  var parentWidth = parseInt(document.getElementById(sDivId).parentElement.offsetWidth);

  var parentHeight = parseInt(document.getElementById(sDivId).parentElement.offsetHeight);

  addEvent("mousedown", function () {

    var evt = window.event || arguments[0];

    var buttonType = evt.buttons || evt.button;

    if (evt.target != undefined) {

      if (evt.target.id !== sDivId) return;

    }

    if (evt.srcElement != undefined) {

      if (evt.srcElement.id !== sDivId) return;

    }

    if (evt.buttons == undefined && buttonType == 0){

      _self.onBeforeSelect(evt, sDivId);

    }

    if (buttonType === 1) {

      _self.onBeforeSelect(evt, sDivId);

    }

    if (buttonType === 2) {

      intMousePosition = [evt.clientX, evt.clientY];

      var movX = parseInt(GetStyle(document.getElementById(sDivId), "left"));

      var movY = parseInt(GetStyle(document.getElementById(sDivId), "top"));

      intOriginalPosition = [movX, movY];

      document.getElementById(sDivId).style.cursor = "move";

    }

    clearEventBubble(evt);

  }, document);

 

  addEvent("mousemove", function () {

    var evt = window.event || arguments[0];

    //if (evt.target.id !== sDivId) return;

    var buttonType = evt.buttons || evt.button;

    if (evt.buttons == undefined && buttonType == 0) {

      _self.onSelect(evt, sDivId);

    }

    if (buttonType === 1) {

      _self.onSelect(evt, sDivId);

    }

    if (buttonType === 2) {

      var newX = intOriginalPosition[0] + evt.clientX - intMousePosition[0];

      var newY = intOriginalPosition[1] + evt.clientY - intMousePosition[1];

      if (newX >= 0) {

        newX = 0;

      }

      if (newY >= 0) {

        newY = 0;

      }

      $("#" + sDivId).css("left", newX + "px");

      $("#" + sDivId).css("top", newY + "px");

      $("#" + sDivId).css("width", (parentWidth-newX) + "px");

      $("#" + sDivId).css("height", (parentHeight-newY) + "px");

 

    }

    clearEventBubble(evt);

  }, document);

 

  addEvent("mouseup", function () {

    var evt = window.event || arguments[0];

    var buttonType = evt.buttons || evt.button;

    if (evt.buttons == undefined && buttonType == 0) {

    }

    if (buttonType === 1) {

    }

      document.getElementById(sDivId).style.cursor = "default";

      _self.onEnd();

  }, document);

}

 

RegionSelect.prototype.onBeforeSelect = function (evt, sDivId) {

  // 创建模拟 选择框

  var _self = this;

  _self.InitRegions(_self.selProp);

  if (!document.getElementById("selContainer")) {

    this.selectDiv = document.createElement("div");

    this.selectDiv.style.cssText = "position:absolute;width:0px;height:0px;font-size:0px;margin:0px;padding:0px;border:1px dashed #0099FF;background-color:#C3D5ED;z-index:1000;filter:alpha(opacity:60);opacity:0.6;display:none;";

    this.selectDiv.id = "selContainer";

    document.getElementById(sDivId).appendChild(this.selectDiv);

  } else {

    this.selectDiv = document.getElementById("selContainer");

  }

 

  this.startX = posXY(evt, sDivId).x;

  this.startY = posXY(evt, sDivId).y;

  this.isSelect = true;

 

}

 

RegionSelect.prototype.onSelect = function (evt, sDivId) {

  var self = this;

  if (self.isSelect) {

    if (self.selectDiv.style.display == "none") self.selectDiv.style.display = "";

 

    var posX = posXY(evt, sDivId).x;

    var poxY = posXY(evt, sDivId).y;

    self.selectDiv.style.left = Math.min(posX, this.startX) + "px";

    self.selectDiv.style.top = Math.min(poxY, this.startY) + "px";

    self.selectDiv.style.width = Math.abs(posX - this.startX) + "px";

    self.selectDiv.style.height = Math.abs(poxY - this.startY) + "px";

 

    var regionList = self.regions;

    for (var i = 0; i < regionList.length; i++) {

      if (self.selectDiv.parentNode.id !== regionList[i].parentNode.id) continue;

      var r = regionList[i], sr = self.innerRegion(self.selectDiv, r);

      if (sr && r.className.indexOf(self.selectedClass) == -1) {

        r.className = r.className + " " + self.selectedClass;

        _selectedRegions.push(r);

      } else if (!sr && r.className.indexOf(self.selectedClass) != -1) {

        r.className = r.className.replaceAll(self.selectedClass, "");

        _selectedRegions.remove(r);

      }

 

    }

  }

}

 

RegionSelect.prototype.onEnd = function () {

  var self = this;

  if (self.selectDiv) {

    self.selectDiv.style.display = "none";

  }

  this.isSelect = false;

  //_selectedRegions = this.selectedRegion;

}

 

// 判断一个区域是否在选择区内

RegionSelect.prototype.innerRegion = function (selDiv, region) {

  var s_top = parseInt(selDiv.style.top);

  var s_left = parseInt(selDiv.style.left);

  var s_right = s_left + parseInt(selDiv.offsetWidth);

  var s_bottom = s_top + parseInt(selDiv.offsetHeight);

 

  var r_top = parseInt(region.offsetTop);

  var r_left = parseInt(region.offsetLeft);

  var r_right = r_left + parseInt(region.offsetWidth);

  var r_bottom = r_top + parseInt(region.offsetHeight);

 

  var t = Math.max(s_top, r_top);

  var r = Math.min(s_right, r_right);

  var b = Math.min(s_bottom, r_bottom);

  var l = Math.max(s_left, r_left);

 

  if (b > t + 5 && r > l + 5) {

    return region;

  } else {

    return null;

  }

 

}

 

RegionSelect.prototype.clearSelections = function (regions) {

  for (var i = 0; i < regions.length; i++) {

    regions[i].className = regions[i].className.replaceAll(this.selectedClass, "");

  }

}

 

function getSelectedRegions() {

  return _selectedRegions;

}

 

/*-------------------------------------- 区域选择方法结束 --------------------------------------------*/

 

function showSelDiv() {

  var selInfo = "";

  var arr = getSelectedRegions();

  for (var i = 0; i < arr.length; i++) {

    selInfo += arr[i].innerHTML + "\n";

  }

 

  alert("共选择 " + arr.length + " 个文件,分别是:\n" + selInfo);

 

}

 

function MoveSelectDiv(event, ui,id) {

  var arr = getSelectedRegions();

  var iMoveLeft = ui.position.left - ui.originalPosition.left;

  var iMoveTop = ui.position.top - ui.originalPosition.top;

 

  for (var i = 0; i < arr.length; i++) {

    //if (arr[i].id === id) continue;

 

    if (arr[i].parentNode.id !== document.getElementById(id).parentNode.id) continue;

    var iLeft = parseInt($(arr[i]).attr("bLeft"));

    var iTop = parseInt($(arr[i]).attr("bTop"));

    $(arr[i]).css("left", (iLeft + iMoveLeft) + "px");

    $(arr[i]).css("top", (iTop + iMoveTop) + "px");

  }

}

 

function startMove() {

  var arr = getSelectedRegions();

  for (var i = 0; i < arr.length; i++) {

    $(arr[i]).attr("bLeft", $(arr[i]).position().left);

    $(arr[i]).attr("bTop", $(arr[i]).position().top);

  }

}

Copy after login

3. Alignment and rotation code examples

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

//左对齐

function SelectAlignLeft() {

  var arr = getSelectedRegions();

  var iLeft = 0;

  var id = "";

 

  for (var i = 0; i < arr.length; i++) {

    if (id === "") id = arr[i].parentNode.id;

    if (id !== arr[i].parentNode.id) continue;

    if ($(arr[i]).position().left<iLeft||iLeft===0) {

      iLeft = $(arr[i]).position().left;

    }

  }

 

  for (var j = 0; j < arr.length; j++) {

    if (id !== arr[j].parentNode.id) continue;

    $(arr[j]).css("left", iLeft + "px");

  }

 

  jsPlumb.repaintEverything();

}

 

//居中对齐

function SelectAlignCenter() {

  var arr = getSelectedRegions();

  var iLeft = 0;

  var id = "";

 

  for (var i = 0; i < arr.length; i++) {

    if (id === "") id = arr[i].parentNode.id;

    if (id !== arr[i].parentNode.id) continue;

    if ($(arr[i]).position().left < iLeft || iLeft === 0) {

      iLeft = $(arr[i]).position().left + parseInt(GetStyle(arr[i],"width")) / 2;

    }

  }

 

  for (var j = 0; j < arr.length; j++) {

    if (id !== arr[j].parentNode.id) continue;

    $(arr[j]).css("left", (iLeft - parseInt(GetStyle(arr[j],"width")) / 2) + "px");

  }

 

  jsPlumb.repaintEverything();

}

//右对齐

function SelectAlignRight() {

  var arr = getSelectedRegions();

  var iLeft = 0;

  var id = "";

 

  for (var i = 0; i < arr.length; i++) {

    if (id === "") id = arr[i].parentNode.id;

    if (id !== arr[i].parentNode.id) continue;

    if ($(arr[i]).position().left + parseInt(GetStyle(arr[i], "width")) > iLeft || iLeft === 0) {

      iLeft = $(arr[i]).position().left + parseInt(GetStyle(arr[i], "width"));

    }

  }

 

  for (var j = 0; j < arr.length; j++) {

    if (id !== arr[j].parentNode.id) continue;

    $(arr[j]).css("left", (iLeft - parseInt(GetStyle(arr[j], "width"))) + "px");

  }

 

  jsPlumb.repaintEverything();

}

 

//上对齐

function SelectAlignTop() {

  var arr = getSelectedRegions();

  var iTop = 0;

  var id = "";

 

  for (var i = 0; i < arr.length; i++) {

    if (id === "") id = arr[i].parentNode.id;

    if (id !== arr[i].parentNode.id) continue;

    if ($(arr[i]).position().top < iTop || iTop === 0) {

      iTop = $(arr[i]).position().top;

    }

  }

 

  for (var j = 0; j < arr.length; j++) {

    if (id !== arr[j].parentNode.id) continue;

    $(arr[j]).css("top", iTop + "px");

  }

 

  jsPlumb.repaintEverything();

}

 

//垂直居中

function SelectAlignMiddle() {

  var arr = getSelectedRegions();

  var iTop = 0;

  var id = "";

 

  for (var i = 0; i < arr.length; i++) {

    if (id === "") id = arr[i].parentNode.id;

    if (id !== arr[i].parentNode.id) continue;

    if ($(arr[i]).position().top + parseInt(GetStyle(arr[i], "height")) / 2 < iTop || iTop === 0) {

      iTop = $(arr[i]).position().top + parseInt(GetStyle(arr[i], "height")) / 2;

    }

  }

 

  for (var j = 0; j < arr.length; j++) {

    if (id !== arr[j].parentNode.id) continue;

    $(arr[j]).css("top", (iTop - parseInt(GetStyle(arr[j], "height")) / 2) + "px");

  }

 

  jsPlumb.repaintEverything();

}

 

//下对齐

function SelectAlignBottom() {

  var arr = getSelectedRegions();

  var iTop = 0;

  var id = "";

 

  for (var i = 0; i < arr.length; i++) {

    if (id === "") id = arr[i].parentNode.id;

    if (id !== arr[i].parentNode.id) continue;

    if ($(arr[i]).position().top + parseInt(GetStyle(arr[i], "height")) > iTop || iTop === 0) {

      iTop = $(arr[i]).position().top + parseInt(GetStyle(arr[i], "height"));

    }

  }

 

  for (var j = 0; j < arr.length; j++) {

    if (id !== arr[j].parentNode.id) continue;

    $(arr[j]).css("top", (iTop - parseInt(GetStyle(arr[j], "height"))) + "px");

  }

 

  jsPlumb.repaintEverything();

}

 

//上下靠拢

function SelectUpColse() {

  var arr = getSelectedRegions();

  var iTop = 0;

  var id = "";

  for (var i = 0; i < arr.length; i++) {

    if (id === "") id = arr[i].parentNode.id;

    if (id !== arr[i].parentNode.id) continue;

    if (iTop === 0) iTop = $(arr[i]).position().top;

    $(arr[i]).css("top", iTop + "px");

    iTop += parseInt(GetStyle(arr[i], "height"));

  }

 

  jsPlumb.repaintEverything();

}

 

//左右靠拢

function SelectLeftColse() {

  var arr = getSelectedRegions();

  var iLeft = 0;

  var id = "";

  for (var i = 0; i < arr.length; i++) {

    if (id === "") id = arr[i].parentNode.id;

    if (id !== arr[i].parentNode.id) continue;

    if (iLeft === 0) iLeft = $(arr[i]).position().left;

    $(arr[i]).css("left", iLeft + "px");

    iLeft += parseInt(GetStyle(arr[i], "width"));

  }

 

  jsPlumb.repaintEverything();

 

}

 

 

//同高

function SelectSameHeight() {

  var arr = getSelectedRegions();

  var iHeigth = 0;

  var id = "";

  for (var i = 0; i < arr.length; i++) {

    if (id === "") id = arr[i].parentNode.id;

    if (id !== arr[i].parentNode.id) continue;

    if (iHeigth === 0) iHeigth = parseInt(GetStyle(arr[i], "height"));

    $(arr[i]).css("height", iHeigth+"px");

  }

 

  jsPlumb.repaintEverything();

}

 

 

//同宽

function SelectSameWidth() {

  var arr = getSelectedRegions();

  var iWidth = 0;

  var id = "";

  for (var i = 0; i < arr.length; i++) {

    if (id === "") id = arr[i].parentNode.id;

    if (id !== arr[i].parentNode.id) continue;

    if (iWidth === 0) iWidth = parseInt(GetStyle(arr[i], "width"));

    $(arr[i]).css("width", iWidth + "px");

  }

 

  jsPlumb.repaintEverything();

 

}

 

 

//旋转

function SelectClockwise(index) {

  var arr = getSelectedRegions();

  //var iWidth = 0;

  //var id = "";

  for (var i = 0; i < arr.length; i++) {

    //if (id === "") id = arr[i].parentNode.id;

    //if (id !== arr[i].parentNode.id) continue;

    var sIndex= arr[i].style.transform.replace("rotate(", "").replace("deg)", "");

    var iNum = 0;

    if (sIndex) iNum = parseInt(sIndex);

    $(arr[i]).css("transform", "rotate(" + (iNum + index)%360 + "deg)");

 

    var points = jsPlumb.getEndpoints(arr[i]);

  }

 

  jsPlumb.repaintEverything();

 

}

//删除选中

function DeleteSelect() {

  var arr = getSelectedRegions();

  for (var i = 0; i < arr.length; i++) {

    jsPlumb.remove(arr[i],true);

    //var points = jsPlumb.getEndpoints(arr[i]);

    //for (var j = 0; j < points.length; j++) {

    //  jsPlumb.deleteEndpoint(points[j]);

    //}

    //arr[i].parentNode.removeChild(arr[i]);

    }

 

  jsPlumb.repaintEverything();

 

}

 

function GetStyle(obj, attr) {

  if (obj.currentStyle) {

    return obj.currentStyle[attr]; //只适用于IE

  }

  else {

    return getComputedStyle(obj, false)[attr];  //只适用于FF,Chrome,Safa

  }

  return obj.style[attr]; //本人测试在IE和FF下没有用,chrome有用

}

Copy after login

The code may be a bit messy and needs to be sorted out. In the previous chapter, a blogger asked me for the source code. This time I have released a preliminary version. I hope it can help everyone better learn the core technology of flow charts, JsPlumb.

Related labels:
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template