2013-12-23 90 views
2

只需引用元素ID就可以用html和jquery畫一條線嗎?我在文本中有一個重要的單詞,並且希望在這個單詞和描述它的圖像之間畫一條線。我已經看到,可以在畫布之間繪製元素,但它們的樣式位置設置爲絕對。由於我的元素是文本中的單詞,因此我無法將其設置爲絕對。 例從html元素id畫線到另一個具有jQuery和canvas的html元素

<p>This is my text with this very <span id="important_word">important</span> word</p> 
... 
<img src="important.jpg" id="important_img"/> 

現在我想的跨度和IMG之間劃清了界限。可能嗎?

在此先感謝!

回答

3

我做了一個非常粗略的例子,我將如何去做。它應該設置你在正確的軌道,雖然:

我用可靠元素的class行和相應元素的data-id屬性。

HTML:

<p>This is my <span class="line" data-id="important_img">text</span> with this very <span class="line" data-id="important_img2">important</span> word</p>... 

<img src="important.jpg" id="important_img" /> 
<br> 
<br>o asf isj biojso jo f ad f 
<img src="important.jpg" id="important_img2" /> 

的jQuery:

$('.line').hover(function() { 
    var $t = $(this); 
    var $i = $('#' + $t.data('id')); 

    // find offset positions for the word (t = this) and image (i) 
    var ot = { 
     x: $t.offset().left + $t.width()/2, 
     y: $t.offset().top + $t.height()/2 
    }; 
    var oi = { 
     x: $i.offset().left + $i.width()/2, 
     y: $i.offset().top + $i.height()/2 
    }; 

    // x,y = top left corner 
    // x1,y1 = bottom right corner 
    var p = { 
     x: ot.x < oi.x ? ot.x : oi.x, 
     x1: ot.x > oi.x ? ot.x : oi.x, 
     y: ot.y < oi.y ? ot.y : oi.y, 
     y1: ot.y > oi.y ? ot.y : oi.y 
    }; 

    // create canvas between those points 
    var c = $('<canvas/>').attr({ 
     'width': p.x1 - p.x, 
     'height': p.y1 - p.y 
    }).css({ 
     'position': 'absolute', 
     'left': p.x, 
     'top': p.y, 
     'z-index': 1 
    }).appendTo($('body'))[0].getContext('2d'); 

    // draw line 
    c.strokeStyle = '#f00'; 
    c.lineWidth = 2; 
    c.beginPath(); 
    c.moveTo(ot.x - p.x, ot.y - p.y); 
    c.lineTo(oi.x - p.x, oi.y - p.y); 
    c.stroke(); 
}, function() { 
    $('canvas').remove(); 
}); 

演示:

http://jsfiddle.net/v8pbc/

+0

非常感謝你安迪!這是我不知道的方法抵消(),節日快樂:) – user1478200

+0

非常有幫助! –

4

由於這個問題不斷出現,我已經付出了一些努力。它不是jquery,所以你可能在一定程度上可以簡化。僅供參考此答案也張貼在an answer to this other question,但請求是相同的。使用HTML和問題的CSS,這裏有一個jsbin演示http://jsbin.com/guken/3/

example output

的方法是創建一個浮動的canvas元素(陰影粉紅色),並奠定了DOM的其餘部分的下面(使用z-index)。然後我計算兩個盒子邊框上與盒子中心之間的一條線相對應的點。紅色和藍色方塊實際上是與行結束一起移動的div,可用於註釋,如源,目標等。

在該jsbin中,您可以單擊一個元素,然後獲取一行準備單擊在下。它檢測所選元素的懸停,並將鼠標懸停在目標上時捕捉到目標。

我不會在這裏貼上所有的代碼,但如果我們在客戶端DOM座標畫一條線,從一個x,y位置到另一個位是這樣的:

