geomap-0.4.3.js 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. /*
  2. * GeoMap v0.4.3
  3. * https://github.com/x6doooo/GeoMap
  4. *
  5. * Copyright 2013 Dx. Yang
  6. * Released under the MIT license
  7. */
  8. (function(){
  9. var version = "0.4.3"
  10. var convertor = {
  11. "xmin": 360,
  12. "xmax": 0,
  13. "ymin": 180,
  14. "ymax": 0,
  15. /*!Private
  16. 让阿拉斯加地区在地图右侧显示
  17. */
  18. "formatPoint": function(p){
  19. return [
  20. (p[0] < -168.5 ? p[0] + 360 : p[0]) + 170,
  21. 90 - p[1]
  22. ];
  23. },
  24. "makePoint": function(p){
  25. var self = this,
  26. point = self.formatPoint(p),
  27. x = point[0],
  28. y = point[1];
  29. if(self.xmin > x) self.xmin = x;
  30. if(self.xmax < x) self.xmax = x;
  31. if(self.ymin > y) self.ymin = y;
  32. if(self.ymax < y) self.ymax = y;
  33. return [x, y];
  34. },
  35. "Point": function(coordinates){
  36. coordinates = this.makePoint(coordinates);
  37. return coordinates.join(',');
  38. },
  39. "LineString": function(coordinates){
  40. var str = '',
  41. self = this,
  42. i = 0,
  43. len = coordinates.length,
  44. point;
  45. for( ; i < len; i++){
  46. point = self.makePoint(coordinates[i]);
  47. if(i == 0){
  48. str = 'M' + point.join(',');
  49. }else{
  50. str = str + 'L' + point.join(',');
  51. }
  52. }
  53. return str;
  54. },
  55. "Polygon": function(coordinates){
  56. var str = '',
  57. i = 0,
  58. len = coordinates.length;
  59. for(; i < len; i++){
  60. str = str + convertor.LineString(coordinates[i]) + 'z';
  61. }
  62. return str;
  63. },
  64. "MultiPoint": function(coordinates){
  65. var arr = [],
  66. i = 0,
  67. len = coordinates.length;
  68. for(; i < len; i++){
  69. arr.push(convertor.Point(coordinates[i]));
  70. }
  71. return arr;
  72. },
  73. "MultiLineString": function(coordinates){
  74. var str = '',
  75. i = 0,
  76. len = coordinates.length;
  77. for(; i < len; i++){
  78. str += convertor.LineString(coordinates[i]);
  79. }
  80. return str;
  81. },
  82. "MultiPolygon": function(coordinates){
  83. var str = '',
  84. i = 0,
  85. len = coordinates.length;
  86. for(; i < len; i++){
  87. str += convertor.Polygon(coordinates[i]);
  88. }
  89. return str;
  90. }
  91. };
  92. var GeoMap = function(cfg){
  93. var self = this,
  94. defaultCfg = {
  95. container: 'body',
  96. offset: null,
  97. scale: null,
  98. mapStyle: {
  99. 'fill': '#fff',
  100. 'stroke': '#999',
  101. 'stroke-width': 0.7
  102. },
  103. crossline:{
  104. enable: false,
  105. color: '#ccc'
  106. },
  107. background:'#fff'
  108. };
  109. $.extend(true, defaultCfg, cfg);
  110. self.container = $(defaultCfg.container);
  111. if(self.container.length == 0){
  112. throw new Error('map container is not defined!');
  113. }
  114. self.width = defaultCfg.width || self.container.width();
  115. self.height = defaultCfg.height || self.container.height();
  116. self.left = self.container.offset().left;
  117. self.top = self.container.offset().top;
  118. self.canvas = new Raphael(self.container.get(0), self.width, self.height);
  119. self.shapes = self.canvas.set();
  120. self.config = defaultCfg;
  121. self.paths = null;
  122. };
  123. GeoMap.prototype = {
  124. load: function(json){
  125. this.paths = this.json2path(json);
  126. },
  127. render: function(){
  128. var self = this,
  129. shapes = self.shapes,
  130. paths = self.paths,
  131. canvas = self.canvas,
  132. config = self.config,
  133. style = config.mapStyle,
  134. offset = config.offset,
  135. scale = config.scale,
  136. background = config.background,
  137. crossline = config.crossline,
  138. width = self.width,
  139. height = self.height,
  140. left = self.left + 5,
  141. top = self.top + 7,
  142. mapleft = convertor.xmin,
  143. maptop = convertor.ymin,
  144. mapwidth = convertor.xmax - convertor.xmin,
  145. mapheight = convertor.ymax - convertor.ymin,
  146. aPath = null, linehead, linex, liney, back, i, len, currentPath;
  147. if(!scale){
  148. var temx = width/mapwidth,
  149. temy = height/mapheight;
  150. temx > temy ? temx = temy : temy = temx;
  151. temx = temy * 0.73;
  152. scale = {
  153. x: temx,
  154. y: temy
  155. };
  156. }
  157. if(!offset){
  158. offset = {
  159. x: mapleft,
  160. y: maptop
  161. };
  162. }
  163. back = canvas.rect(mapleft, maptop, mapwidth, mapheight).scale(scale.x, scale.y, 0, 0).attr({
  164. 'fill': background, 'stroke-width': 0
  165. });
  166. linehead = 'M' + (mapleft) + ',' + (maptop);
  167. linex = linehead + 'H' + convertor.xmax * scale.x;
  168. liney = linehead + 'V' + convertor.ymax * scale.y;
  169. self.crosslineX = canvas.path(linex).attr({'stroke': crossline.color, 'stroke-width': '1px'}).hide();
  170. self.crosslineY = canvas.path(liney).attr({'stroke': crossline.color, 'stroke-width': '1px'}).hide();
  171. for(i = 0, len = paths.length; i < len; i++){
  172. currentPath = paths[i];
  173. if(currentPath.type == 'point' || currentPath.type == 'MultiPoint'){
  174. //TODO
  175. }else{
  176. aPath = canvas.path(currentPath.path).data({'properties': currentPath.properties, 'id': currentPath.id});
  177. }
  178. shapes.push(aPath);
  179. }
  180. canvas.setViewBox(offset.x, offset.y, width, height, false);
  181. shapes.attr(style).scale(scale.x, scale.y, mapleft, maptop);
  182. //TODO: crossline的位置计算,由于要做一点偏移,所以偏移量要考虑到缩放问题,类似getGeoPosition方法,计算出图上偏移的实际值
  183. if(crossline.enable === true){
  184. shapes.mouseover(function(){
  185. showCrossLine();
  186. }).mousemove(function(e){
  187. moveCrossLine(e);
  188. }).mouseout(function(){
  189. hideCrossLine();
  190. });
  191. back.mouseover(function(){
  192. showCrossLine();
  193. }).mousemove(function(e){
  194. moveCrossLine(e);
  195. }).mouseout(function(){
  196. hideCrossLine();
  197. });
  198. }
  199. function showCrossLine(){
  200. self.crosslineX.toFront().show();
  201. self.crosslineY.toFront().show();
  202. }
  203. function moveCrossLine(e){
  204. var pos = getEventPos(e);
  205. self.crosslineX.transform('T0,'+pos.y);
  206. self.crosslineY.transform('T'+ pos.x + ',0');
  207. }
  208. function hideCrossLine(){
  209. self.crosslineX.hide();
  210. self.crosslineY.hide();
  211. }
  212. function getEventPos(e){
  213. return {
  214. x: parseInt(e.pageX - left) + 0.4,
  215. y: parseInt(e.pageY - top) + 0.4
  216. };
  217. }
  218. },
  219. /*!
  220. 将平面上的一个点的坐标,转换成实际经纬度坐标
  221. */
  222. getGeoPosition: function(p){
  223. var x1 = p[0],
  224. y1 = p[1],
  225. m = this.shapes[0].matrix,
  226. x,
  227. y;
  228. a = m.a;
  229. b = m.b;
  230. c = m.c;
  231. d = m.d;
  232. e = m.e;
  233. f = m.f;
  234. y = (y1 - f - x1 / a * b + e / a * b) / (d - c / a * b);
  235. x = (x1 - e - y * c) / a;
  236. y = 90 - y;
  237. x = x - 170;
  238. x = x > 180 ? x - 360 : x;
  239. return [x, y];
  240. },
  241. setPoint: function(p){
  242. // 点的默认样式
  243. var self = this,
  244. a = {
  245. "x":0,
  246. "y":0,
  247. "r":1,
  248. "opacity":0.5,
  249. "fill": "#238CC3",
  250. "stroke": "#238CC3",
  251. "stroke-width": 0,
  252. "stroke-linejoin": "round"
  253. },
  254. matrixTrans = self.shapes[0].matrix;
  255. $.extend(true, a, p);
  256. p = convertor.makePoint([a.x, a.y]);
  257. //通过matrix去计算点变换后的坐标
  258. p[0] = matrixTrans.x(p[0], p[1]);
  259. p[1] = matrixTrans.y(p[0], p[1]);
  260. self.getGeoPosition(p);
  261. a.x = p[0];
  262. a.y = p[1];
  263. c = self.canvas.circle(p[0], p[1], a.r).attr(a);
  264. return c;
  265. },
  266. json2path: function(json){
  267. var self = this,
  268. shapes = json.features,
  269. shapeType,
  270. shapeCoordinates,
  271. str,
  272. geometries,
  273. pathArray = [],
  274. i, j,
  275. len, len2,
  276. val,
  277. shape;
  278. convertor.xmin = 360;
  279. convertor.xmax = 0;
  280. convertor.ymin = 180;
  281. convertor.ymax = 0;
  282. for(i = 0, len = shapes.length; i < len; i++){
  283. shape = shapes[i];
  284. if(shape.type == 'Feature'){
  285. pushApath(shape.geometry, shape);
  286. }else if(shape.type = 'GeometryCollection'){
  287. geometries = shape.geometries;
  288. for(j = 0, len2 = geometries.length; j < len2; j++){
  289. val = geometries[j];
  290. pushApath(val, val);
  291. }
  292. }
  293. }
  294. function pushApath(gm, shape){
  295. shapeType = gm.type;
  296. shapeCoordinates = gm.coordinates;
  297. str = convertor[shapeType](shapeCoordinates);
  298. pathArray.push({
  299. type: shapeType,
  300. path: str,
  301. properties: shape.properties,
  302. id: shape.id
  303. });
  304. }
  305. return pathArray;
  306. }
  307. };
  308. GeoMap.version = version;
  309. this.GeoMap = GeoMap;
  310. })();