貌似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