| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494 |
- /*
- * GeoMap v0.5.2
- * https://github.com/x6doooo/GeoMap
- *
- * Copyright 2013 Dx. Yang
- * Released under the MIT license
- */
- (function($, undefined){
- var version = "0.5.2"
- var convertor_parse = {
- "formatPoint": function(p){
- return [
- (p[0] < -168.5 ? p[0] + 360 : p[0]) + 170,
- 90 - p[1]
- ];
- },
- "makePoint": function(p){
- var self = this,
- point = self.formatPoint(p),
- x = point[0],
- y = point[1];
- if(self.xmin > x) self.xmin = x;
- if(self.xmax < x) self.xmax = x;
- if(self.ymin > y) self.ymin = y;
- if(self.ymax < y) self.ymax = y;
- },
- "Point": function(coordinates){
- this.makePoint(coordinates);
- },
- "LineString": function(coordinates){
- var self = this,
- i = 0,
- len = coordinates.length;
- for( ; i < len; i++){
- self.makePoint(coordinates[i]);
- }
- },
- "Polygon": function(coordinates){
- var i = 0,
- len = coordinates.length;
- for(; i < len; i++){
- this.LineString(coordinates[i]);
- }
- },
- "MultiPoint": function(coordinates){
- var i = 0,
- len = coordinates.length;
- for(; i < len; i++){
- this.Point(coordinates[i]);
- }
- },
- "MultiLineString": function(coordinates){
- var i = 0,
- len = coordinates.length;
- for(; i < len; i++){
- this.LineString(coordinates[i]);
- }
- },
- "MultiPolygon": function(coordinates){
- var i = 0,
- len = coordinates.length;
- for(; i < len; i++){
- this.Polygon(coordinates[i]);
- }
- }
- };
- function parseSrcSize(json){
- var
- shapes = json.features,
- shapeType,
- shapeCoordinates,
- geometries,
- i, j,
- len, len2,
- val,
- shape;
- convertor_parse.xmin = 360;
- convertor_parse.xmax = 0;
- convertor_parse.ymin = 180;
- convertor_parse.ymax = 0;
- for(i = 0, len = shapes.length; i < len; i++){
- shape = shapes[i];
- if(shape.type == 'Feature'){
- pushApath(shape.geometry, shape);
- }else if(shape.type = 'GeometryCollection'){
- geometries = shape.geometries;
- for(j = 0, len2 = geometries.length; j < len2; j++){
- val = geometries[j];
- pushApath(val, val);
- }
- }
- }
- function pushApath(gm){
- shapeType = gm.type;
- shapeCoordinates = gm.coordinates;
- convertor_parse[shapeType](shapeCoordinates);
- }
- json.srcSize = {
- left: convertor_parse.xmin.toFixed(4) * 1,
- top: convertor_parse.ymin.toFixed(4) * 1,
- width: (convertor_parse.xmax - convertor_parse.xmin).toFixed(4) * 1,
- height: (convertor_parse.ymax - convertor_parse.ymin).toFixed(4) * 1
- };
- return json;
- }
- var convertor = {
- /*!Private
- 让阿拉斯加地区在地图右侧显示
- */
- "formatPoint": function(p){
- return [
- (p[0] < -168.5 ? p[0] + 360 : p[0]) + 170,
- 90 - p[1]
- ];
- },
- "makePoint": function(p){
- var self = this,
- point = self.formatPoint(p),
- x = (point[0] - convertor.offset.x) * convertor.scale.x,
- y = (point[1] - convertor.offset.y) * convertor.scale.y;
- return [x, y];
- },
- "Point": function(coordinates){
- coordinates = this.makePoint(coordinates);
- return coordinates.join(',');
- },
- "LineString": function(coordinates){
- var str = '',
- self = this,
- i = 0,
- len = coordinates.length,
- point;
- for( ; i < len; i++){
- point = self.makePoint(coordinates[i]);
- if(i == 0){
- str = 'M' + point.join(',');
- }else{
- str = str + 'L' + point.join(',');
- }
- }
- return str;
- },
- "Polygon": function(coordinates){
- var str = '',
- i = 0,
- len = coordinates.length;
- for(; i < len; i++){
- str = str + convertor.LineString(coordinates[i]) + 'z';
- }
- return str;
- },
- "MultiPoint": function(coordinates){
- var arr = [],
- i = 0,
- len = coordinates.length;
- for(; i < len; i++){
- arr.push(convertor.Point(coordinates[i]));
- }
- return arr;
- },
- "MultiLineString": function(coordinates){
- var str = '',
- i = 0,
- len = coordinates.length;
- for(; i < len; i++){
- str += convertor.LineString(coordinates[i]);
- }
- return str;
- },
- "MultiPolygon": function(coordinates){
- var str = '',
- i = 0,
- len = coordinates.length;
- for(; i < len; i++){
- str += convertor.Polygon(coordinates[i]);
- }
- return str;
- }
- };
- function json2path(json, obj){
- var
- shapes = json.features,
- shapeType,
- shapeCoordinates,
- str,
- geometries,
- pathArray = [],
- i, j,
- len, len2,
- val,
- shape;
- convertor.scale = null;
- convertor.offset = null;
- if((!obj.scale || !obj.offset) && !json.srcSize){
- parseSrcSize(json);
- }
- if(!obj.offset){
- obj.offset = {
- x: json.srcSize.left,
- y: json.srcSize.top
- };
- }else if(json.srcSize){
- obj.offset.x = json.srcSize.left + obj.config.offset.x;
- obj.offset.y = json.srcSize.top + obj.config.offset.y;
- }
- if(!obj.scale){
- var temx = obj.width / json.srcSize.width,
- temy = obj.height / json.srcSize.height;
- temx > temy ? temx = temy : temy = temx;
- temx = temy * 0.73;
- obj.scale = {
- x: temx,
- y: temy
- };
- }
- convertor.scale = obj.scale;
- convertor.offset = obj.offset;
- for(i = 0, len = shapes.length; i < len; i++){
- shape = shapes[i];
- if(shape.type == 'Feature'){
- pushApath(shape.geometry, shape);
- }else if(shape.type = 'GeometryCollection'){
- geometries = shape.geometries;
- for(j = 0, len2 = geometries.length; j < len2; j++){
- val = geometries[j];
- pushApath(val, val);
- }
- }
- }
- function pushApath(gm, shape){
- shapeType = gm.type;
- shapeCoordinates = gm.coordinates;
- str = convertor[shapeType](shapeCoordinates);
- pathArray.push({
- type: shapeType,
- path: str,
- properties: shape.properties,
- id: shape.id
- });
- }
- return pathArray;
- }
- var GeoMap = function(cfg){
- var self = this,
- defaultCfg = {
- container: 'body',
- offset: null,
- scale: null,
- mapStyle: {
- 'fill': '#fff',
- 'stroke': '#999',
- 'stroke-width': 0.7
- },
- background:'#fff',
- sideSize: 4
- };
- $.extend(true, defaultCfg, cfg);
- self.container = $(defaultCfg.container);
- self.offset = defaultCfg.offset;
- self.scale = defaultCfg.scale;
- if(self.container.length == 0){
- throw new Error('map container is not defined!');
- }
- self.width = defaultCfg.width || self.container.width();
- self.height = defaultCfg.height || self.container.height();
- self.canvas = new Raphael(self.container.get(0), self.width, self.height);
- self.shapes = self.canvas.set();
- self.config = defaultCfg;
- self.paths = null;
- };
- GeoMap.prototype = {
- clear: function(){
- this.offset = null;
- this.scale = null;
- this.shapes.remove();
- },
- load: function(json){
- this.paths = json2path(json, this);
- },
- render: function(){
- var self = this,
- shapes = self.shapes,
- paths = self.paths,
- canvas = self.canvas,
- config = self.config,
- style = config.mapStyle,
- aPath = null, i, len, currentPath;
- for(i = 0, len = paths.length; i < len; i++){
- currentPath = paths[i];
- if(currentPath.type == 'point' || currentPath.type == 'MultiPoint'){
- //TODO
- }else{
- aPath = canvas.path(currentPath.path).data({'properties': currentPath.properties, 'id': currentPath.id}).attr(style);
- }
- shapes.push(aPath);
- }
- },
- /*!
- 将平面上的一个点的坐标,转换成实际经纬度坐标
- */
- getGeoPosition: function(p){
- var self = this,
- x = p[0],
- y = p[1];
- x = x / self.scale.x + self.offset.x - 170;
- x = x > 180 ? x - 360 : x;
- y = 90 - (y / self.scale.y + self.offset.y);
- return [x, y];
- },
- geo2pos: function(p){
- var self = this;
- convertor.offset = self.offset;
- convertor.scale = self.scale;
- if(typeof p.x != 'number') p.x *= 1;
- if(typeof p.y != 'number') p.y *= 1;
- p = convertor.makePoint([p.x, p.y]);
- return p;
- },
- setPoint: function(p){
- // 点的默认样式
- var self = this,
- a = {
- "x": 0,
- "y": 0,
- "r": 1,
- "opacity": 0.5,
- "fill": "#238CC3",
- "stroke": "#238CC3",
- "stroke-width": 0,
- "stroke-linejoin": "round"
- };
- p = self.geo2pos(p);
- p = {x:p[0],y:p[1]};
- $.extend(true, a, p);
- return self.canvas.circle(p.x, p.y, a.r).attr(a);
- },
- drawLineByMapPoints: function(pointsArray){
- var str = '';
- var op = ''
- $.each(pointsArray, function(k, v){
- op = k == 0 ? 'M' : 'L';
- str += op + v.attrs.x + ',' + v.attrs.y;
- });
- return this.canvas.path(str);
- }
- };
- //TODO: heat map
- GeoMap.isPointInsidePath = function(pts, pt) {
- var i,
- j,
- k,
- n = pts.length,
- wn = 0;
- for(i = n-1, j = 0; j < n; i = j, j++) {
- k = (pt[0] - pts[i][1]) * (pts[j][2] - pts[i][2]) - (pts[j][1] - pts[i][1]) * (pt[1] - pts[i][2]);
- if((pt[1] >= pts[i][2] && pt[1] <= pts[j][2])||(pt[1] <= pts[i][2] && pt[1] >= pts[j][2])) {
- if( k < 0){
- wn++;
- }else if(k > 0){
- wn--;
- }else{
- if( (pt[1] <= pts[i][2] && pt[1] >= pts[j][2] && pt[0] <= pts[i][1] && pt[0] >= pts[j][1]) ||
- (pt[1] <= pts[i][2] && pt[1] >= pts[j][2] && pt[0] >= pts[i][1] && pt[0] <= pts[j][1]) ||
- (pt[1] >= pts[i][2] && pt[1] <= pts[j][2] && pt[0] <= pts[i][1] && pt[0] >= pts[j][1]) ||
- (pt[1] >= pts[i][2] && pt[1] <= pts[j][2] && pt[0] >= pts[i][1] && pt[0] <= pts[j][1]) ){
- return 0; //点在多边形边界上
- }
- }
- }
- }
- if(wn == 0){
- return 1; //点在多边形外部
- }else{
- return -1; //点在多边形内部
- }
- };
- //计算耗时较长
- GeoMap.prototype.mosaic = function(proc) { // proc => 是否使用worker线程
- var self = this,
- shapes = self.shapes,
- paths = self.paths,
- canvas = self.canvas,
- config = self.config,
- style = config.mapStyle,
- offset = self.offset,
- scale = self.scale,
- background = config.background,
- width = self.width,
- height = self.height,
- mapleft = convertor.xmin,
- maptop = convertor.ymin,
- mapwidth = convertor.xmax - convertor.xmin,
- mapheight = convertor.ymax - convertor.ymin,
- aPath = null,
- sideSize = config.sideSize,
- halfSide = sideSize / 2,
- back, i, len, currentPath;
- for (i = 0, len = paths.length; i < len; i++) {
- currentPath = paths[i];
- if (currentPath.type == 'point' || currentPath.type == 'MultiPoint') {
- //TODO
- } else {
- aPath = canvas.path(currentPath.path).data({
- 'ps': currentPath.path,
- 'properties': currentPath.properties,
- 'id': currentPath.id
- }).attr({
- 'fill': background,
- 'stroke-width': 0
- });
- }
- shapes.push(aPath);
- }
- var arrPos = [],
- bbox,
- startX,
- startY,
- i,
- j,
- temX,
- temY;
- $.each(shapes, function(k, v){
- bbox = v.getBBox();
- startX = ~~( (bbox.x - halfSide) / sideSize ) * sideSize;
- startY = ~~( (bbox.y- halfSide) / sideSize ) * sideSize;
- for(i = 0; i * sideSize + startX <= bbox.x2; i++){
- temX = i * sideSize + startX;
- for(j = 0; j * sideSize + startY <= bbox.y2; j++){
- temY = j * sideSize + startY;
- if(GeoMap.isPointInsidePath(v.attrs.path, [temX, temY]) != 1){
- arrPos.push([temX, temY]);
- }
- }
- }
-
- });
- arrPos.forEach(function(v){
- canvas.rect(v[0] - 1, v[1] - 1, sideSize * 0.8, sideSize * 0.8).attr(style);
- //.scale(scale.x, scale.y, offset.x, offset.y);
- });
- };
- GeoMap.version = version;
- this.GeoMap = GeoMap;
- })(jQuery);
|