gojs实现可拖动编辑任务工作看板效果代码
代码语言:html
所属分类:图表
代码描述:gojs实现可拖动编辑任务工作看板效果代码
下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> </head> <body> <script src="//repo.bfw.wiki/bfwrepo/js/go.js"></script> <div id="allSampleContent" class="p-4 w-full"> <link href="https://fonts.googleapis.com/css?family=Lato:300,400,700" rel="stylesheet" type="text/css"> <script id="code"> // define a custom grid layout that makes sure the length of each lane is the same // and that each lane is broad enough to hold its subgraph class PoolLayout extends go.GridLayout { constructor() { super(); this.MINLENGTH = 200; // this controls the minimum length of any swimlane this.MINBREADTH = 100; // this controls the minimum breadth of any non-collapsed swimlane this.cellSize = new go.Size(1, 1); this.wrappingColumn = Infinity; this.wrappingWidth = Infinity; this.spacing = new go.Size(0, 0); this.alignment = go.GridLayout.Position; } doLayout(coll) { const diagram = this.diagram; if (diagram === null) return; diagram.startTransaction("PoolLayout"); // make sure all of the Group Shapes are big enough const minlen = this.computeMinPoolLength(); diagram.findTopLevelGroups().each(lane => { if (!(lane instanceof go.Group)) return; const shape = lane.selectionObject; if (shape !== null) { // change the desiredSize to be big enough in both directions const sz = this.computeLaneSize(lane); shape.width = (!isNaN(shape.width)) ? Math.max(shape.width, sz.width) : sz.width; // if you want the height of all of the lanes to shrink as the maximum needed height decreases: shape.height = minlen; // if you want the height of all of the lanes to remain at the maximum height ever needed: //shape.height = (isNaN(shape.height) ? minlen : Math.max(shape.height, minlen)); const cell = lane.resizeCellSize; if (!isNaN(shape.width) && !isNaN(cell.width) && cell.width > 0) shape.width = Math.ceil(shape.width / cell.width) * cell.width; if (!isNaN(shape.height) && !isNaN(cell.height) && cell.height > 0) shape.height = Math.ceil(shape.height / cell.height) * cell.height; } }); // now do all of the usual stuff, according to whatever properties have been set on this GridLayout super.doLayout(coll); diagram.commitTransaction("PoolLayout"); }; // compute the minimum length of the whole diagram needed to hold all of the Lane Groups computeMinPoolLength() { let len = this.MINLENGTH; myDiagram.findTopLevelGroups().each(lane => { const holder = lane.placeholder; if (holder !== null) { const sz = holder.actualBounds; len = Math.max(len, sz.height); } }); return len; } // compute the minimum size for a particular Lane Group computeLaneSize(lane) { // assert(lane instanceof go.Group); const sz = new go.Size(lane.isSubGraphExpanded ? this.MINBREADTH : 1, this.MINLENGTH); if (lane.isSubGraphExpanded) { const holder = lane.placeholder; if (holder !== null) { const hsz = holder.actualBounds; sz.width = Math.max(sz.width, hsz.width); } } // minimum breadth needs to be big enough to hold the header const hdr = lane.findObject("HEADER"); if (hdr !== null) sz.width = Math.max(sz.width, hdr.actualBounds.width); return sz; } } // end PoolLayout class function init() { // Since 2.2 you can also author concise templates with method chaining instead of GraphObject.make // For details, see https://gojs.net/latest/intro/buildingObjects.html const $ = go.GraphObject.make; myDiagram = $(go.Diagram, "myDiagramDiv", { // make sure the top-left corner of the viewport is occupied contentAlignment: go.Spot.TopLeft, // use a simple layout to stack the top-level Groups next to each other layout: $(PoolLayout), // disallow nodes to be dragged to the diagram's background mouseDrop: e => { e.diagram.currentTool.doCancel(); }, // a clipboard copied node is pasted into the original node's group (i.e. lane). "commandHandler.copiesGroupKey": true, // automatically re-layout the swim lanes after dragging the selection "SelectionMoved": relayoutDiagram, // this DiagramEvent listener is "SelectionCopied": relayoutDiagram, // defined above "undoManager.isEnabled": true, // allow TextEditingTool to start without selecting first "textEditingTool.starting": go.TextEditingTool.SingleClick }); // Customize the dragging tool: // When dragging a node set its opacity to 0.6 and move it to be in front of other nodes myDiagram.toolManager.draggingTool.doActivate = function() { go.DraggingTool.prototype.doActivate.call(this); this.currentPart.opacity = 0.6; this.currentPart.layerName = "Foreground"; } myDiagram.toolManager.draggingTool.doDeactivate = function() { this.currentPart.opacity = 1; this.currentPart.layerName = ""; go.DraggingTool.prototype.doDeactivate.call(this); } // this is called after nodes have been moved function relayoutDiagram() { myDiagram.selection.each(n => n.invalidateLayout()); myDiagram.layoutDiagram(); } // There are only three note colors by default, blue, red, and yellow but you could add more here: const noteColors = ['#009CCC', '#CC293D', '#FFD700']; function getNoteColor(num) { return noteColors[Math.min(num, noteColors.length - 1)]; } myDiagram.nodeTemplate = $(go.Node, "Horizontal", new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify), $(go.Shape, "Rectangle", { fill: '#009CCC', strokeWidth: 1, stroke: '#009CCC', width: 6, stretch: go.GraphObject.Vertical, alignment: go.Spot.Left, // if a user clicks the colored portion of a node, cycle through colors click: (e, obj) => { myDiagram.startTransaction("Update node color"); let newColor = parseInt(obj.part.data.color) + 1; if (newColor > noteColors.length - 1) newColor = 0; myDiagram.model.setDataProperty(obj.part.data, "color", newColor); myDiagram.commitTransaction("Update node color"); } }, new go.Binding("fill", "color", getNoteColor), new go.Binding("stroke", "color", getNoteColor) ), $(go.Panel, "Auto", $(go.Shape, "Rectangle", { fill: "white", stroke: '#CCCCCC' }), $(go.Panel, "Table", { width: 130, minSize: new go.Size(NaN, 50) }, $(go.TextBlock, { name: 'TEXT', margin: 6, font: '11px Lato, sans-serif', editable: true, stroke: "#000", maxSize: new go.Size(130, NaN), alignment: go.Spot.TopLeft }, new go.Binding("text", "text").makeTwoWay()) ) ) ); // unmovable node that acts as a button myDiagram.nodeTemplateMap.add('newbutton', $(go.Node, "Horizontal", new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify), { selectable: false, click: (e, node) => { myDiagram.startTransaction('add node'); const newdata = { group: "Problems", loc: "0 50", text: "New item " + node.containingGroup.memberParts.count, color: 0 }; myDiagram.model.addNodeData(newdata); myDiagram.commitTransaction('add node'); const newnode = myDiagram.findNodeForData(newdata); myDiagram.select(newnode); myDiagram.commandHandler.editTextBlock(); }, background: 'white' }, $(go.Panel, "Auto", $(go.Shape, "Rectangle", { strokeWidth: 0, stroke: null, fill: '#6FB583' }), $(go.Shape, "PlusLine", { margin: 6, strokeWidth: 2, width: 12, height: 12, stroke: 'white', background: '#6FB583' }) ), $(go.TextBlock, "New item", { font: '10px Lato, sans-serif', margin: 6, }) ) ); // While dragging, highlight the dragged-over group function highlightGroup(grp, show) { if (show) { const part = myDiagram.toolManager.draggingTool.currentPart; if (part.containingGroup !== grp) { grp.isHighlighted = true; return; } } grp.isHighlighted = false; } myDiagram.groupTemplate = $(go.Group, "Vertical", { selectable: false, selectionObjectName: "SHAPE", // even though its not selectable, this is used in the layout layerName: "Background", // all lanes are always behind all nodes and links layout: $(go.GridLayout, // automatically lay out the lane's subgraph { wrappingColumn: 1, cellSize: new go.Size(1, 1), spacing: new go.Size(5, 5), alignment: go.GridLayout.Position, comparer: (a, b) => { // can re-order tasks within a lane const ay = a.location.y; const by = b.location.y; if (isNaN(ay) || isNaN(by)) return 0; if (ay < by) return -1; if (ay > by) return 1; return 0; } }), click: (e, grp) => { // allow simple click on group to clear selection if (!e.shift && !e.control && !e.meta) e.diagram.clearSelection(); }, computesBoundsAfterDrag: true, // needed to prevent recomputing Group.placeholder bounds too soon handlesDragDropForMembers: true, // don't need to define handlers on member Nodes and Links mouseDragEnter: (e, grp, prev) => highlightGroup(grp, true), mouseDragLeave: (e, grp, next) => highlightGroup(grp, false), mouseDrop: (e, grp) => { // dropping a copy of some Nodes and Links onto this Group adds them to this .........完整代码请登录后点击上方下载按钮下载查看
网友评论0