2017-04-24 98 views
-1

我正在使用Konva库在HTML5画布上绘制一些东西。画布垂直指向线

我已经给了来自用户的交互2点通过鼠标点击:

var A={x:'',y:''}; 
var B={x:'',y:''}; 

1)如何画线行吗? enter image description here

我的问题是:

1)如何获得每个间隔垂直线?

2)如何获得从A点到B点的距离?

3)如何获得从A到B在线的所有点?

4)如何获得红点?

+0

你必须定义 - 是在图片什么样的曲线?正弦波?垂直于什么?距离 - 直线段长度还是曲线长度? – MBo

+0

这是自定义的。所有的距离可以灵活取决于屏幕。我只有A和B点。红线与线(A,B)垂直,所以我需要找到这些点。 –

+0

总是有相同数量的红点?或者也可以改变? – MrApnea

回答

1

我们有A,B点差矢量

D.X = B.X - A.X 
D.Y = B.Y - A.Y 
Length = Sqrt(D.X * D.X + D.Y * D.Y) 

normalized (unit) vector 
uD.X = D.X/Length 
uD.Y = D.Y/Length 

perpendicular unit vector 
P.X = - uD.Y 
P.Y = uD.X 

some red point: 
R.X = A.X + uD.X * Dist + P.X * SideDist * SideSign  
R.Y = A.Y + uD.Y * Dist + P.Y * SideDist * SideSign   

where Dist is in range 0..Length 
Dist = i/N * Length for N equidistant points 
SideSign is +/- 1 for left and right side 
+0

谢谢。这是完美的解决方案。 –

1

你没有解释你的线是什么,所以我假定这是一个正弦波(尽管图像看起来就像粘在一起的圆圈???)

由于MBo给出了基础知识,这只是将其应用于波浪线。

// normalize a vector 
 
function normalize(vec){ 
 
    var length = Math.sqrt(vec.x * vec.x + vec.y * vec.y); 
 
    vec.x /= length; 
 
    vec.y /= length; 
 
    return vec; 
 
     
 
} 
 
// creates a wavy line 
 
function wavyLine(start, end, waves, amplitude){ 
 
    return ({ 
 
     start, 
 
     end, 
 
     waves, 
 
     amplitude, 
 
     update(){ 
 
      if(this.vec === undefined){ 
 
       this.vec = {}; 
 
       this.norm = {}; 
 
      } 
 
      this.vec.x = this.end.x - this.start.x; 
 
      this.vec.y = this.end.y - this.start.y; 
 
      this.length = Math.sqrt(this.vec.x * this.vec.x + this.vec.y * this.vec.y); 
 
      this.norm.x = this.vec.x/this.length; 
 
      this.norm.y = this.vec.y/this.length; 
 
      return this; 
 
     } 
 
    }).update(); 
 
} 
 

 

 
// draws a wavy line 
 
function drawWavyLine(line) { 
 
    var x, stepSize, i, y, phase, dist; 
 
    ctx.beginPath(); 
 
    stepSize = ctx.lineWidth; 
 
    ctx.moveTo(line.start.x, line.start.y); 
 
    for (i = stepSize; i < line.length; i+= stepSize) { 
 
     x = line.start.x + line.norm.x * i; // get point i pixels from start 
 
     y = line.start.y + line.norm.y * i; // get point i pixels from start 
 
     phase = (i/(line.length/line.waves)) * Math.PI * 2; // get the wave phase at this point 
 
     dist = Math.sin(phase) * line.amplitude; // get the distance from the line to the point on the wavy curve 
 
     x -= line.norm.y * dist; 
 
     y += line.norm.x * dist; 
 
     ctx.lineTo(x, y); 
 
    } 
 
    phase = line.waves * Math.PI * 2; // get the wave phase at this point 
 
    dist = Math.sin(phase) * line.amplitude; // get the distance from the line to the point on the wavy curve 
 
    ctx.lineTo(line.end.x - line.norm.y * dist, line.end.y + line.norm.x * dist);  
 
    ctx.stroke(); 
 
} 
 

 
// find the closest point on a wavy line to a point returns the pos on the wave, tangent and point on the linear line 
 
