Resize text on vue konvajs

654 views Asked by At

I am trying to resize the text element but when I try to make it bigger I always changes the scale.

I configured the transformer option like the konvajs vue documentation and works well, then i configured like the js example but when you are resizing the text element the text always change the scale and the size of the element sometimes does not change to the size you have selected but to a much larger size.

I have based on the example in js (https://konvajs.org/docs/select_and_transform/Resize_Text.html#page-title) and tried to pass it to vue.

I imported the library on main.js

import VueKonva from "vue-konva";

Vue.use(VueKonva);

app.js template

<v-stage ref="stage" :config="config" @mousedown="handleStageMouseDown" @touchstart="handleStageMouseDown">
  <v-layer ref="layer">
    <template v-for="item in list">
      <v-text :key="item.id" :ref="item.name" :config="item" @transformend="handleTransformEnd" />
    </template>

    <v-transformer ref="transformer" :config="{ enabledAnchors: ['middle-left', 'middle-right'], boundBoxFunc: (oldBox, newBox) => {
          if (newBox.width < this.MIN_WIDTH) {
            return oldBox;
          }

          return newBox;
        },
      }"
    />
  </v-layer>
</v-stage>

app.js script

<script>
export default {
  name: "App",
  data() {
    return {
      MIN_WIDTH: 20,
      config: {
        width: window.innerWidth,
        height: window.innerHeight,
      },
      selectedShapeName: "",
      list: [
        {
          x: 50,
          y: 60,
          fontSize: 20,
          text: "Hello from the Konva framework. Try to resize me.",
          draggable: true,
          width: 200,
          scaleX: 1,
          name: "textResize1",
          height: "auto",
        },
      ],
    };
  },
  methods: {
    handleTransformEnd(e) {
      const item = this.list.find((i) => i.name === this.selectedShapeName);

      item.width = Math.max(
        e.target.width() * e.target.scaleX(),
        this.MIN_WIDTH
      );
      item.scaleX = 1;
      item.scaleY = 1;
    },
    handleStageMouseDown(e) {
      // clicked on stage - clear selection
      if (e.target === e.target.getStage()) {
        this.selectedShapeName = "";
        this.updateTransformer();
        return;
      }

      // clicked on transformer - do nothing
      const clickedOnTransformer =
        e.target.getParent().className === "Transformer";
      if (clickedOnTransformer) {
        return;
      }

      // find clicked rect by its name
      const name = e.target.name();
      const item = this.list.find((i) => i.name === name);
      if (item) {
        this.selectedShapeName = name;
      } else {
        this.selectedShapeName = "";
      }
      this.updateTransformer();
    },
    updateTransformer() {
      // here we need to manually attach or detach Transformer node
      const transformerNode = this.$refs.transformer.getNode();
      const stage = transformerNode.getStage();
      const { selectedShapeName } = this;

      const selectedNode = stage.findOne("." + selectedShapeName);
      // do nothing if selected node is already attached
      if (selectedNode === transformerNode.node()) {
        return;
      }

      if (selectedNode) {
        // attach to another node
        transformerNode.nodes([selectedNode]);
      } else {
        // remove transformer
        transformerNode.nodes([]);
      }
    },
  },
};
</script>

Example with this code https://codesandbox.io/s/transform-07mwo

Edit: Updated with the code

1

There are 1 answers

0
IvanG11 On

I make it work with these changes

In the v-text tag we need to change the transformend event to transform event to update the text visually without changing the scale.

Old v-text tag

<v-text 
    :key="item.id"  
    :ref="item.name"    
    :config="item"  
    @transformend="handleTransformEnd"  
/>

Updated v-text tag

<v-text 
    :key="item.id"  
    :ref="item.name"    
    :config="item"  
    @transform="handleTransformEnd" 
/>

In the function handleTransformEnd we have to update the width of the item in the list and at the same time we have to update the selected shape and update the X and Y scaling so that it is always at 1 so that it is not rescaled.

Old handleTransformEnd

handleTransformEnd(e) { 
  const item = this.list.find((i) => i.name === this.selectedShapeName);    
  item.width = Math.max(    
    e.target.width() * e.target.scaleX(),   
    this.MIN_WIDTH  
  );    
  item.scaleX = 1;  
  item.scaleY = 1;  
},

Updated handleTransformEnd

handleTransformEnd() {
  const selectedNode = this.$refs.transformer
    .getStage()
    .getStage()
    .findOne("." + this.selectedShapeName);

  const item = this.list.find(
    (item) => item.name === this.selectedShapeName
  );
  item.width = item.width * selectedNode.getScaleX();

  selectedNode.setScaleX(1);
  selectedNode.setScaleY(1);
},