var lineElem; 
function drawLineXY(fromXY, toXY) { 
    if(!lineElem) { 
     lineElem = document.createElement('canvas'); 
     lineElem.style.position = "absolute"; 
     lineElem.style.zIndex = -100; 
     document.body.appendChild(lineElem); 
    } 
    var leftpoint, rightpoint; 
    if(fromXY.x < toXY.x) { 
     leftpoint = fromXY; 
     rightpoint = toXY; 
    } else { 
     leftpoint = toXY; 
     rightpoint = fromXY; 
    } 

    var lineWidthPix = 4; 
    var gutterPix = 10; 
    var origin = {x:leftpoint.x-gutterPix, 
        y:Math.min(fromXY.y, toXY.y)-gutterPix}; 
    lineElem.width = Math.max(rightpoint.x - leftpoint.x, lineWidthPix) + 
     2.0*gutterPix; 
    lineElem.height = Math.abs(fromXY.y - toXY.y) + 2.0*gutterPix; 
    lineElem.style.left = origin.x; 
    lineElem.style.top = origin.y; 
    var ctx = lineElem.getContext('2d'); 
    // Use the identity matrix while clearing the canvas 
    ctx.save(); 
    ctx.setTransform(1, 0, 0, 1, 0, 0); 
    ctx.clearRect(0, 0, lineElem.width, lineElem.height); 
    ctx.restore(); 
    ctx.lineWidth = 4; 
    ctx.strokeStyle = '#09f'; 
    ctx.beginPath(); 
    ctx.moveTo(fromXY.x - origin.x, fromXY.y - origin.y); 
    ctx.lineTo(toXY.x - origin.x, toXY.y - origin.y); 
    ctx.stroke(); 
} 

作爲例子只是一個行,並且我們可以隨時存儲已完成準備創建更多的行,它使用全局變量lineElem。在第一次繪製線條時,它會創建一個canvas元素,將其插入到DOM中並將其分配給lineElem。在此構造之後,它隨後重新使用畫布元素,更改大小並重新繪製新座標對。

爲防止線條被畫布邊緣切斷,有一個用於填充畫布寬度和高度的陰溝設置。剩下的就是在客戶DOM座標和畫布本身的繪製座標之間獲得座標平移。

唯一的另一個非直接位是計算一個線框上一個盒子邊界上一個點的座標。這並不完美,但這是一個合理的開始。關鍵是從源(from)點的角度計算目標(to)點的角度,並看看如何比較箱子角部的已知角度:

function getNearestPointOutside(from, to, boxSize) { 
    // which side does it hit? 
    // get the angle of to from from. 
    var theta = Math.atan2(boxSize.y, boxSize.x); 
    var phi = Math.atan2(to.y - from.y, to.x - from.x); 
    var nearestPoint = {}; 
    if(Math.abs(phi) < theta) { // crosses +x 
     nearestPoint.x = from.x + boxSize.x/2.0; 
     nearestPoint.y = from.y + ((to.x === from.x) ? from.y : 
     ((to.y - from.y)/(to.x - from.x) * boxSize.x/2.0)); 
    } else if(Math.PI-Math.abs(phi) < theta) { // crosses -x 
     nearestPoint.x = from.x - boxSize.x/2.0; 
     nearestPoint.y = from.y + ((to.x === from.x) ? from.y : 
     (-(to.y - from.y)/(to.x - from.x) * boxSize.x/2.0)); 
    } else if(to.y > from.y) { // crosses +y 
     nearestPoint.y = from.y + boxSize.y/2.0; 
     nearestPoint.x = from.x + ((to.y === from.y) ? 0 : 
     ((to.x - from.x)/(to.y - from.y) * boxSize.y/2.0)); 
    } else { // crosses -y 
     nearestPoint.y = from.y - boxSize.y/2.0; 
     nearestPoint.x = from.x - ((to.y === from.y) ? 0 : 
     ((to.x - from.x)/(to.y - from.y) * boxSize.y/2.0)); 
    } 
    return nearestPoint; 
} 

西塔是角到第一個盒子角落,而phi是實際的線條角度。

爲了獲得箱子的位置在客戶座標,你需要使用elem.getBoundingClientRect(),這將產生除其他事項外左,上,寬度,高度,我用它來找到一個框的中心:

function getCentreOfElement(el) { 
    var bounds = el.getBoundingClientRect(); 
    return {x:bounds.left + bounds.width/2.0, 
      y:bounds.top + bounds.height/2.0}; 
} 

把所有這些放在一起,你可以畫一條線從一個元素到另一個元素。