2

I am inspired with KonvaJS tutorial Modify Curves with Anchor Points to make my own example which is to create multiple custom arrows.

  1. on click on the selectionBox create an anchor.

  2. on the creation of the third anchor create the curved arrow.

  3. on the fourth click reset all variables in order to draw a new curved arrow.

    var width = window.innerWidth;
    var height = window.innerHeight;

    // globals
    var selectionBoxLayer, curveLayer, lineLayer, anchorLayer, quad, bezier;

    function updateDottedLines() {
        var q = quad;
        var quadLine = lineLayer.get('#quadLine')[0];

        quadLine.setPoints([q.start.attrs.x, q.start.attrs.y, q.control.attrs.x, q.control.attrs.y, q.end.attrs.x, q.end.attrs.y]);
        lineLayer.draw();
    }
    function buildAnchor(x, y) {
        var anchor = new Konva.Circle({
            x: x,
            y: y,
            radius: 20,
            stroke: '#666',
            fill: '#ddd',
            strokeWidth: 2,
            draggable: true
        });

        // add hover styling
        anchor.on('mouseover', function() {
            document.body.style.cursor = 'pointer';
            this.setStrokeWidth(4);
            anchorLayer.draw();
        });
        anchor.on('mouseout', function() {
            document.body.style.cursor = 'default';
            this.setStrokeWidth(2);
            anchorLayer.draw();

        });

        anchor.on('dragend', function() {
            drawCurves();
            updateDottedLines();
        });

        anchorLayer.add(anchor);
        anchorLayer.draw();
        return anchor;
    }
        function drawCurves() {
        var context = curveLayer.getContext();
        var arrowLine = new Konva.Shape({
            sceneFunc: function(context){
              debugger;
                      // draw quad
        context.beginPath();
        context.moveTo(quad.start.attrs.x, quad.start.attrs.y);
        context.quadraticCurveTo(quad.control.attrs.x, quad.control.attrs.y, quad.end.attrs.x, quad.end.attrs.y);
                //Draw Arrow Head
                var headlen = 10;   // length of head in pixels
                var angle = Math.atan2(quad.end.attrs.y - quad.control.attrs.y, quad.end.attrs.x - quad.control.attrs.x);
                context.lineTo(quad.end.attrs.x-headlen*Math.cos(angle-Math.PI/6), quad.end.attrs.y-headlen*Math.sin(angle-Math.PI/6));
                context.moveTo(quad.end.attrs.x, quad.end.attrs.y);
                context.lineTo(quad.end.attrs.x- headlen*Math.cos(angle+Math.PI/6), quad.end.attrs.y-headlen*Math.sin(angle+Math.PI/6));
                context.fillStrokeShape(this);
            },
            stroke: 'black',
            strokeWidth: 4
        });
        curveLayer.add(arrowLine);
        curveLayer.draw();
    }

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

    // curveLayer just contains a canvas which is drawn
    // onto with the existing canvas API
    curveLayer = new Konva.Layer();

    var quadLine = new Konva.Line({
        dash: [10, 10, 0, 10],
        strokeWidth: 3,
        stroke: 'black',
        lineCap: 'round',
        id: 'quadLine',
        opacity: 0.3,
        points: [0, 0]
    });


    // add dotted line connectors
    lineLayer.add(quadLine);

    quad = {};

    // keep curves insync with the lines
    anchorLayer.on('beforeDraw', function() {
      if(quad.start && quad.control && quad.end){
        drawCurves();
        updateDottedLines();
      }
    });

   var selectionBoxBackground = new Konva.Rect({
        x: 0,
        y: 0,
        height:stage.height(),
        width: stage.width(),
        fill: 'transparent',
        draggable: false,
        name: 'selectionBoxBackground'
    });
    selectionBoxLayer.add(selectionBoxBackground);
    var clickCounter = 0;
    selectionBoxBackground.on("click", function(){
        clickCounter +=1;
      var mousePos = {};
        switch(clickCounter){
            case 1:
            mousePos = stage.getPointerPosition();
            quad.start = buildAnchor(mousePos.x, mousePos.y);
            break;
            case 2:
            mousePos = stage.getPointerPosition();
            quad.control = buildAnchor(mousePos.x, mousePos.y);
            break;
            case 3:
            mousePos = stage.getPointerPosition();
            quad.end = buildAnchor(mousePos.x, mousePos.y);
            drawCurves();
            updateDottedLines();
            break;
            default:
            clickCounter = 0;
            quad = {};
            anchorLayer.destroyChildren();
            anchorLayer.draw();
        }      
    });

    
    stage.add(curveLayer);
    stage.add(lineLayer);
    stage.add(selectionBoxLayer);
    stage.add(anchorLayer);
 body {
      margin: 0;
      padding: 0;
      overflow: hidden;
      background-color: #F0F0F0;
    }
<script src="https://cdn.rawgit.com/konvajs/konva/0.11.1/konva.min.js"></script>

<body>
  <div id="container"></div>


</body>

P.S Please note when I write in the browser console curveLayer.children, it will bring all created curved arrows.

Hint: I think on the creation of new Shape() the values of all created shapes will be changed to the new one.

I don't know what I am missing.

Mahdi Alkhatib
  • 1,954
  • 1
  • 29
  • 43

0 Answers0