konvajs

How to visually adjust border radius for KonvaJS Rect during transformation?


I want to adjust visually the border radius for the rect, so it stays "the same" during transformation. What happens is the border-radius get's stretched during transformation, and it visually does not keep the border looking the way it basically should.

Reproduce from it:

<!DOCTYPE html>
<html>
<head>
  <!-- USE DEVELOPMENT VERSION -->
  <script src="https://unpkg.com/konva@9.3.16/konva.min.js"></script>
  <meta charset="utf-8" />
  <title>Konva Transform Limits Demo</title>
  <style>
    body {
      margin: 0;
      padding: 0;
      overflow: hidden;
      background-color: #f0f0f0;
    }
  </style>
</head>

<body>
<div id="container"></div>
<script>
  var width = window.innerWidth;
  var height = window.innerHeight;

  var stage = new Konva.Stage({
    container: 'container',
    width: width,
    height: height,
  });

  var layer = new Konva.Layer();
  stage.add(layer);

  var rect = new Konva.Rect({
    x: 160,
    y: 60,
    width: 100,
    height: 90,
    fill: 'red',
    name: 'rect',
    stroke: 'black',
    cornerRadius: 8,
    strokeScaleEnabled: false,
    draggable: true,
  });
  layer.add(rect);

  var MAX_WIDTH = 600;
  // create new transformer
  var tr = new Konva.Transformer({
    boundBoxFunc: function (oldBoundBox, newBoundBox) {
      // "boundBox" is an object with
      // x, y, width, height and rotation properties
      // transformer tool will try to fit nodes into that box

      // the logic is simple, if new width is too big
      // we will return previous state
      if (Math.abs(newBoundBox.width) > MAX_WIDTH) {
        return oldBoundBox;
      }

      return newBoundBox;
    },
  });
  layer.add(tr);
  tr.nodes([rect]);
</script>
</body>
</html>

This looks weird when transforming: enter image description here

I've tried to connect to the transform event:

rect.on("transform", () => {
const scaledRadius = originalCornerRadius / Math.max(rect.scaleX(), rect.scaleY());
rect.cornerRadius(scaledRadius);
 });

And adjust the radius but this doesnt seem to give me satisfied results.


Solution

  • I recommend resetting scaleX and scaleY and using only the width/height attributes for transformation.

    var width = window.innerWidth;
      var height = window.innerHeight;
    
      var stage = new Konva.Stage({
        container: 'container',
        width: width,
        height: height,
      });
    
      var layer = new Konva.Layer();
      stage.add(layer);
    
      var rect = new Konva.Rect({
        x: 160,
        y: 60,
        width: 100,
        height: 90,
        fill: 'red',
        name: 'rect',
        stroke: 'black',
        cornerRadius: 20,
        strokeScaleEnabled: false,
        draggable: true,
      });
      layer.add(rect);
    
      var MAX_WIDTH = 600;
    
      // create new transformer
      var tr = new Konva.Transformer({
        ignoreStroke: true,
        padding: 2,
        boundBoxFunc: function (oldBoundBox, newBoundBox) {
          if (Math.abs(newBoundBox.width) > MAX_WIDTH) {
            return oldBoundBox;
          }
          return newBoundBox;
        },
      });
      layer.add(tr);
      tr.nodes([rect]);
    
      // Correctly adjust dimensions and scale on transformation
      rect.on('transform', () => {
        // Get new scale
        const scaleX = rect.scaleX();
        const scaleY = rect.scaleY();
    
        // Update width and height based on scales
        rect.width(rect.width() * scaleX);
        rect.height(rect.height() * scaleY);
    
        // Reset scales
        rect.scaleX(1);
        rect.scaleY(1);
      });
    
      stage.draw();
    <script src="https://unpkg.com/konva@9.3.16/konva.min.js"></script>
    <div id="container"></div>