貌似squeamish ossifrage擊敗了我這一個,和他們說過會正是我的做法太...
解決方案
本質上找到EAC最長的線段h區域的路徑,然後定位您的文本以與該線段對齊,同時嘗試確保文本不會顛倒(!)
例
這裏有一個sample jsfiddle
在我添加標籤,所有區域的小提琴的$(document).ready()
功能,但你會注意到,一些地區的有不在該區域內的質心或導致問題的非直線邊緣 - 稍微修改地圖可能是最簡單的修復方法。
說明
這裏有3個功能,我寫證明的原則:
addOrientatedLabel(regionName)
- 增加了一個標籤,地圖的指定區域。
getAngleInDegreesFromRegion(regionName)
- 獲取區域
getLengthSquared(startPt,endPt)
的最長邊緣的角度 - 得到長度的平方線SEG(比讓長度更有效)的。
addOrientatedLabel()
地方使用平移變換和旋轉的文本以相同的角度在該區域的最長線段在質心的標籤。在SVG變換得到解決從右到左使:
transform="translate(x,y) rotate(45)"
被解釋爲旋轉第一,然後翻譯。這個順序很重要!
它也使用text-anchor="middle"
和dominant-baseline="middle"
,如squeamish ossifrage所解釋的。未能這樣做會導致文本在其區域內錯位。
getAngleInDegreesFromRegion()
是所有工作都完成的地方。它通過選擇器獲取區域的SVG路徑,然後遍歷路徑中的每個點。只要發現某個點是線段的一部分(而不是移動到或其他指令),它就會計算線段的平方長度。如果線段的平方長度是迄今爲止最長的,則存儲其細節。我使用平方長度,因爲這節省了執行平方根操作(它僅用於比較目的,所以平方長度很好)。
請注意,我將longestLine
數據初始化爲水平數據,因此如果該區域根本沒有線段,至少會獲得水平文本。
一旦我們有最長的線,我計算它的相對於x軸的角度與Math.atan2
,並將其從弧度轉換爲度爲SVG與(angle/Math.PI) * 180
。最後的技巧是確定角度是否將文本顛倒,如果是,則旋轉另一個180度。
注意
我沒有以前那麼我的SVG的代碼可能不是最佳使用SVG,但它的測試,它的工作原理上是由主要的直線段所有地區 - 你需要添加錯誤檢查課程的生產應用!
代碼
function addOrientatedLabel(regionName) {
var angleInDegrees = getAngleInDegreesFromRegion(regionName);
var map = $('#world-map').vectorMap('get', 'mapObject');
var coords = map.getRegionCentroid(regionName);
var svg = document.getElementsByTagName('g')[0]; //Get svg element
var newText = document.createElementNS("http://www.w3.org/2000/svg","text");
newText.setAttribute("font-size","4");
newText.setAttribute("text-anchor","middle");
newText.setAttribute("dominant-baseline","middle");
newText.setAttribute('font-family', 'MyriadPro-It');
newText.setAttribute('transform', 'translate(' + coords[0] + ',' + coords[1] + ') rotate(' + angleInDegrees + ')');
var textNode = document.createTextNode(regionName);
newText.appendChild(textNode);
svg.appendChild(newText);
}
這裏是我的方法來找到一個給定的地圖區域路徑最長的線段:
function getAngleInDegreesFromRegion(regionName) {
var svgPath = document.getElementById(regionName);
/* longest edge will default to a horizontal line */
/* (in case the shape is degenerate): */
var longestLine = { startPt: {x:0, y:0}, endPt: {x:100,y:0}, lengthSquared : 0 };
/* loop through all the points looking for the longest line segment: */
for (var i = 0 ; i < svgPath.pathSegList.numberOfItems-1; i++) {
var pt0 = svgPath.pathSegList.getItem(i);
var pt1 = svgPath.pathSegList.getItem(i+1);
if (pt1.pathSegType == SVGPathSeg.PATHSEG_LINETO_ABS) {
var lengthSquared = getLengthSquared(pt0, pt1);
if(lengthSquared > longestLine.lengthSquared) {
longestLine = { startPt:pt0, endPt:pt1, lengthSquared:lengthSquared};
}
}/* end if dealing with line segment */
}/* end loop through all pts in svg path */
/* determine angle of longest line segement relative to x axis */
var dY = longestLine.startPt.y - longestLine.endPt.y;
var dX = longestLine.startPt.x - longestLine.endPt.x;
var angleInDegrees = (Math.atan2(dY,dX)/Math.PI * 180.0);
/* if text would be upside down, rotate through 180 degrees: */
if((angleInDegrees > 90 && angleInDegrees < 270) || (angleInDegrees < -90 && angleInDegrees > -270)) {
angleInDegrees += 180;
angleInDegrees %= 360;
}
return angleInDegrees;
}
注意,我getAngleInDegreesFromRegion()
方法只考慮最長直如果它是使用PATHSEG_LINETO_ABS
SVG命令創建的,則在路徑中行...您需要更多的功能來處理不包含直的區域線。您可以通過處理與曲線爲直線近似:
if (pt1.pathSegType != SVGPathSeg.PATHSEG_MOVETO_ABS)
但會有一些極端情況,所以修改你的地圖數據可能是最簡單的方法。
最後,以下是完整強制性平方距離方法:
function getLengthSquared(startPt, endPt) {
return ((startPt.x - endPt.x) * (startPt.x - endPt.x)) + ((startPt.y - endPt.y) * (startPt.y - endPt.y));
}
希望這是很清楚,以幫助您開始。
解決質心位於區域中心之外的區域可能是最困難的問題。如果您將所有曲線視爲直線曲線,則即使在存在曲線邊緣的區域,它也會排列文本以「確定」工作。如上所述,對地圖數據進行一些修改(如果可能的話)可能是對那些效果不佳的地區最簡單的修復方法。 – 2014-12-20 21:19:30
我有正確的功能來解決某些SVG路徑上的問題。 問題是某些路徑是用相對值表示的,所以我在StackOverflow中添加了這個答案中的函數: [convert-svg-path-to-absolute-commands](http://stackoverflow.com/questions/ (svgPath.getAttribute(「d」)9677885/convert-svg-path-to-absolute-commands) 然後我添加了行來檢查路徑是否相對並最終調用convertToAbsolute()函數: if(svgPath.getAttribute .search(「l」)> -1){convertToAbsolute(svgPath);} } 請爲未來添加此修改。 非常感謝你! – 2014-12-20 21:24:46
這是JSFiddle上的正確示例 http://jsfiddle.net/Lee53kwr/27/ – 2014-12-20 21:27:26