2016-10-29 3 views
2

기본 JS를 사용하여 경로의 자유형 드로잉을 구현했습니다. 그러나 예상대로 경로 가장자리는 공격적이지 않고 부드럽 지 않습니다. 그래서 simplifyJS를 사용하여 점을 단순화하고 경로를 다시 그리는 옵션이 있습니다. 여기SVG 부드러운 핸드 드로잉

을 그리면서 그러나 here 같은, 대신 그린 후 평활, 나는이 간단한 가장자리를 찾기 위해 시도하고 내 코드입니다 :

var x0, y0; 

    var dragstart = function(event) { 
     var that = this; 
     var pos = coordinates(event); 
     x0 = pos.x; 
     y0 = pos.y; 
     that.points = []; 
    }; 

    var dragging = function(event) { 
     var that = this; 
     var xy = coordinates(event); 
     var points = that.points; 
     var x1 = xy.x, y1 = xy.y, dx = x1 - x0, dy = y1 - y0; 
     if (dx * dx + dy * dy > 100) { 
      xy = { 
       x: x0 = x1, 
       y: y0 = y1 
      }; 
     } else { 
      xy = { 
       x: x1, 
       y: y1 
      }; 
     } 
     points.push(xy); 
    }; 

그러나 위의 추가 된 링크로 작동하지 않습니다. 여전히 가장자리가 좋지 않습니다. 도와주세요.

enter image description here enter image description here

+3

그것은 당신의 문제가 무엇인지 정말 분명하지 않다 - 당신을 돕기 위해 우리를 도와 – danyamachine

+2

등 더 많은 정보 스크린 샷하는 의도 한 결과를 더 잘 설명과 실제 결과를 추가하는 것이 좋습니다. 문제가 무엇인지 명확하게 알 수 있도록 [MCVE] (http://www.stackoverflow.com/help/mcve)를 만드십시오. –

+0

@PaulLeBeau 위의 스크린 샷을 추가했습니다. 필자는 의존성 코드가 너무 많아서 바이올린을 만들기가 쉽지 않습니다. – Exception

답변

8

다음 코드 단편은 마지막 마우스 위치의 평균을 계산하여 곡선을 부드럽게 만듭니다. 스무딩 레벨은 이러한 값이 유지되는 버퍼의 크기에 따라 달라집니다. 드롭 다운 목록에서 제공되는 다양한 버퍼 크기를 시험해 볼 수 있습니다. 12 포인트 버퍼의 동작은 질문에서 참조한 Mike Bostock's code snippet과 다소 유사합니다.

더 정교한 기법을 구현하여 버퍼에 저장된 위치 (가중 평균, 선형 회귀, 3 차 스플라인 스무딩 등)에서 부드럽게 된 점을 얻을 수 있지만이 간단한 평균 방법은 사용자의 요구에 충분히 정확하게 적용 할 수 있습니다.

var strokeWidth = 2; 
 
var bufferSize; 
 

 
var svgElement = document.getElementById("svgElement"); 
 
var rect = svgElement.getBoundingClientRect(); 
 
var path = null; 
 
var strPath; 
 
var buffer = []; // Contains the last positions of the mouse cursor 
 

 
svgElement.addEventListener("mousedown", function (e) { 
 
    bufferSize = document.getElementById("cmbBufferSize").value; 
 
    path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); 
 
    path.setAttribute("fill", "none"); 
 
    path.setAttribute("stroke", "#000"); 
 
    path.setAttribute("stroke-width", strokeWidth); 
 
    buffer = []; 
 
    var pt = getMousePosition(e); 
 
    appendToBuffer(pt); 
 
    strPath = "M" + pt.x + " " + pt.y; 
 
    path.setAttribute("d", strPath); 
 
    svgElement.appendChild(path); 
 
}); 
 

 
svgElement.addEventListener("mousemove", function (e) { 
 
    if (path) { 
 
     appendToBuffer(getMousePosition(e)); 
 
     updateSvgPath(); 
 
    } 
 
}); 
 

 
svgElement.addEventListener("mouseup", function() { 
 
    if (path) { 
 
     path = null; 
 
    } 
 
}); 
 

 
var getMousePosition = function (e) { 
 
    return { 
 
     x: e.pageX - rect.left, 
 
     y: e.pageY - rect.top 
 
    } 
 
}; 
 

 
var appendToBuffer = function (pt) { 
 
    buffer.push(pt); 
 
    while (buffer.length > bufferSize) { 
 
     buffer.shift(); 
 
    } 
 
}; 
 

 
// Calculate the average point, starting at offset in the buffer 
 
