1

Draw Polygon

I need help to draw a polygon and snap to a grid. I also would like to be able to change the dimensions after it has been drawn. Does anyone know where I can find information on how to do this in konva js.

I have googled it but can't seem to get anywhere. the support docs from konva.js are good but can't find exactly what im looking for.

<!DOCTYPE html>
<html>

<head>
    <script src="https://unpkg.com/konva@8.4.3/konva.min.js"></script>
    <meta charset="utf-8" />
    <title>Konva Simple Window drawing</title>
    <style>
        body {
            padding: 0;
            margin: 0;
            overflow: hidden;
        }

        #container {
            border: 1px solid grey;
            background-color: lightgrey;
        }

        #controls {
            position: absolute;
            top: 4px;
            left: 4px;
        }
    </style>
</head>

<body>
    <script src="https://cdn.rawgit.com/konvajs/konva/1.6.5/konva.min.js"></script>

    <div id='container1'
        style="display: inline-block; width: 300px, height: 200px; background-color: silver; overflow: hidden; position: relative;">
    </div>
    <script>
// Set up the canvas / stage
var s1 = new Konva.Stage({container: 'container1', width: 600, height: 300});
        
        // Add a layer for line
        var lineLayer = new Konva.Layer({draggable: false});
        s1.add(lineLayer);
        
        // Add a layer for drag points
        var pointLayer = new Konva.Layer({draggable: false});
        s1.add(pointLayer);
        
        // Add a rectangle to layer to catch events. Make it semi-transparent 
        var r = new Konva.Rect({x:0, y: 0,  width: 600, height: 300, fill: 'black', opacity: 0.1})
        pointLayer.add(r)
        
        // Everything is ready so draw the canvas objects set up so far.
        s1.draw()
        
        // generic canvas end
        
        
        
        // Class for the draggable point
        // Params: path = the parent object, opts = position info, doPush = should we just make it or make it AND store it
        var DragPoint = function(path, opts, doPush){
          var path = path;
        
          this.x = opts.x;
          this.y = opts.y;
          this.fixed = opts.fixed;
          this.id = randId();  // random id.
        
          if (doPush){  // in some cases we want to create the pt then insert it in the run of the array and not always at the end
            path.pts.push(this);  
          }
        
          // random id generator
          function randId() {
             return Math.random().toString(36).replace(/[^a-z]+/g, '').substr(2, 10);
          }
        
          // mark the pt as fixed - important state, shown by filled point
          this.makeFixed = function(){
            this.fixed = true;
            s1.find('#' + this.id)
                .fill(path.fillColor);      
          }
          
          this.kill = function(){
            s1.find('#' + this.id)
                .remove();        
          }
          
          this.draw = function(){
            // Add point & pt
            var circleId = this.id;
         
            var pt = new Konva.Circle({
              id: circleId,
              x: this.x, 
              y: this.y, 
              radius: 3,
              opacity: path.pointOpacity,
              strokeWidth: 3,
              stroke: path.strokeColor,
              fill: 'transparent',
              draggable: 'true'    
            })
            pt.on('dragstart', function(){
                path.drawState = 'dragging';
            })
            pt.on('dragmove', function(){
              var pos = this.getPosition();
              path.updatePt(this.id(), pos)
              path.calc(this.id());
              path.draw();
            })
            pt.on('dragend', function(){
        
              path.drawState = 'drawing';
              var pos = this.getPosition();
        
              path.updatePt(this.getId(), pos);
        
              path.splitPts(this.getId());
              
              path.draw();
            })
        
            if (this.fixed){
              this.makeFixed();
            }
            
            
            path.ptLayer.add(pt);
            path.draw();
        
          }  
          
        }
        
        var path = function() {
        
            this.lineLayer = null;
            this.ptLayer = null;
            this.drawState = '';
        
         
            this.pts = []; // array of dragging points.
        
            this.startPt = null;
            this.endPt = null;
        

        
            // Add a point to the path.
            this.addPt = function(pos, isFixed){ 
              
              if (this.drawState === 'dragging'){  // do not add a new point because we were just dragging another
                return null;
              }
              
              this.startPt = this.startPt || pos;
              this.endPt = pos;
        
              // create this new pt
              var pt = new DragPoint(this, {x: this.endPt.x, y: this.endPt.y, fixed: isFixed}, true, "A");
              pt.draw();
              pt.makeFixed(); // always fixed for manual points
              
              // if first point ignore the splitter process
              if (this.pts.length > 0){
                this.splitPts(pt.id, true);
              }    
        
              this.startPt = this.endPt; // remember the last point
        
              this.calc(); // calculate the line points from the array
              this.draw();  // draw the line 
            }
        
          // Position the points.  
          this.calc = function (draggingId){
            draggingId = (typeof draggingId === 'undefined' ? '---' : draggingId); // when dragging an unfilled point we have to override its automatic positioning.
        
            for (var i = 1; i < this.pts.length - 1; i = i + 1){
        
              var d2 = this.pts[i];
              if (!d2.fixed && d2.id !== draggingId){      // points that have been split are fixed, points that have not been split are repositioned mid way along their line segment.
        
                var d1 = this.pts[i - 1];
                var d3 = this.pts[i + 1];
                var pos = this.getHalfwayPt(d1, d3);
                
                d2.x = pos.x;
                d2.y = pos.y;
              }
              s1.find('#' + d2.id).position({x: d2.x, y: d2.y}); // tell the shape where to go
            }
          }
        
          // draw the line
          this.draw = function (){  
        
            if (this.drawingLine){
              this.drawingLine.remove();
            }
            this.drawingLine = this.newLine(); // initial line point
            
            for (var i = 0; i < this.pts.length; i = i + 1){
              this.drawingLine.points(this.drawingLine.points().concat([this.pts[i].x, this.pts[i].y]))
            }
            
            this.ptLayer.draw();
            this.lineLayer.draw();
          }
        
          // When dragging we need to update the position of the point
          this.updatePt = function(id, pos){
        
              for (var i = 0; i < this.pts.length; i = i + 1){
                if (this.pts[i].id === id){
        
                  this.pts[i].x = pos.x;
                  this.pts[i].y = pos.y;
        
                  break;
                }    
              }
          }
        
          // Function to add and return a line object. We will extend this line to give the appearance of drawing.
          this.newLine = function(){
            var line = new Konva.Line({
                stroke: this.color,
                strokeWidth: this.width,
                lineCap: 'round',
                lineJoin: 'round',
                tension : .1
              });
        
            this.lineLayer.add(line)
            return line;
          }  
        
        
          // make pts either side of the split
          this.splitPts = function(id, force){
            var idx = -1;
            
            // find the pt in the array
            for (var i = 0; i < this.pts.length; i = i + 1){
              if (this.pts[i].id === id){
                idx = i;
        
                if (this.pts[i].fixed && !force){
                  return null; // we only split once.
                }
        
                //break;
              }   
            }
        
            // If idx is -1 we did not find the pt id !
            if ( idx === -1){
              return null
            }
            else if (idx === 0  ) { 
              return null
            }
            else { // pt not = 0 or max 
        
              // We are now going to insert a new pt either side of the one we just dragged
              var d1 = this.pts[idx - 1]; // previous pt to the dragged pt
              var d2 = this.pts[idx    ]; // the pt pt
              var d3 = this.pts[idx + 1]; // the next pt after the dragged pt
        
              d2.makeFixed()// flag this pt as no longer splittable
        
              // get point midway from prev pt and dragged pt    
              var pos = this.getHalfwayPt(d1, d2);
              var pt = new DragPoint(this, {x: pos.x, y: pos.y, foxed: false}, false, "C");
              pt.draw();
              this.pts.splice(idx, 0, pt);
        
              if (d3){
                // get point midway from dragged pt to next     
                pos = this.getHalfwayPt(d2, d3);
                var pt = new DragPoint(this, {x: pos.x, y: pos.y, foxed: false}, false, "D");
                pt.draw();
                this.pts.splice(idx + 2, 0, pt); // note idx + 2 !
        
              }
        
            }  
        
          }  
          
          // convert last point array entry to handy x,y object.
          this.getPoint = function(pts){
            return {x: pts[pts.length - 2], y: pts[pts.length - 1]};
          }
          
          this.getHalfwayPt = function(d1, d2){
            var pos = {
                  x: d1.x + (d2.x - d1.x)/2, 
                  y: d1.y + (d2.y - d1.y)/2
              }
            return pos;
          }
        
          this.exportPoints = function(){
            var list = [], pt;    
            console.log('pts=' + this.pts.length)
            for (var i = 0; i < this.pts.length; i = i + 1){      
              pt = this.pts[i]
              if (pt.fixed){
                console.log('push ' + i)
                list.push({x: pt.x, y: pt.y});   
              }   
            }  
            return list;
          }
          
        }
        
        var path = new path();
        path.lineLayer = lineLayer;
        path.ptLayer = pointLayer;
        
        path.fillColor = 'AliceBlue'; 
        path.strokeColor = 'blue'; 
        path.pointOpacity = 1;
        path.pointRadius = 3;
        path.color = '#666666'
        
        
        // Listen for mouse up on the stage to know when to draw points
        s1.on('mouseup touchend', function () {
        
          path.addPt(s1.getPointerPosition(), true);
        });
        
        // jquery is used here simply as a quick means to make the buttons work.
        
        // Controls for points export
        $('#export').on('click', function(){
        
          if ($(this).html() === "Hide"){
            $(this).html('Export');
            $('#points').hide();
          }
          else {
            $(this).html('Hide');
            $('#points')
              .css('display', 'block')
              .val(JSON.stringify(path.exportPoints()));
          }  
        
        })
        
        // reset button
        $('#reset').on('click', function(){
          path.reset();
          })
    </script>

</body>

</html>

0 Answers0