function closestPointOnLine(point,line){ 
 
    var x = point.x - line.start.x; 
 
    var y = point.y - line.start.y; 
 
    // get the amount the line vec needs to be scaled so tat point is perpendicular to the line 
 
    var l = (line.vec.x * x + line.vec.y * y)/(line.length * line.length); 
 
    x = line.vec.x * l; // scale the vec 
 
    y = line.vec.y * l; 
 
    return pointAtDistance(Math.sqrt(x * x + y * y), line); 
 
} 
 

 

 
// find the point at (linear) distance along wavy line and return coordinate, coordinate on wave, and tangent 
 
function pointAtDistance(distance,line){ 
 
    var lenScale = line.length/line.waves; // scales the length into radians 
 
    var phase = distance * Math.PI * 2/lenScale; // get the wave phase at this point 
 
    var dist = Math.sin(phase) * line.amplitude; // get the distance from the line to the point on the wavy curve 
 
    var slope = Math.cos(phase) * Math.PI * 2 * line.amplitude/lenScale; // derivitive of sin(a*x) is -a*cos(a*x) 
 
    // transform tangent (slope) into a vector along the line. This vector is not a unit vector so normalize it 
 
    var tangent = normalize({ 
 
     x : line.norm.x - line.norm.y * slope, 
 
     y : line.norm.y + line.norm.x * slope 
 
    }); 
 
    // move from the line start to the point on the linear line at distance 
 
    var linear = { 
 
     x : line.start.x + line.norm.x * distance, 
 
     y : line.start.y + line.norm.y * distance 
 
    } 
 
    // move out perpendicular to the wavy part 
 
    return { 
 
     x : linear.x - line.norm.y * dist, 
 
     y : linear.y + line.norm.x * dist, 
 
     tangent,linear 
 
    }; 
 
} 
 

 
// create a wavy line 
 
var wLine = wavyLine({x:10,y:100},{x:300,y:100},3,50); 
 

 

 

 
// draw the wavy line and show some points on it 
 
function display(timer){ 
 
    globalTime = timer; 
 
    ctx.setTransform(1,0,0,1,0,0); // reset transform 
 
    ctx.globalAlpha = 1;   // reset alpha 
 
    ctx.clearRect(0,0,w,h); 
 
    var radius = Math.max(ch,cw); 
 
    // set up the wavy line 
 
    wLine.waves = Math.sin(timer/10000) * 6; 
 
    wLine.start.x = Math.cos(timer/50000) * radius + cw; 
 
    wLine.start.y = Math.sin(timer/50000) * radius + ch; 
 
    wLine.end.x = -Math.cos(timer/50000) * radius + cw; 
 
    wLine.end.y = -Math.sin(timer/50000) * radius + ch ; 
 
    wLine.update(); 
 
    
 
    // draw the linear line 
 
    ctx.lineWidth = 0.5; 
 
    ctx.strokeStyle = "blue"; 
 
    ctx.beginPath(); 
 
    ctx.moveTo(wLine.start.x, wLine.start.y); 
 
    ctx.lineTo(wLine.end.x, wLine.end.y); 
 
    ctx.stroke(); 
 

 
    // draw the wavy line 
 
    ctx.lineWidth = 2; 
 
    ctx.strokeStyle = "black"; 
 
    drawWavyLine(wLine); 
 
    
 
    
 
    // find point nearest mouse 
 
    var p = closestPointOnLine(mouse,wLine); 
 
    ctx.lineWidth = 1; 
 
    ctx.strokeStyle = "red"; 
 
    ctx.beginPath(); 
 
    ctx.arc(p.x,p.y,5,0,Math.PI * 2); 
 
    ctx.moveTo(p.x + p.tangent.x * 20,p.y + p.tangent.y * 20); 
 
    ctx.lineTo(p.x - p.tangent.y * 10,p.y + p.tangent.x * 10); 
 
    ctx.lineTo(p.x + p.tangent.y * 10,p.y - p.tangent.x * 10); 
 
    ctx.closePath(); 
 
    ctx.stroke(); 
 
    
 
    // find points at equal distance along line 
 
    
 
    ctx.lineWidth = 1; 
 
    ctx.strokeStyle = "blue"; 
 
    ctx.beginPath(); 
 
    for(var i = 0; i < w; i += w/10){ 
 
     var p = pointAtDistance(i,wLine); 
 
     ctx.moveTo(p.x + 5,p.y); 
 
     ctx.arc(p.x,p.y,5,0,Math.PI * 2); 
 
     ctx.moveTo(p.x,p.y); 
 
     ctx.lineTo(p.linear.x,p.linear.y); 
 
     ctx.moveTo(p.x + p.tangent.x * 40, p.y + p.tangent.y * 40);   
 
     ctx.lineTo(p.x - p.tangent.x * 40, p.y - p.tangent.y * 40);   
 
     
 
    } 
 
    ctx.stroke(); 
 
    
 
} 
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 
/****************************************************************************** 
 
The code from here down is generic full page mouse and canvas boiler plate 
 
code. As I do many examples which all require the same mouse and canvas 
 
functionality I have created this code to keep a consistent interface. The 
 
Code may or may not be part of the answer. 
 
This code may or may not have ES6 only sections so will require a transpiler 
 
such as babel.js to run on legacy browsers. 
 
*****************************************************************************/ 
 
