vue.jsnuxt.jskonvajskonvavue-konva

Create Konvajs Shapes and Connections creating dynamically based on button click events


I would like to create Rectangle Shapes and Connections using the Vue-Konva/Konvajs within my application. I do not want to create load the Static values rather I would like to create the Shapes when the user clicks on the Add Node button and create Connectors when the user clicks on the Add Connector button and build the connections between Shapes.

I looked into a few things and was able to do it using the mouse events but was unable to convert it to button clicks.

Following is the current code I have: CodeSandbox

Can someone please guide me on how to create shapes and connectors on click of the button events? Any suggestion or guidance is much appreciated.

I am looking something like this: enter image description here


Solution

  • After trying a few things I was able to get it working. Posting here as it can be useful to someone in the future:

    <template>
      <div class="container-fluid">
        <div class="row">
          <div class="col-sm-6">
            <button class="btn btn-primary btn-sm" @click="addEvent()">
              Add Event
            </button>&nbsp;
            <button class="btn btn-success btn-sm" @click="submitNodes()">
              Submit
            </button>&nbsp;
          </div>
        </div>
        <div class="row root">
          <div class="col-sm-12 body">
            <v-stage
              ref="stage"
              class="stage"
              :config="stageSize"
              @mouseup="handleMouseUp"
              @mousemove="handleMouseMove"
              @mousedown="handleMouseDown"
            >
              <v-layer ref="layer">
                <v-rect
                  v-for="(rec, index) in nodeArray"
                  :key="index"
                  :config="{
                    x: Math.min(rec.startPointX, rec.startPointX + rec.width),
                    y: Math.min(rec.startPointY, rec.startPointY + rec.height),
                    width: Math.abs(rec.width),
                    height: Math.abs(rec.height),
                    fill: 'rgb(0,0,0,0)',
                    stroke: 'black',
                    strokeWidth: 3,
                  }"
                />
              </v-layer>
            </v-stage>
          </div>
        </div>
      </div>
    </template>
    
    <script>
    export default {
      data () {
        return {
          stageSize: {
            width: null,
            height: 900
          },
          lines: [],
          isDrawing: false,
          eventFlag: false,
          nodeCounter: 0,
          nodeArray: []
        }
      },
      mounted () {
        if (process.browser && window !== undefined) {
          this.stageSize.width = window.innerWidth
          // this.stageSize.height = window.innerHeight
        }
      },
      methods: {
        handleMouseDown (event) {
          if (this.eventFlag) {
            this.isDrawing = true
            const pos = this.$refs.stage.getNode().getPointerPosition()
            const nodeInfo = this.nodeArray[this.nodeArray.length - 1]
            nodeInfo.startPointX = pos.x
            nodeInfo.startPointY = pos.y
            console.log(JSON.stringify(nodeInfo, null, 4))
          }
        },
        handleMouseUp () {
          this.isDrawing = false
          this.eventFlag = false
        },
        setNodes (element) {
          this.nodeArray = element
        },
        handleMouseMove (event) {
          if (!this.isDrawing) {
            return
          }
          // console.log(event);
          const point = this.$refs.stage.getNode().getPointerPosition()
          // Handle  rectangle part
          const curRec = this.nodeArray[this.nodeArray.length - 1]
          curRec.width = point.x - curRec.startPointX
          curRec.height = point.y - curRec.startPointY
        },
        // Function to read the Nodes after add all the nodes
        submitNodes () {
          console.log('ALL NODE INFO')
          console.log(JSON.stringify(this.nodeArray, null, 4))
          this.handleDragstart()
        },
        addEvent () {
          this.eventFlag = true
          this.setNodes([
            ...this.nodeArray,
            {
              width: 0,
              height: 0,
              draggable: true,
              name: 'Event ' + this.nodeCounter
            }
          ])
          this.nodeCounter++
        }
      }
    }
    </script>
    
    <style scoped>
    .root {
      --bg-color: #fff;
      --line-color-1: #D5D8DC;
      --line-color-2: #a9a9a9;
    }
    
    .body {
      height: 100vh;
      margin: 0;
    }
    
    .stage {
      height: 100%;
      background-color: var(--bg-color);
      background-image: conic-gradient(at calc(100% - 2px) calc(100% - 2px),var(--line-color-1) 270deg, #0000 0),
        conic-gradient(at calc(100% - 1px) calc(100% - 1px),var(--line-color-2) 270deg, #0000 0);
      background-size: 100px 100px, 20px 20px;
    }
    </style>