Search code examples
javascriptcanvasvue.jshtml5-canvaskonvajs

How to generate Canvas layer with on click button


i have a question - how to draw canvas layer (for example just simple square) with event on click on button in Vue.js? I have stage and on that stage with position x:0, y:0 i want after click on button to generate that square and with drag and drop to position it on that stage? I'm using Konvajs for creating Canvas

Can somebody help me?

<template>

 <div id="main">
  <h1></h1>            
  <div id="obszarroboczy" style="width: 500px; height: 600px;">

 <v-stage ref="stage"
      :config="configKonva"

      @dragstart="handleDragstart"
      @dragend="handleDragend">
      <v-layer ref="layer">
        <v-star
          v-for="item in list"
          :key="item.id"
          :config="item"></v-star>
      </v-layer>
      <v-layer ref="dragLayer"></v-layer>
    </v-stage>     
  </div>
  <div class="col-md-6">
    <button v-on:click="handleClick" id="more_canvas">More</button>
  </div>  
</div>
</template>

<script>


import Vue from "vue";
import axios from "axios";
import draggable from "vuedraggable";
import swal from "sweetalert2";
import VueKonva from "vue-konva";
export default {
  name: "EnumCurrencyIndex",
  $mount: "#main",
  components: {
    draggable
  },

  data() {
    return {
      model: [],
      editable: true,
      isDragging: false,
      delayedDragging: false,
      type: "currency",
      editedElement: null,
      newElement: "",
      list: [],
      configKonva: {
        width: 400,
        height: 400
      }, 
       configCircle: {
            x: 100,
            y: 100,
            radius: 70,
            fill: 'red',
            stroke: 'black',
            strokeWidth: 4
       },
      vm:  {}
    };
  },
  beforeMount() {
    this.fetchData();
  },


  computed: {
    dragOptions() {
      return {
        animation: 0,
        group: "description",
        disabled: !this.editable,
        ghostClass: "ghost"
      };
    },
    listString() {
      return this.model;
    },
     dragCanvas()  {
      return this.model;
    }
  },
  watch: {
    $route: "fetchData",
    isDragging(newValue) {
      if (newValue) {
        this.delayedDragging = true;
        return;
      }
      this.$nextTick(() => {
        this.delayedDragging = false;
      });
    }
  },
  methods: {

     handleDragstart(starComponent) {
       var vm = this;
      const shape = starComponent.getStage();
      const dragLayer = vm.$refs.dragLayer.getStage();
      const stage = vm.$refs.stage.getStage();
      // moving to another layer will improve dragging performance
      shape.moveTo(dragLayer);
      stage.draw();
      starComponent.config.shadowOffsetX = 15;
      starComponent.config.shadowOffsetY = 15;
      starComponent.config.scaleX = starComponent.config.startScale * 1.2;
      starComponent.config.scaleY = starComponent.config.startScale * 1.2;
    },
    handleDragend(starComponent) {
      var vm = this;
      const shape = starComponent.getStage();
      const layer = vm.$refs.layer.getStage();
      const stage = vm.$refs.stage.getStage();
      shape.moveTo(layer);
      stage.draw();
      shape.to({
        duration: 0.5,
        easing: Konva.Easings.ElasticEaseOut,
        scaleX: starComponent.config.startScale,
        scaleY: starComponent.config.startScale,
        shadowOffsetX: 5,
        shadowOffsetY: 5

      });


    },
     handleClick(configCircle) {
       var vm = this;
        const shape = vm.$refs.layer.getStage();
      const layer = vm.$refs.layer.getStage();
      const stage = vm.$refs.stage.getStage();

        console.log(1);
layer.add(configCircle);
stage.add(layer);




      },
 haveIntersection(r1, r2) {
            return !(
                r2.x > r1.x + r1.width ||
                r2.x + r2.width < r1.x ||
                r2.y > r1.y + r1.height ||
                r2.y + r2.height < r1.y
            );
        },


    orderList() {
      this.model = this.model.sort((one, two) => {
        return one.position - two.position;
      });
    },
    onMove({ relatedContext, draggedContext }) {
      const relatedElement = relatedContext.element;
      const draggedElement = draggedContext.element;
      return (
        (!relatedElement || !relatedElement.fixed) && !draggedElement.fixed
      );
    },
    fetchData() {
      var vm = this;
      axios
        .get(`/api/${this.resource}?type=${this.type}`)
        .then(function(response) {
          Vue.set(vm.$data, "model", response.data.model);
        })
        .catch(function(error) {
          console.log(error);
        });
    }
  },
  mounted() {
     var box = document.getElementById("obszarroboczy");
    this.configKonva.width = box.offsetWidth;
    this.configKonva.height = box.offsetHeight;

    var vm = this;
    for (let n = 0; n < 30; n++) {
      const scale = Math.random();
      const stage = vm.$refs.stage.getStage();
      vm.list.push({
        x: Math.random() * stage.getWidth(),
        y: Math.random() * stage.getHeight(),
        rotation: Math.random() * 180,
        numPoints: 5,
        innerRadius: 30,
        outerRadius: 50,
        fill: "#89b717",
        opacity: 0.8,
        draggable: true,
        scaleX: scale,
        scaleY: scale,
        shadowColor: "black",
        shadowBlur: 10,
        shadowOffsetX: 5,
        shadowOffsetY: 5,
        shadowOpacity: 0.6,
        startScale: scale
      });

    };

  },

  directives: {
    "element-focus": function(el, binding) {
      if (binding.value) {
        el.focus();
      }
    }
  }
};
</script>
<style>
#obszarroboczy {
  width: 100px;
  height: 300px;
}
.normal {
  background-color: grey;
}
.table td {
  width: 100px;
  height: 100px;
  background: white;
  border: 2px dotted black;
  max-width: 100px;
  padding: 5px;
}
.drag {
  display: flex;
  flex-direction: row;
}

.list {
  flex-grow: 1;
  max-width: 47%;
  margin-right: 40px;
}

.name {
  width: 50%;
  display: inline-block;
  height: 50px;
  background: pink;
  border: 5px green solid;
  box-sizing: border-box;
  padding: 5px;
}
.name.large {
  width: 100%;
}

.dragArea {
  min-height: 100px;
}
.dragArea img {
  margin: 3px;
  cursor: pointer;
}
</style>

Solution

  • var mainCanvas = new Vue({
      el: '#main', // the element where the method wil lrender the canvas to
      data: {
        name: 'Vue.js'
      },
      methods: {
        handleClick: function (event) { // handleClick is the method name for the button
          var stage = new Konva.Stage({ // this line till the stage.add() line renders the draggable square
            container: 'obszarroboczy',
            width: 500,
            height: 500
          });
    
          var layer = new Konva.Layer();
    
          var rect = new Konva.Rect({
            x: 0,
            y: 0,
            width: 100,
            height: 100,
            fill: 'green',
            stroke: 'black',
            strokeWidth: 4,
            draggable: true
          });
    
          layer.add(rect);
    
          stage.add(layer);
        }
      }
    });
    

    I added comments to explain what certain important lines does but you can check out the official KonvaJS Docs in GitHub for a more detailed explanation on what each line above does.