0

So, I've been working with vue-konva and I have something like this:

<v-container>
    <v-stage ref="stage">
        <v-layer ref="baseImage">
            <v-image>
        </v-layer>
        <v-layer ref="annotationLayer">
            <v-rect ref="eventBox">
            <v-rect ref="rubberBox">
            <v-rect ref="annotationRect">
        </v-layer>
    </v-stage>
<v-container>

Currently there are some issues if I want to draw new boxes, when there are other annotationRects already on the image. Because they are technically above the eventBox and rubberbox, they are "blocking" these two layers when the cursor is above an existing annotationRect.

But, I don't want to just constantly have eventBox and rubberBox be on top of annotationRect because I need to be able to interact with annotationRect to move them, resize them ,etc.

Is there a way for me to reorder eventBox, rubberBox, and annotationRect, i.e. changing the order to (bottom to top) annotationRect-eventBox-rubberBox from the original eventBox-rubberBox-annotationRect and back, on the fly, for example when the vue component receives an event from another component?

GAW
  • 85
  • 1
  • 5
  • You can use the Konva z-index property for this. See https://konvajs.org/docs/groups_and_layers/zIndex.html. There are also shape.moveUp(), shape.moveDown, shape.moveToTop, shape.moveToBottom functions which do what the name says. So animationRect.moveToTop() would put that shape 'above' the others. – Vanquished Wombat Apr 22 '20 at 08:56

1 Answers1

1

You need to define your eventBox, rubberBox, and annotationRect inside order array in the state of your app. Then you can use v-for directive to render items from the array:

<template>
  <div>
    <v-stage ref="stage" :config="stageSize" @click="changeOrder">
      <v-layer>
        <v-text :config="{text: 'Click me to change order', fontSize: 15}"/>
        <v-rect v-for="item in items" v-bind:key="item.id" :config="item"/>
      </v-layer>
      <v-layer ref="dragLayer"></v-layer>
    </v-stage>
  </div>
</template>

<script>
const width = window.innerWidth;
const height = window.innerHeight;
export default {
  data() {
    return {
      stageSize: {
        width: width,
        height: height
      },
      items: [
        { id: 1, x: 10, y: 50, width: 100, height: 100, fill: "red" },
        { id: 2, x: 50, y: 70, width: 100, height: 100, fill: "blue" }
      ]
    };
  },
  methods: {
    changeOrder() {
      const first = this.items[0];
      // remove first item:
      this.items.splice(0, 1);
      // add it to the top:
      this.items.push(first);
    }
  }
};
</script>

DEmo: https://codesandbox.io/s/vue-konva-list-render-l70vs?file=/src/App.vue

lavrton
  • 18,973
  • 4
  • 30
  • 63
  • Ah, thanks for the example. I think I can understand it a bit better now. One follow up question, is this doable when I not only have a bunch of Rects in the Layer but also other shapes like Lines and Circles that I want to reorder at once? – GAW Apr 24 '20 at 08:56
  • 1
    You can do many shapes. You just need to save some kind of "type" for each item and choose the required component depending on that type. – lavrton Apr 24 '20 at 15:28
  • Sorry to ask again, so in this case do I v-for in v-layer level or how exactly? For example if i want to render (bottom to top) rect-rect-rect-lines-circles and then change to rect-lines-circles-rect-rect, etc. Just so it's clear once and for all, a new demo based on this case would be very appreciated. – GAW Apr 25 '20 at 16:35
  • 1
    you may need to create your custom component that receives an item. Inside it, you are checking a type, and render required shape (with v-if probably) – lavrton Apr 27 '20 at 14:14