var getAveragePoint = function (offset) { 
 
    var len = buffer.length; 
 
    if (len % 2 === 1 || len >= bufferSize) { 
 
     var totalX = 0; 
 
     var totalY = 0; 
 
     var pt, i; 
 
     var count = 0; 
 
     for (i = offset; i < len; i++) { 
 
      count++; 
 
      pt = buffer[i]; 
 
      totalX += pt.x; 
 
      totalY += pt.y; 
 
     } 
 
     return { 
 
      x: totalX/count, 
 
      y: totalY/count 
 
     } 
 
    } 
 
    return null; 
 
}; 
 

 
var updateSvgPath = function() { 
 
    var pt = getAveragePoint(0); 
 

 
    if (pt) { 
 
     // Get the smoothed part of the path that will not change 
 
     strPath += " L" + pt.x + " " + pt.y; 
 

 
     // Get the last part of the path (close to the current mouse position) 
 
     // This part will change if the mouse moves again 
 
     var tmpPath = ""; 
 
     for (var offset = 2; offset < buffer.length; offset += 2) { 
 
      pt = getAveragePoint(offset); 
 
      tmpPath += " L" + pt.x + " " + pt.y; 
 
     } 
 

 
     // Set the complete current path coordinates 
 
     path.setAttribute("d", strPath + tmpPath); 
 
    } 
 
};
html, body 
 
{ 
 
    padding: 0px; 
 
    margin: 0px; 
 
} 
 
#svgElement 
 
{ 
 
    border: 1px solid; 
 
    margin-top: 4px; 
 
    margin-left: 4px; 
 
    cursor: default; 
 
} 
 
#divSmoothingFactor 
 
{ 
 
    position: absolute; 
 
    left: 14px; 
 
    top: 12px; 
 
}
<div id="divSmoothingFactor"> 
 
    <label for="cmbBufferSize">Buffer size:</label> 
 
    <select id="cmbBufferSize"> 
 
     <option value="1">1 - No smoothing</option> 
 
     <option value="4">4 - Sharp curves</option> 
 
     <option value="8" selected="selected">8 - Smooth curves</option> 
 
     <option value="12">12 - Very smooth curves</option> 
 
     <option value="16">16 - Super smooth curves</option> 
 
     <option value="20">20 - Hyper smooth curves</option> 
 
    </select> 
 
</div> 
 
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="svgElement" x="0px" y="0px" width="600px" height="400px" viewBox="0 0 600 400" enable-background="new 0 0 600 400" xml:space="preserve">

+0

이것은 놀라운 대답입니다! – Exception

+0

현상금 할당을 기다리고 있지만 다음 50 분 내에 해결할 수 없습니다. – Exception

+0

@ConnersFan이 질문에 나를 도울 수 있습니까? http://stackoverflow.com/q/40708754/1008575 – Exception

0

이미 GitHub의 예에서이에 대한 몇 가지 구현이 있습니다 https://github.com/epistemex/cardinal-spline-js

입력 내용을 변경하지 않아도 점 사이의 선이 부드럽게 그려지는 기능 만 변경할 수 있습니다. 그것으로 점은 단순화 도중 조금 미끄러지지 않습니다.

관련 문제