Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using it's URL and the proper URL extention.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                 <script src="https://unpkg.com/konva@8/konva.min.js"></script>
<p>Hold left mouse button and drag to add a line with multiple points <br />
  Red line shows mouse points, blue line shows simplified points. </p>
<p><b>Try a long stright line to see the simplification effect</b></p>
<p><button id='reset'>Reset</button></p>
<p><span id='info'>.</span></p>


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

CSS

              
                body {
  margin: 20px;
  padding: 0;
  overflow: hidden;
  background-color: #f0f0f0;
}
#container {
  border: 1px solid silver;
  width: 600px;
  height: 200px;
}
 
              
            
!

JS

              
                
/*
 (c) 2017, Vladimir Agafonkin
 Simplify.js, a high-performance JS polyline simplification library
 mourner.github.io/simplify-js
*/

(function () { 'use strict';

// to suit your point format, run search/replace for '.x' and '.y';
// for 3D version, see 3d branch (configurability would draw significant performance overhead)

// square distance between 2 points
function getSqDist(p1, p2) {

    var dx = p1.x - p2.x,
        dy = p1.y - p2.y;

    return dx * dx + dy * dy;
}

// square distance from a point to a segment
function getSqSegDist(p, p1, p2) {

    var x = p1.x,
        y = p1.y,
        dx = p2.x - x,
        dy = p2.y - y;

    if (dx !== 0 || dy !== 0) {

        var t = ((p.x - x) * dx + (p.y - y) * dy) / (dx * dx + dy * dy);

        if (t > 1) {
            x = p2.x;
            y = p2.y;

        } else if (t > 0) {
            x += dx * t;
            y += dy * t;
        }
    }

    dx = p.x - x;
    dy = p.y - y;

    return dx * dx + dy * dy;
}
// rest of the code doesn't care about point format

// basic distance-based simplification
function simplifyRadialDist(points, sqTolerance) {

    var prevPoint = points[0],
        newPoints = [prevPoint],
        point;

    for (var i = 1, len = points.length; i < len; i++) {
        point = points[i];

        if (getSqDist(point, prevPoint) > sqTolerance) {
            newPoints.push(point);
            prevPoint = point;
        }
    }

    if (prevPoint !== point) newPoints.push(point);

    return newPoints;
}

function simplifyDPStep(points, first, last, sqTolerance, simplified) {
    var maxSqDist = sqTolerance,
        index;

    for (var i = first + 1; i < last; i++) {
        var sqDist = getSqSegDist(points[i], points[first], points[last]);

        if (sqDist > maxSqDist) {
            index = i;
            maxSqDist = sqDist;
        }
    }

    if (maxSqDist > sqTolerance) {
        if (index - first > 1) simplifyDPStep(points, first, index, sqTolerance, simplified);
        simplified.push(points[index]);
        if (last - index > 1) simplifyDPStep(points, index, last, sqTolerance, simplified);
    }
}

// simplification using Ramer-Douglas-Peucker algorithm
function simplifyDouglasPeucker(points, sqTolerance) {
    var last = points.length - 1;

    var simplified = [points[0]];
    simplifyDPStep(points, 0, last, sqTolerance, simplified);
    simplified.push(points[last]);

    return simplified;
}

// both algorithms combined for awesome performance
function simplify(points, tolerance, highestQuality) {

    if (points.length <= 2) return points;

    var sqTolerance = tolerance !== undefined ? tolerance * tolerance : 1;

    points = highestQuality ? points : simplifyRadialDist(points, sqTolerance);
    points = simplifyDouglasPeucker(points, sqTolerance);

    return points;
}

// export as AMD module / Node module / browser or worker variable
if (typeof define === 'function' && define.amd) define(function() { return simplify; });
else if (typeof module !== 'undefined') {
    module.exports = simplify;
    module.exports.default = simplify;
} else if (typeof self !== 'undefined') self.simplify = simplify;
else window.simplify = simplify;

})();


/*
* From here onwards we set up the stage and its contents.
*/
const stage = new Konva.Stage({
        container: 'container',
        width: $('#container').innerWidth(),
        height: $('#container').innerHeight() 
      }),
      layer = new Konva.Layer(),
      layer1 = new Konva.Layer();

let path, path1, dot, info = $('#info'), lineCnt = 0;
stage.add(layer, layer1);

let points = [], segments = [];

function addPoint(pt){
  
  // store the new raw point
  points.push(pt);
    
 // Add a visible marker for the raw pt
  const newDot = dot.clone({x: pt.x, y: pt.y});
  layer.add(newDot)

  // Make the drawing commands for the raw line
  // convert to drawing commands, supported commands are M, m, L, l, H, h, V, v, Q, q, T, t, C, c, S, s, A, a, Z, z
  let pathData = "", pathData1 = "";
  for (let i = 0; i < points.length; i++){
    let pt = points[i];
    switch (i){
      case 0:
        pathData+="M " + pt.x + " " + pt.y;
        break;
        
      default:
        pathData+="L " + pt.x + " " + pt.y;
        break;
    }
  }
 
  // remove the current simplified point markers ready to redraw after simplification
  const kids = layer1.find('.dotline' + lineCnt);
  for (let i = 0; i < kids.length; i++){
    kids[i].remove();
  }

  // simplify the raw points to make an equiv line with fewer points.
  const simplifiedPts = simplify(points);

  info.html('Raw points ' + points.length + ', simplified to ' + simplifiedPts.length)

  // Make the drawing commands for the simplified line
  for (let i = 0; i < simplifiedPts.length; i++){
    let pt = simplifiedPts[i];
    switch (i){
      case 0:
        pathData1+="M " + pt.x + " " + pt.y;
        break;
        
      default:
        pathData1+="L " + pt.x + " " + pt.y;
        break;
    }   
    const newDot1 = dot.clone({x: pt.x - 25, y: pt.y, name: 'dotline' + lineCnt});
    layer1.add(newDot1)
  }
   
  // set the new path data into the paths objects.
  path.data(pathData);
  path1.data(pathData1);
  
}

// user ends drawing with mouse up  
stage.on('mouseup', function (e) { 
  reset(false)
})

// user draws with mouse held down and moving
stage.on('mousemove', function (e) { 
  if (e.evt.buttons == 1){ // left btn only
    const pt = stage.getPointerPosition();
    addPoint(pt)    
  }
})

// reset button
$('#reset').on('click', function(){
  reset(true)
 
})
// reset the stage and points lists
function reset(clear){
  if (clear){
    layer.removeChildren();
    layer1.removeChildren();
  }
  points = [];
  segments = [];
  
  path = new Konva.Path({stroke: 'red', strokeWidth: 4});
  dot = new Konva.Circle({strokeWidth: 2, stroke: 'lime', radius: 5});
  path1 = new Konva.Path({stroke: 'blue', strokeWidth: 4, x: -25});
  layer.add(path, path1);   
  lineCnt++;
}
reset(true);
              
            
!
999px

Console