// V2.0 ES6 version for Stackoverflow and Groover QuickRun 
 
var w, h, cw, ch, canvas, ctx, mouse, globalTime = 0; 
 
// You can declare onResize (Note the capital R) as a callback that is also 
 
// called once at start up. Warning on first call canvas may not be at full 
 
// size. 
 
;(function(){ 
 
    const RESIZE_DEBOUNCE_TIME = 100; 
 
    var resizeTimeoutHandle; 
 
    var firstRun = true; 
 
    function createCanvas() { 
 
     var c,cs; 
 
     cs = (c = document.createElement("canvas")).style; 
 
     cs.position = "absolute"; 
 
     cs.top = cs.left = "0px"; 
 
     cs.zIndex = 1000; 
 
     document.body.appendChild(c); 
 
     return c; 
 
    } 
 
    function resizeCanvas() { 
 
     if (canvas === undefined) { canvas = createCanvas() } 
 
     canvas.width = innerWidth; 
 
     canvas.height = innerHeight; 
 
     ctx = canvas.getContext("2d"); 
 
     if (typeof setGlobals === "function") { setGlobals() } 
 
     if (typeof onResize === "function") { 
 
      clearTimeout(resizeTimeoutHandle); 
 
      if (firstRun) { onResize() } 
 
      else { resizeTimeoutHandle = setTimeout(onResize, RESIZE_DEBOUNCE_TIME) } 
 
      firstRun = false; 
 
     } 
 
    } 
 
    function setGlobals() { 
 
     cw = (w = canvas.width)/2; 
 
     ch = (h = canvas.height)/2; 
 
    } 
 
    mouse = (function() { 
 
     var m; // alias for mouse 
 
     var mouse = { 
 
      x : 0, y : 0, // mouse position and wheel 
 
      buttonRaw : 0, 
 
      buttonOnMasks : [0b1, 0b10, 0b100], // mouse button on masks 
 
      buttonOffMasks : [0b110, 0b101, 0b011], // mouse button off masks 
 
      bounds : null, 
 
      eventNames : "mousemove,mousedown,mouseup".split(","), 
 
      event(e) { 
 
       var t = e.type; 
 
       m.bounds = m.element.getBoundingClientRect(); 
 
       m.x = e.pageX - m.bounds.left - scrollX; 
 
       m.y = e.pageY - m.bounds.top - scrollY; 
 
       if (t === "mousedown") { m.buttonRaw |= m.buttonOnMasks[e.which - 1] } 
 
       else if (t === "mouseup") { m.buttonRaw &= m.buttonOffMasks[e.which - 1] } 
 
      }, 
 
      start(element) { 
 
       m.element = element === undefined ? document : element; 
 
       m.eventNames.forEach(name => document.addEventListener(name, mouse.event)); 
 
      }, 
 
     } 
 
     m = mouse; 
 
     return mouse; 
 
    })(); 
 

 
    function update(timer) { // Main update loop 
 
     globalTime = timer; 
 
     display(timer);   // call demo code 
 
     requestAnimationFrame(update); 
 
    } 
 
    setTimeout(function(){ 
 
     canvas = createCanvas(); 
 
     mouse.start(canvas); 
 
     resizeCanvas(); 
 
     window.addEventListener("resize", resizeCanvas); 
 
     requestAnimationFrame(update); 
 
    },0); 
 
})();