GPS/轨迹追踪、轨迹回放、围栏控制


折腾一个多月终于弄完了这个项目,起初都未曾接触GPS/轨迹追踪、轨迹回放、圈划围栏...等一些在百度地图或者Googel地图操作的一些业务,后端的业务相对来说简单点

cas单点登录,mongdb灵活的数据存储方式,ActiveMQ消息推送、Redis存储...

这篇的主要篇幅主要来讲述下项目中的一些地图上棘手的问题

接口测试数据:

1.GPS数据接收接口对于日期格式的转化


作为码农都知道Web接口传输的数据都是以Json的数据形式传输,日期格式不同是我们头疼的事情,当然要是我们自己给App端,云平台端...都喜欢直接点java.util.Date类型直接抛给对
方,当然作为接收方很反感这种以毫秒的形式
①org.springframework.web.bind.annotation.ResponseBody 这是我们用SpringMvc常用的一种转JSON的形式,常用业务中完全可以搞定
②com.alibaba.fastjson.annotation.JSONField 阿里巴巴的转JSON形式,起初对它并不有所偏好,后来写接口写多了,就慢慢喜欢上了

@ResponseBody 直接将我们所需要的数据格式封装起来直接转JSON返回
如:

  1 import java.io.Serializable;
  2 
  3 @SuppressWarnings("rawtypes")
  4 public class APIContent implements Serializable{
  5     /**
  6      * 
  7      */
  8     private static final long serialVersionUID = 2127409162712908650L;
  9     
 10     public APIContent(){}
 11     
 12     private Page page;
 13     
 14     private boolean ok=true;
 15     
 16     /**
 17      * 返回的数据包
 18      */
 19     private Object data;
 20     
 21     /**
 22      * 错误码,请查globs
 23      */
 24     private int code = ApiGlobals.SUCCESS;
 25     /**
 26      * 消息处理
 27      */
 28     private String msg;
 29     
 30     
 31     /**
 32      * 返回数据成功,设置数据。
 33      * @param data
 34      */
 35     public APIContent(Object data){
 36         this.data=data;
 37     }
 38     
 39     /**
 40      * 返回数据成功,设置数据。
 41      * @param data
 42      */
 43     public APIContent(Page page, Object data){
 44         this.page = page;
 45         this.data=data;
 46     }
 47     public APIContent(int code){
 48         this.code=code;
 49     }
 50     public Object getData() {
 51         return data;
 52     }
 53 
 54     public void setData(Object data) {
 55         this.data = data;
 56     }
 57 
 58     public int getCode() {
 59         return code;
 60     }
 61 
 62     public void setApiCode(int code){
 63         switch(code){
 64         case ApiCode.opt.DATA_REPEAT:
 65             setMsg("data is repeat! ");
 66             break;
 67         case ApiCode.opt.NOT_LOGIN:
 68             setMsg("please login first! ");
 69             break;
 70         case ApiCode.bug.INVAILD_PARAMS:
 71             setMsg("invaild params! ");
 72             break;
 73         case ApiCode.bug.NO_RESOURCE:
 74             setMsg("not exists resource! ");
 75             break;
 76         case ApiCode.bug.OPERATION:
 77             setMsg("operation falied! ");
 78             break;
 79         case ApiCode.bug.UNDEFINE_FUN:
 80             setMsg("unimplements function or version! ");
 81             break;    
 82         case ApiCode.fatal.ERR_SERVER:
 83             setMsg("server error! ");
 84             break;    
 85         case ApiCode.Login.INVAILD_PWD:
 86             setMsg("password is invalid! ");
 87         case ApiCode.Login.NOT_REGISTER:
 88             setMsg("not register user! ");
 89             break;    
 90         case ApiCode.BindDevice.DEVICE_HAS_BIND:
 91             setMsg("device has binded! ");
 92             break;    
 93         case ApiCode.BindDevice.INVAILD_PWD:
 94             setMsg("device password is invalid! ");
 95             break;    
 96         case ApiCode.BindDevice.NO_DEVICE:
 97             setMsg("device is not exists! ");
 98             break;    
 99         }
100         this.code=code;
101     }
102     
103     public boolean isOk() {
104         return ok;
105     }
106     public void setOk(boolean ok) {
107         this.ok = ok;
108     }
109     public void setCode(int code) {
110 
111         this.code = code;
112     }
113     
114     public Page getPage() {
115         return page;
116     }
117     public void setPage(Page page) {
118         this.page = page;
119     }
120     public String getMsg() {
121         return msg;
122     }
123     public void setMsg(String msg) {
124         this.msg = msg;
125     }
126     
127 }
View Code

将数据封装到date中然后标识状态码,提示信息返回


@JSONField 的处理有所不同的是,对于日期的处理以及返回形式都可改变
如:我们对日期格式的转化

@JSONField(name = "type")
private String mcTypeName; // 设备类型
@JSONField(name = "expireTime", format = "yyyy-MM-dd HH:mm:ss")
private Date expireTime;    //过期时间
@JSONField(name = "createTime", format = "yyyy-MM-dd HH:mm:ss")
private Date createTime;    //接入时间

返回数据处理 :自定义形式..仅作参考

1 Map<Class<?>, String[]> includes = new HashMap<Class<?>, String[]>();
2 includes.put(APIContent.class, new String[] { "code", "msg", "data" });
3 includes.put(HashMap.class, new String[] { "gps", "obd", "hb", "status", "bd", "gg", "geoname"});
4 includes.put(VOrganize.class, new String[] { "organizeName", "vehicles" });
5 includes.put(Vehicle.class, new String[] { "statusMap", "plateNum", "vechleName", "imei", "id", "vechleioc" });
6 includes.put(OBDProtocol.class, new String[] { "engineStatus", "speedAverage" });
7 includes.put(GPSProtocol.class, new String[] { "acc", "gpsTime", "latitude", "longitude" });
8 includes.put(HBProtocol.class, new String[] { "time" });
9 includes.put(Point.class, new String[] { "lat", "lng" });
View Code
  1 package com.jimi.commons.utils;
  2 
  3 import java.util.ArrayList;
  4 import java.util.Iterator;
  5 import java.util.List;
  6 import java.util.Map;
  7 import java.util.Map.Entry;
  8 
  9 import javax.servlet.ServletOutputStream;
 10 import javax.servlet.http.HttpServletResponse;
 11 
 12 import org.apache.commons.beanutils.PropertyUtils;
 13 import org.apache.commons.io.IOUtils;
 14 import org.apache.log4j.Logger;
 15 
 16 import com.alibaba.fastjson.serializer.JSONSerializer;
 17 import com.alibaba.fastjson.serializer.NameFilter;
 18 import com.alibaba.fastjson.serializer.PropertyFilter;
 19 import com.alibaba.fastjson.serializer.SerializeConfig;
 20 import com.alibaba.fastjson.serializer.SerializeWriter;
 21 import com.alibaba.fastjson.serializer.SerializerFeature;
 22 import com.alibaba.fastjson.serializer.SimpleDateFormatSerializer;
 23 import com.alibaba.fastjson.serializer.ValueFilter;
 24 import com.jimi.commons.vo.APIContent;
 25 
 26 
 27 /**
 28  * 转换JSON工具类
 29  * 
 30  */
 31 public class JsonUtils {
 32     private static Logger log = Logger.getLogger(JsonUtils.class);
 33     private final static String DATAS_FLAG = "\"data\":[]";
 34     private static boolean loaded = false;
 35     
 36     /**
 37      * 
 38      * @param object
 39      * @param includes
 40      * @return
 41      * @author chengxuwei
 42      * 
 43      */
 44     public static String toJson(Object object,Map<Class<?>,String[]> includes) {
 45         return toJson(object,includes,null,null);
 46     }
 47 
 48     /**
 49      * 
 50      * @param object
 51      * @param includes
 52      * @param alias
 53      * @return
 54      * @author chengxuwei
 55      */
 56     public static String toJson(Object object,Map<Class<?>,String[]> includes,Map<Class<?>,Map<String,String>> alias) {
 57         return toJson(object,includes,null,alias);
 58     }
 59     /**
 60      * 带包函,排出的序列化
 61      * @param object 被转对象
 62      * @param includes 类包函的属性
 63      * @param excludes 类排出的属性
 64      * @return
 65      * @author chengxuwei
 66      */
 67     public static String toJson(Object object,Map<Class<?>,String[]> includes,Map<Class<?>,String[]> excludes,Map<Class<?>,Map<String,String>> alias ) {
 68         SerializeWriter writer = new SerializeWriter();
 69         try{
 70             JSONSerializer serializer = new JSONSerializer(writer); 
 71             //序列化配置
 72 //            serializer.config(SerializerFeature.WriteNullNumberAsZero, true);
 73 //            serializer.config(SerializerFeature.WriteNullStringAsEmpty, true);
 74 //            serializer.config(SerializerFeature.WriteNullBooleanAsFalse, true);
 75 //            serializer.config(SerializerFeature.WriteNullListAsEmpty, true);
 76             //包括
 77             if(null!=includes&&includes.size()>0){
 78                 SimpleSerializerFilter filter = SimpleSerializerFilter.getIncludeFilter();
 79                 Iterator<Entry<Class<?>, String[]>> ite = includes.entrySet().iterator();
 80                 while(ite.hasNext()){
 81                     Entry<Class<?>, String[]> kv = ite.next();
 82                     filter.addFilterFields(kv.getKey(), kv.getValue());
 83                 }
 84                 serializer.getPropertyFilters().add(filter);
 85             }
 86             //排出
 87             if(null!=excludes&&excludes.size()>0){
 88                 SimpleSerializerFilter filter=SimpleSerializerFilter.getExcludesFilter();
 89                 Iterator<Entry<Class<?>, String[]>> ite = excludes.entrySet().iterator();
 90                 while(ite.hasNext()){
 91                     Entry<Class<?>, String[]> kv = ite.next();
 92                     filter.addFilterFields(kv.getKey(), kv.getValue());
 93                 }
 94                 serializer.getPropertyFilters().add(filter);
 95                 
 96             }
 97             //别名
 98             if(null!=alias&&alias.size()>0){
 99                 SimpleNameFilter filter=new SimpleNameFilter();
100                 filter.addAllAlias(alias);
101                 serializer.getNameFilters().add(filter);
102             }
103             //值过滤,Android,IOS终端需要空字符串为""空数字为0
104             serializer.getValueFilters().add(new ValueFilter(){
105                 public Object process(Object source, String name, Object value) {  
106                     if(null==value){
107                         try {
108                             Class clazz = PropertyUtils.getPropertyType(source, name);
109                             if(clazz.isAssignableFrom(String.class)){
110                                 value="";
111                             }else if(clazz.isAssignableFrom(Integer.class)){
112                                 value=0;
113                             }
114                         } catch (Exception e) {
115                             e.printStackTrace();
116                         }
117                     }
118 
119                     return value;  
120                 }  
121       
122             });
123             //write
124             serializer.write(object);
125             return     writer.toString();
126         }catch(Exception e){
127             log.error("to json string error", e);
128         }finally{
129             writer.close();
130         }
131         return null;
132     }
133     
134     /**
135      * 转为Json字串
136      * 
137      * @param object   转换数据对象
138      * @return Json字串
139      */
140     public static String toJson(Object object) {
141         return toJson(object, new String[0]);
142     }
143     
144     /**
145      * 转为Json字串
146      * 
147      * @param object   转换数据对象
148      * @param includes 包含属性数组
149      * @return Json字串
150      */
151     public static String toJson(Object object, String... includes) {
152         return toJson(object, includes, new String[0]);
153     }
154     
155     /**
156      * 转为Json字串
157      * 
158      * @param object   转换数据对象
159      * @param includes 包含属性数组
160      * @param excludes 不包含属性数组
161      * @return Json字串
162      */
163     public static String toJson(Object object, String[] includes, String[] excludes) {
164         return toJson(object, includes, excludes, null);
165     }
166     
167     /**
168      * 转为Json字串
169      * 
170      * 
171      * 属性名称转换
172      * 
173      * 对象A有两个属性:id和name
174      * 正常转换为Json字串为:{"id": 1001, "name":"测试数据"}
175      * 
176      * 定义属性名称转换:
177      * nameMap.put("id", "cid");
178      * 转换为Json字串为:{"cid": 1001, "name":"测试数据"}
179      * 
180      * @param object   转换数据对象
181      * @param includes 包含属性数组
182      * @param excludes 不包含属性数组
183      * @param aliasMap 属性别名map
184      * @return Json字串
185      */
186     @SuppressWarnings("rawtypes")
187     public static String toJson(Object object, String[] includes, String[] excludes, final Map<String, String> aliasMap) {
188         //属性过滤
189         PropertyFilter propertyFilter = null;
190         if ((includes != null && includes.length > 0) || (excludes != null && excludes.length > 0)) {
191             propertyFilter = new CustomPropertyFilter(includes, excludes);
192         }
193         
194         /**
195          * 属性名称转换
196          * 
197          * 对象A有两个属性:id和name
198          * 正常转换为Json字串为:{"id": 1001, "name":"测试数据"}
199          * 
200          * 定义属性名称转换:
201          * nameMap.put("id", "cid");
202          * 转换为Json字串为:{"cid": 1001, "name":"测试数据"}
203          */
204         NameFilter nameFilter = null;
205         
206         if (aliasMap != null && aliasMap.size() > 0) {
207             nameFilter = new NameFilter() {
208                 public String process(Object source, String name, Object value) {
209                     if (aliasMap.containsKey(name)) {
210                         return aliasMap.get(name);
211                     }
212                     return name;
213                 }
214             };
215         }
216         
217         StringBuffer sb = new StringBuffer(2048);
218         
219         try {
220             if (object instanceof APIContent) {
221                 APIContent apiContent = (APIContent) object;
222                 List list = null;
223                 if(apiContent.getData() instanceof List){
224                     list =(List)apiContent.getData();
225                     List nullList=new ArrayList();
226                     apiContent.setData(nullList);
227                 }
228                 sb.append(toJson4Detail(DATAS_FLAG, apiContent, list, propertyFilter, nameFilter));
229                 list = null;
230             }else {
231                 sb.append(toJSONString(object, propertyFilter, nameFilter));
232             }
233         } catch (Exception e) {
234             log.error("toJson错误:", e);
235         }
236         
237         return sb.toString();
238     }
239     
240     public static String escapeXml(String input) {
241         if (input != null) {
242             input = input.replaceAll("<", "&lt;").replaceAll(">", "&gt;");
243         }
244         return input;
245     }
246     
247     private static String toJSONString(Object object, SerializerFeature... features) {
248         return toJSONString(object, null, features);
249     }
250     
251     private static String toJSONString(Object object, PropertyFilter propertyFilter, SerializerFeature... features) {
252         return toJSONString(object, propertyFilter, null, features);
253     }
254     
255     private static String toJSONString(Object object, PropertyFilter propertyFilter, NameFilter nameFilter, SerializerFeature... features) {
256         SerializeWriter out = new SerializeWriter();
257         
258         try {
259             JSONSerializer serializer = new JSONSerializer(out);
260             for (SerializerFeature feature : features) {
261                 serializer.config(feature, true);
262             }
263             
264             serializer.config(SerializerFeature.WriteDateUseDateFormat, true);
265             //serializer.config(SerializerFeature.WriteTabAsSpecial, true);
266             serializer.config(SerializerFeature.DisableCircularReferenceDetect, true);
267             
268             if (propertyFilter != null) {
269                 serializer.getPropertyFilters().add(propertyFilter);
270             }
271             if (nameFilter != null) {
272                 serializer.getNameFilters().add(nameFilter);
273             }
274             
275             setSerializeConfig(serializer.getMapping());
276             
277             serializer.write(object);
278             
279             return out.toString();
280         } finally {
281             out.close();
282         }
283     }
284     
285     private static String toJson4Detail(String flag, Object data, Object list, PropertyFilter propertyFilter, NameFilter nameFilter) {
286         StringBuffer sb = new StringBuffer(2048);
287         
288         if (list == null) {
289             sb.append(toJSONString(data,propertyFilter, nameFilter));
290         } else {
291             sb.append(toJSONString(data));
292             int pos = sb.indexOf(flag);
293             if (pos != -1) {
294                 int end = pos + flag.length();
295                 int start = end - 2;
296                 sb.delete(start , end);
297                 sb.insert(start, toJSONString(list, propertyFilter, nameFilter));
298             }
299         }
300         
301         return sb.toString();
302     }
303     
304     private static void setSerializeConfig(SerializeConfig serializeConfig) {
305         if (!loaded) {
306             serializeConfig.put(java.sql.Date.class, new SimpleDateFormatSerializer("yyyy-MM-dd"));
307             loaded = true;
308         }
309     }
310 
311     
312  
313 }
View Code
 1 /*
 2      * public void returnJson2(HttpServletResponse response, Object object, String... includes) { returnJson2(response, getJson(object, includes)); }
 3      * 
 4      * public void returnJson2(HttpServletResponse response, Object object, String[] includes, String[] excludes) { returnJson2(response, getJson(object, includes, excludes)); }
 5      * 
 6      * public void returnJson2(HttpServletResponse response, String json) { returnJson(response, (HttpServletRequest) null, json); }
 7      */
 8     public void returnJson(HttpServletResponse response, HttpServletRequest request, String json) {
 9         try {
10             String contentType = "application/json; charset=UTF-8";
11             if (request != null) {
12                 String accept = request.getHeader("accept");
13                 if (accept != null && !accept.contains("json")) {
14                     contentType = "text/html; charset=UTF-8";
15                 }
16             }
17             response.setContentType(contentType);
18             response.getWriter().write(json);
19             response.getWriter().flush();
20         } catch (IOException e) {
21             if (logger.isErrorEnabled()) {
22                 logger.error("returnJson is error!", e);
23             }
24         }
25     }

 2.分段轨迹/轨迹追踪

(注:每次选取不同轨迹的时候先清除原先画的轨迹)

百度地图

 

谷歌地图

 

代码实现:

①值得注意的是GPS经纬度转化为百度经纬度和谷歌经纬度是不一样的
这里我做的算法处理
获取百度经纬度:通过GPS/(lat,lng)得到百度地图经纬度
获取谷歌地图经纬度:通过GPS/(lat,lng)得到百度地图经纬度,在将百度经纬度转化为谷歌地图经纬度
源码:(获取上诉接口数据...然后在做坐标处理)

Point.java

 1 public class Point {
 2 
 3     private double lat;// 纬度
 4     private double lng;// 经度
 5 
 6     public Point() {
 7     }
 8 
 9     public Point(double lng, double lat) {
10         this.lng = lng;
11         this.lat = lat;
12     }
13 
14     @Override
15     public boolean equals(Object obj) {
16         if (obj instanceof Point) {
17             Point bmapPoint = (Point) obj;
18             return (bmapPoint.getLng() == lng && bmapPoint.getLat() == lat) ? true
19                     : false;
20         } else {
21             return false;
22         }
23     }
24 
25     public double getLat() {
26         return lat;
27     }
28 
29     public void setLat(double lat) {
30         this.lat = lat;
31     }
32 
33     public double getLng() {
34         return lng;
35     }
36 
37     public void setLng(double lng) {
38         this.lng = lng;
39     }
40 
41     @Override
42     public String toString() {
43         return "Point [lat=" + lat + ", lng=" + lng + "]";
44     }
45 
46 }
View Code

经纬度转化算法

  1 public class CoordinateConversion {
  2     private static final double x_pi = 3.14159265358979324 * 3000.0 / 180.0;
  3 
  4     private static final double pi = 3.14159265358979324;  //元周率
  5     private static final double a = 6378245.0; //卫星椭球坐标投影到平面地图坐标系的投影因子。
  6     private static final double ee = 0.00669342162296594323; //ee: 椭球的偏心率。
  7 
  8     /**
  9      * gg_lat 纬度 
 10      * gg_lon 经度 
 11      * GCJ-02转换BD-09 Google地图经纬度转百度地图经纬度
 12      * */
 13     public static Point google_bd_encrypt(double gg_lat, double gg_lon) {
 14         Point point = new Point();
 15         double x = gg_lon, y = gg_lat;
 16         double z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * x_pi);
 17         double theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * x_pi);
 18         double bd_lon = z * Math.cos(theta) + 0.0065;
 19         double bd_lat = z * Math.sin(theta) + 0.006;
 20         point.setLat(bd_lat);
 21         point.setLng(bd_lon);
 22         return point;
 23     }
 24 
 25     /**
 26      * wgLat 纬度 
 27      * wgLon 经度 
 28      * BD-09转换GCJ-02 百度转google
 29      * */
 30     public static Point bd_google_encrypt(double bd_lat, double bd_lon) {
 31         Point point = new Point();
 32         double x = bd_lon - 0.0065, y = bd_lat - 0.006;
 33         double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi);
 34         double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);
 35         double gg_lon = z * Math.cos(theta);
 36         double gg_lat = z * Math.sin(theta);
 37         point.setLat(gg_lat);
 38         point.setLng(gg_lon);
 39         return point;
 40     }
 41     
 42     
 43     /**
 44      * wgLat 纬度 
 45      * wgLon 经度 
 46      * BD-09转换GCJ-02 百度转
 47      * */
 48     public static Point bd_google_baidu_encrypt(double bd_lat, double bd_lon) {
 49         Point point = new Point();
 50         point=wgs_gcj_encrypts(bd_lat,bd_lon);
 51         point=google_bd_encrypt(point.getLat(),point.getLng());
 52         return point;
 53     }
 54     
 55 
 56     /**
 57      * wgLat 纬度
 58      * wgLon 经度
 59      * WGS-84 到 GCJ-02 的转换(即 GPS 加偏)
 60      * */
 61     public static Point wgs_gcj_encrypts(double wgLat, double wgLon) {
 62         Point point = new Point();
 63         if (outOfChina(wgLat, wgLon)) {
 64             point.setLat(wgLat);
 65             point.setLng(wgLon);
 66             return point;
 67         }
 68         double dLat = transformLat(wgLon - 105.0, wgLat - 35.0);
 69         double dLon = transformLon(wgLon - 105.0, wgLat - 35.0);
 70         double radLat = wgLat / 180.0 * pi;
 71         double magic = Math.sin(radLat);
 72         magic = 1 - ee * magic * magic;
 73         double sqrtMagic = Math.sqrt(magic);
 74         dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
 75         dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
 76         double lat = wgLat + dLat;
 77         double lon = wgLon + dLon;
 78         point.setLat(lat);
 79         point.setLng(lon);
 80         return point;
 81     }
 82 
 83     public static void transform(double wgLat, double wgLon, double[] latlng) {
 84         if (outOfChina(wgLat, wgLon)) {
 85             latlng[0] = wgLat;
 86             latlng[1] = wgLon;
 87             return;
 88         }
 89         double dLat = transformLat(wgLon - 105.0, wgLat - 35.0);
 90         double dLon = transformLon(wgLon - 105.0, wgLat - 35.0);
 91         double radLat = wgLat / 180.0 * pi;
 92         double magic = Math.sin(radLat);
 93         magic = 1 - ee * magic * magic;
 94         double sqrtMagic = Math.sqrt(magic);
 95         dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
 96         dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
 97         latlng[0] = wgLat + dLat;
 98         latlng[1] = wgLon + dLon;
 99     }
100 
101     private static boolean outOfChina(double lat, double lon) {
102         if (lon < 72.004 || lon > 137.8347)
103             return true;
104         if (lat < 0.8293 || lat > 55.8271)
105             return true;
106         return false;
107     }
108 
109     private static double transformLat(double x, double y) {
110         double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y
111                 + 0.2 * Math.sqrt(Math.abs(x));
112         ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
113         ret += (20.0 * Math.sin(y * pi) + 40.0 * Math.sin(y / 3.0 * pi)) * 2.0 / 3.0;
114         ret += (160.0 * Math.sin(y / 12.0 * pi) + 320 * Math.sin(y * pi / 30.0)) * 2.0 / 3.0;
115         return ret;
116     }
117 
118     private static double transformLon(double x, double y) {
119         double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1
120                 * Math.sqrt(Math.abs(x));
121         ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
122         ret += (20.0 * Math.sin(x * pi) + 40.0 * Math.sin(x / 3.0 * pi)) * 2.0 / 3.0;
123         ret += (150.0 * Math.sin(x / 12.0 * pi) + 300.0 * Math.sin(x / 30.0
124                 * pi)) * 2.0 / 3.0;
125         return ret;
126     }
127 }

 

 

初始化原型地图通用模块

  1 <script type="text/javascript">
  2 var allMap;//公共的默认加载百度google地图
  3 var allMapType=$("#selectMap").val();
  4 if(allMapType=='googleMap'){
  5     initGoogleMap();
  6     
  7 }else{
  8     initBaiDuMap();//默认自动加载百度地图
  9     
 10 }
 11 
 12 //普通
 13 $("#selectMap").change(function(){
 14     var mapType=$(this).children('option:selected').val();//这就是selected的值 
 15     if(mapType=='googleMap'){
 16         initGoogleMap();
 17         
 18     }else{
 19         initBaiDuMap();
 20         
 21     }
 22     allMapType=mapType;
 23 });
 24 
 25 /***
 26 电子围栏切换
 27 $("#selectGeozoneMap").change(function(){
 28     var mapType=$(this).children('option:selected').val();//这就是selected的值 
 29     if(mapType=='googleMap'){
 30         initGoogleMap();//初始化google地图
 31         intoGoogleTools();//初始化google地图绘制工具
 32     }else{
 33         initBaiDuMap();//初始化百度地图
 34         intoBaiDuMapTools();//初始化百度地图绘制工具
 35     }
 36 });
 37 **/
 38 
 39 function initBaiDuMaps(){
 40     var myCity = new BMap.LocalCity();
 41     myCity.get(myCenterAndZoom); 
 42     function myCenterAndZoom(result){
 43         var cityName = result.name;
 44         //initBaiDuMaps(cityName);
 45     }
 46 }
 47 function initBaiDuMap(){
 48     // 百度地图API功能
 49     allMap= new BMap.Map("allmap"); // 创建Map实例 divID必须为allmap
 50     allMap.centerAndZoom(new BMap.Point(116.404, 39.915), 11); // 初始化地图,设置中心点坐标和地图级别
 51     allMap.addControl(new BMap.MapTypeControl()); //添加地图类型控件
 52     allMap.addControl(new BMap.NavigationControl());//设置导航条 (左上角,添加默认缩放平移控件)
 53     allMap.enableScrollWheelZoom(true); //开启鼠标滚轮缩放
 54     allMap.clearOverlays();
 55 }
 56 
 57 
 58 function initGoogleMap(){
 59     //Google地图API功能
 60     //纬度&经度
 61     var myCenter=new google.maps.LatLng(39.915,116.404);
 62     var mapProp = {
 63             center:myCenter,
 64             zoom:10,
 65             mapTypeId:google.maps.MapTypeId.ROADMAP
 66     };
 67     allMap = new google.maps.Map(document.getElementById("allmap"),mapProp);
 68 }
 69 
 70 
 71 //地图自动高度
 72 function  mapAutoHeight(){
 73     $("#allmap").height($(window).height() - $(".header").outerHeight() - $(".breadcrumb-func").outerHeight() - $(".footer").outerHeight());
 74 }
 75 mapAutoHeight();     
 76 $(window).resize(function(){
 77     mapAutoHeight();
 78 });
 79 
 80 //状态
 81 var icon_end                 = {icon:new BMap.Icon(_ctx+"/resource/images/36x43/end.png"              ,new BMap.Size(36,44)),offset:new BMap.Size(0,-22),imageOffset:new BMap.Size(0,-22)};
 82 var icon_start               = {icon:new BMap.Icon(_ctx+"/resource/images/36x43/start.png"            ,new BMap.Size(36,44)),offset:new BMap.Size(0,-22),imageOffset:new BMap.Size(0,-22)};
 83 var icon_gray_automobile     = {icon:new BMap.Icon(_ctx+"/resource/images/36x43/gray_automobile.png"  ,new BMap.Size(36,44)),offset:new BMap.Size(0,-22),imageOffset:new BMap.Size(0,-22)};
 84 var icon_gray_bus            = {icon:new BMap.Icon(_ctx+"/resource/images/36x43/gray_bus.png"         ,new BMap.Size(36,44)),offset:new BMap.Size(0,-22),imageOffset:new BMap.Size(0,-22)};
 85 var icon_gray_truck          = {icon:new BMap.Icon(_ctx+"/resource/images/36x43/gray_truck.png"       ,new BMap.Size(36,44)),offset:new BMap.Size(0,-22),imageOffset:new BMap.Size(0,-22)};
 86 var icon_green_automobile    = {icon:new BMap.Icon(_ctx+"/resource/images/36x43/green_automobile.png" ,new BMap.Size(36,44)),offset:new BMap.Size(0,-22),imageOffset:new BMap.Size(0,-22)};
 87 var icon_green_bus           = {icon:new BMap.Icon(_ctx+"/resource/images/36x43/green_bus.png"        ,new BMap.Size(36,44)),offset:new BMap.Size(0,-22),imageOffset:new BMap.Size(0,-22)};
 88 var icon_green_truck         = {icon:new BMap.Icon(_ctx+"/resource/images/36x43/green_truck.png"      ,new BMap.Size(36,44)),offset:new BMap.Size(0,-22),imageOffset:new BMap.Size(0,-22)};
 89 var icon_red_automobile      = {icon:new BMap.Icon(_ctx+"/resource/images/36x43/red_automobile.png"   ,new BMap.Size(36,44)),offset:new BMap.Size(0,-22),imageOffset:new BMap.Size(0,-22)};
 90 var icon_red_bus             = {icon:new BMap.Icon(_ctx+"/resource/images/36x43/red_bus.png"          ,new BMap.Size(36,44)),offset:new BMap.Size(0,-22),imageOffset:new BMap.Size(0,-22)};
 91 var icon_red_truck           = {icon:new BMap.Icon(_ctx+"/resource/images/36x43/red_truck.png"        ,new BMap.Size(36,44)),offset:new BMap.Size(0,-22),imageOffset:new BMap.Size(0,-22)};
 92 //0,离线; 1,在线静止; 2,在线运动.
 93 var vechleIconMap=
 94 {
 95     '0_bus'        :icon_gray_bus           ,
 96     '1_bus'        :icon_red_bus            ,
 97     '2_bus'        :icon_green_bus          ,
 98     '0_automobile' :icon_gray_automobile    ,
 99     '1_automobile' :icon_red_automobile     ,
100     '2_automobile' :icon_green_automobile   ,
101     '0_truck'      :icon_gray_truck         ,
102     '1_truck'      :icon_red_truck          ,
103     '2_truck'      :icon_green_truck
104 };
105 
106 var gicon_end                 = {url:_ctx+"/resource/images/36x43/end.png"              ,size:new google.maps.Size(36,44),origin:new google.maps.Point(0,0),anchor:new google.maps.Point(18,44)};
107 var gicon_start               = {url:_ctx+"/resource/images/36x43/start.png"            ,size:new google.maps.Size(36,44),origin:new google.maps.Point(0,0),anchor:new google.maps.Point(18,44)};
108 var gicon_gray_automobile     = {url:_ctx+"/resource/images/36x43/gray_automobile.png"  ,size:new google.maps.Size(36,44),origin:new google.maps.Point(0,0),anchor:new google.maps.Point(18,44)};
109 var gicon_gray_bus            = {url:_ctx+"/resource/images/36x43/gray_bus.png"         ,size:new google.maps.Size(36,44),origin:new google.maps.Point(0,0),anchor:new google.maps.Point(18,44)};
110 var gicon_gray_truck          = {url:_ctx+"/resource/images/36x43/gray_truck.png"       ,size:new google.maps.Size(36,44),origin:new google.maps.Point(0,0),anchor:new google.maps.Point(18,44)};
111 var gicon_green_automobile    = {url:_ctx+"/resource/images/36x43/green_automobile.png" ,size:new google.maps.Size(36,44),origin:new google.maps.Point(0,0),anchor:new google.maps.Point(18,44)};
112 var gicon_green_bus           = {url:_ctx+"/resource/images/36x43/green_bus.png"        ,size:new google.maps.Size(36,44),origin:new google.maps.Point(0,0),anchor:new google.maps.Point(18,44)};
113 var gicon_green_truck         = {url:_ctx+"/resource/images/36x43/green_truck.png"      ,size:new google.maps.Size(36,44),origin:new google.maps.Point(0,0),anchor:new google.maps.Point(18,44)};
114 var gicon_red_automobile      = {url:_ctx+"/resource/images/36x43/red_automobile.png"   ,size:new google.maps.Size(36,44),origin:new google.maps.Point(0,0),anchor:new google.maps.Point(18,44)};
115 var gicon_red_bus             = {url:_ctx+"/resource/images/36x43/red_bus.png"          ,size:new google.maps.Size(36,44),origin:new google.maps.Point(0,0),anchor:new google.maps.Point(18,44)};
116 var gicon_red_truck           = {url:_ctx+"/resource/images/36x43/red_truck.png"        ,size:new google.maps.Size(36,44),origin:new google.maps.Point(0,0),anchor:new google.maps.Point(18,44)};
117 
118 //0,离线; 1,在线静止; 2,在线运动.
119 var gvechleIconMap=
120 {
121     '0_bus'        :gicon_gray_bus           ,
122     '1_bus'        :gicon_red_bus            ,
123     '2_bus'        :gicon_green_bus          ,
124     '0_automobile' :gicon_gray_automobile    ,
125     '1_automobile' :gicon_red_automobile     ,
126     '2_automobile' :gicon_green_automobile   ,
127     '0_truck'      :gicon_gray_truck         ,
128     '1_truck'      :gicon_red_truck          ,
129     '2_truck'      :gicon_green_truck
130 };
131 
132 </script>

轨迹分段Map.js

  1 //获取所有点的坐标
  2 
  3 var label; //信息标签
  4 var centerPoint;
  5 var selfAll;
  6 
  7 var startIcon=_ctx+"/resource/images/36x43//start.png";//
  8 var startMaker;//起点
  9 var startLable;
 10 var startPoint;
 11 
 12 var endIcon=_ctx+"/resource/images/36x43/end.png";//
 13 var endLable;//终点
 14 var endMaker;
 15 var endPoint;
 16 
 17 var points=[];
 18 //Googel
 19 var map;
 20 
 21 //选择加载
 22 $("#selectMap").change(function(){
 23     var mapType=$(this).children('option:selected').val();//这就是selected的值 
 24     if(mapType=='googleMap'){
 25         initGoogleMap();
 26     }else{
 27         initBaiDuMap();
 28     }
 29     allMapType=mapType;
 30     getPointAtMap();
 31 });
 32 
 33 
 34 //选择路段信息
 35 function getPointAtMap(startTime,endTime,imei){
 36     points.splice(0, points.length);   //清除记录
 37     $.ajax({
 38         type:"post",
 39         url:_ctx+"/drivingrecord/getPonitAtMap",
 40         async: false,
 41         cache: false,
 42         data:{"startTime":startTime,"endTime":endTime,"imei":imei,"selectMap":allMapType}, 
 43         dataType: 'json',
 44         success:function(returnData){
 45             if(returnData.code==0){
 46                 if(allMapType == 'googleMap'){
 47                     $.each(returnData.data,function(n,value){
 48                         points.push(new google.maps.LatLng(value.lat, value.lng));
 49                     });
 50                     initgoogel();
 51                 }else{
 52                     allMap.clearOverlays();
 53                     $.each(returnData.data,function(n,value){
 54                         points.push(new BMap.Point(value.lng, value.lat));
 55                     });
 56                     initbaidu();
 57                 }
 58             }else{
 59                 layer.msg("该时间段无行驶记录");
 60                 allMap.clearOverlays();
 61                 initbaidu();
 62             }
 63         }
 64     });
 65 }
 66 
 67 function initbaidu() {
 68     //初始化地图,选取第一个点为起始点
 69     allMap.centerAndZoom(points[0], 15);
 70 
 71     centerPoint = new BMap.Point((points[0].lng + points[points.length - 1].lng) / 2, (points[0].lat + points[points.length - 1].lat) / 2);
 72     allMap.panTo(centerPoint);
 73     //连接所有点
 74     allMap.addOverlay(new BMap.Polyline(points, {strokeColor: "#00cc00", strokeWeight: 5, strokeOpacity: 1}));
 75 
 76     //显示起点
 77     startLable = new BMap.Label("", {offset: new BMap.Size(-35,-35)});
 78     //car = new BMap.Marker(points[0], {icon: new BMap.Icon(iconImg, new BMap.Size(48, 48), {imageOffset: new BMap.Size(0, 0)})});
 79     startPoint=points[0];
 80     startMaker = new BMap.Marker(startPoint, {icon: new BMap.Icon(startIcon, new BMap.Size(48,48)),offset: new BMap.Size(2,-20),imageOffset: new BMap.Size(0,-20)});
 81     //startMaker.setLabel(startLable);
 82     allMap.addOverlay(startMaker);
 83     //显示终点
 84     endLable = new BMap.Label("", {offset: new BMap.Size(-35,-35)});
 85     //car = new BMap.Marker(points[0], {icon: new BMap.Icon(iconImg, new BMap.Size(48, 48), {imageOffset: new BMap.Size(0, 0)})});
 86     endPoint=points[points.length-1];
 87     endMaker = new BMap.Marker(endPoint, {icon: new BMap.Icon(endIcon, new BMap.Size(48,48)),offset: new BMap.Size(2,-20),imageOffset: new BMap.Size(0,-20)});
 88     //endMaker.setLabel(endLable);
 89     allMap.addOverlay(endMaker);
 90 }
 91 
 92 //初始化谷歌地图
 93 function initgoogel(){
 94     var indexCenter=points.length/2;
 95     indexCenter=indexCenter>>0;
 96     
 97     var mapOptions = {
 98             zoom: 14,             //缩放级别
 99             center: points[indexCenter],
100             panControl: true,
101             zoomControl: true,
102             mapTypeControl: true,
103             scaleControl: true,
104             overviewMapControl: true,
105             mapTypeId: google.maps.MapTypeId.ROADMAP
106     };
107     map = new google.maps.Map(document.getElementById('allmap'),mapOptions);
108     var lineSymbol = {
109             //travelMode: google.maps.DirectionsTravelMode.DRIVING,
110             path: google.maps.SymbolPath.FORWARD_CLOSED_ARROW,
111             scale: 2,
112             strokeColor: '#0000',
113             strokeOpacity: 1.0,    // 透明度
114             strokeWeight: 2,    // 宽度
115             strokeOpacity : 0.8,
116             fillColor : "#0000",
117             fillOpacity : 0.4
118     };
119     line = new google.maps.Polyline({
120         path: points,
121         icons: [{
122             icon: lineSymbol,
123             offset: '1%'
124         }],
125         strokeColor: '#418f02',
126         //travelMode: google.maps.DirectionsTravelMode.DRIVING, 
127         map: map
128     });
129     linePath=line.getPath();
130     new google.maps.Marker(
131             {
132                 position: points[0],
133                 icon:startIcon,
134                 map: map 
135             }
136 
137     );
138     new google.maps.Marker(
139             {
140                 position: points[points.length - 1],
141                 icon:endIcon,
142                 map: map 
143             }
144     );
145     
146 }

注:

① 我们都知道纬度的范围是南北纬0-90°,经度的范围是东西经0-180°

百度地图:对应点经纬度先填纬度,后天经度(开始没有仔细看百度API被坑了许久)

points.push(new BMap.Point(value.lng, value.lat));

谷歌地图:经纬度正常

points.push(new google.maps.LatLng(value.lat, value.lng));

②对起始位置,终点位置的修饰以及轨迹的修饰

其实原理都相通,我们描画地图上的坐标,都是通过逐个坐标点来控制,确定起始,终点坐标,自定义类型

如:

百度地图~

//初始化地图,选取第一个点为起始点
allMap.centerAndZoom(points[0], 15);
//连接所有点
allMap.addOverlay(new BMap.Polyline(points, {strokeColor: "#00cc00", strokeWeight: 5, strokeOpacity: 1}));
//显示起点
startLable = new BMap.Label("", {offset: new BMap.Size(-35,-35)});
//car = new BMap.Marker(points[0], {icon: new BMap.Icon(iconImg, new BMap.Size(48, 48), {imageOffset: new BMap.Size(0, 0)})});
startPoint=points[0];
startMaker = new BMap.Marker(startPoint, {icon: new BMap.Icon(startIcon, new BMap.Size(48,48)),offset: new BMap.Size(2,-20),imageOffset: new BMap.Size(0,-20)});
//显示终点
endLable = new BMap.Label("", {offset: new BMap.Size(-35,-35)});
//car = new BMap.Marker(points[0], {icon: new BMap.Icon(iconImg, new BMap.Size(48, 48), {imageOffset: new BMap.Size(0, 0)})});
endPoint=points[points.length-1];
endMaker = new BMap.Marker(endPoint, {icon: new BMap.Icon(endIcon, new BMap.Size(48,48)),offset: new BMap.Size(2,-20),imageOffset: new BMap.Size(0,-20)});
//endMaker.setLabel(endLable);
allMap.addOverlay(endMaker);

(当然这里值得一提的中点位置,不是终点是中点,当时围栏显示轨迹中心位置所取的一个点,每种地图都要设置一个中心点)

即取起始位置和终点位置的中点就OK了~有点逻辑头脑的都可以接收

 

开始做百度地图的时候有点棘手,毕竟先前没有接触过,后来做谷歌地图的时候,就灵活点了~

起点,终点 (确定坐标位置就OK了,我们是把所有坐标放到数组上的,当前后面的操作就SO easy啦)

new google.maps.Marker(
            {
                position: points[0],
                icon:startIcon,
                map: map 
            }

    );
new google.maps.Marker(
            {
                position: points[points.length - 1],
                icon:endIcon,
                map: map 
            }
    );

③百度经纬度,谷歌经纬度转当前地理位置

百度地图:

 

谷歌地图:

 

  1 /** 假数据测试 * */
  2 var label; // 信息标签
  3 var centerPoint;
  4 var selfAll;
  5 
  6 var cars; // 汽车图标
  7 var cariconImg = _ctx + "/resource/images/36x43/green_automobile.png";//
  8 //var cariconImg=icon_green_automobile;//
  9 var carlabel; // 信息标签
 10 var carcenterPoint;
 11 
 12 var startIcon = _ctx + "/resource/images/36x43//start.png";//
 13 var startMaker;// 起点
 14 var startLable;
 15 var startPoint;
 16 
 17 var endIcon = _ctx + "/resource/images/36x43/end.png";//
 18 var endLable;// 终点
 19 var endMaker;
 20 var endPoint;
 21 
 22 var timer; // 定时器
 23 var index = 0; // 记录播放到第几个point
 24 
 25 var points = []; // 坐标
 26 var gpsSpeeds = []; // 时速
 27 var gpsTimes = []; // 时间
 28 
 29 //Googel
 30 var map;
 31 var linePath;
 32 
 33 //默认加载
 34 var allMapType = $("#selectMap").val();
 35 if (allMapType == 'googleMap') {
 36     initGoogleMap(); // 加载Googel地图
 37 }else{
 38     initBaiDuMap(); // 默认自动加载百度地图
 39     initPiont();
 40 }
 41 
 42 //选择加载
 43 $("#selectMap").change(function(){
 44     var mapType=$(this).children('option:selected').val();//这就是selected的值 
 45     if(mapType=='googleMap'){
 46         initGoogleMap();
 47         initPiont();
 48     }else{
 49         initBaiDuMap();
 50         initPiont();
 51     }
 52     allMapType=mapType;
 53 });
 54 
 55 
 56 //加载百度地图上的点
 57 function initPiont() {
 58     points.splice(0, points.length);   //清除记录
 59     var startTime = $("#startTime").val();
 60     var endTime = $("#endTime").val();
 61     var imei = $("#imei").val();
 62     if (startTime != "" && startTime != "" && imei != "") {
 63         $.ajax({
 64             type : "post",
 65             url : _ctx + "/trackreplay/initPiont",
 66             async : false,
 67             cache : false,
 68             data : {"startTime":startTime,"endTime":endTime,"imei":imei,"selectMap":allMapType},
 69             dataType : 'json',
 70             success : function(returnData){
 71                 if (returnData.code == 0){
 72                     if (returnData.data != null){
 73                         if(allMapType == 'googleMap'){
 74                             $.each(returnData.data,function(n,value){
 75                                 points.push(new google.maps.LatLng(value.lat, value.lng));
 76                                 gpsSpeeds.push(value.gpsSpeed);
 77                                 gpsTimes.push(value.CurrentTime);
 78                             });
 79                             initGoogel();
 80                         }else{
 81                             $.each(returnData.data,function(n,value){
 82                                 points.push(new BMap.Point(value.lng, value.lat));
 83                                 gpsSpeeds.push(value.gpsSpeed);
 84                                 gpsTimes.push(value.CurrentTime);
 85                             });
 86                             initBaiDuMap();// 默认自动加载百度地图
 87                             initBaidu();
 88                         }
 89                         $("#gpsTime").text(gpsTimes[0]);
 90                         $("#gpsSpeed").text(gpsSpeeds[0]);
 91                     }else{
 92                         layer.msg("该时间段无行驶记录");
 93                         initBaiDuMap();// 默认自动加载百度地图
 94                         initBaidu();
 95                     }
 96                 }
 97             }
 98         });
 99     }
100 }
101 //初始化百度地图
102 function initBaidu() {
103     // 初始化地图,选取第一个点为起始点
104     allMap.centerAndZoom(points[0], 15);
105 
106     var driving = new BMap.DrivingRoute(allMap);
107 
108     centerPoint = new BMap.Point(
109             (points[0].lng + points[points.length - 1].lng) / 2,
110             (points[0].lat + points[points.length - 1].lat) / 2
111     );
112     allMap.panTo(centerPoint);
113     // 连接所有点
114     allMap.addOverlay(
115             new BMap.Polyline(
116                     points, 
117                     {
118                         strokeColor : "#00cc00",
119                         strokeWeight : 5,
120                         strokeOpacity : 1
121                     }
122             )
123     );
124 
125     //Start
126     startLable = new BMap.Label(
127             "", 
128             {
129                 offset : new BMap.Size(-35, -35)
130             }
131     );
132     startPoint = points[0];
133     startMaker = new BMap.Marker(
134             startPoint, 
135             {
136                 icon : new BMap.Icon(startIcon, new BMap.Size(48, 48)),
137                 offset : new BMap.Size(2, -20),
138                 imageOffset : new BMap.Size(0, -20)
139             }
140     );
141     // startMaker.setLabel(startLable);
142     allMap.addOverlay(startMaker);
143     //Car
144     carlabel = new BMap.Label(
145             "", 
146             {
147                 offset : new BMap.Size(-35, -35)
148             }
149     );
150     carcenterPoint = points[0];
151     cars = new BMap.Marker(
152             carcenterPoint, 
153             {
154                 icon : new BMap.Icon(cariconImg, new BMap.Size(48, 48)),
155                 offset : new BMap.Size(2, -20),
156                 imageOffset : new BMap.Size(0, -20)
157             }
158     );
159     allMap.addOverlay(cars);
160     //End
161     endLable = new BMap.Label("", {offset : new BMap.Size(-35, -35)});
162     endPoint = points[points.length - 1];
163     endMaker = new BMap.Marker(
164             endPoint, 
165             {
166                 icon : new BMap.Icon(endIcon, new BMap.Size(48, 48)),
167                 offset : new BMap.Size(2, -20),
168                 imageOffset : new BMap.Size(0, -20)
169             }
170     );
171     allMap.addOverlay(endMaker);
172 }
173 
174 //初始化谷歌地图
175 function initGoogel(){
176     var indexCenter=points.length/2;
177     indexCenter=indexCenter>>0;
178     var mapOptions = {
179             zoom: 14,             //缩放级别
180             center: points[indexCenter],
181             panControl: true,
182             zoomControl: true,
183             mapTypeControl: true,
184             scaleControl: true,
185             overviewMapControl: true,
186             mapTypeId: google.maps.MapTypeId.ROADMAP
187     };
188     map = new google.maps.Map(document.getElementById('allmap'),mapOptions);
189     var lineSymbol = {
190             //travelMode: google.maps.DirectionsTravelMode.DRIVING,
191             path: google.maps.SymbolPath.FORWARD_CLOSED_ARROW,
192             scale: 2,
193             strokeColor: '#0000',
194             strokeOpacity: 1.0,    // 透明度
195             strokeWeight: 2,    // 宽度
196             strokeOpacity : 0.8,
197             fillColor : "#0000",
198             fillOpacity : 0.4
199     };
200     line = new google.maps.Polyline({
201         path: points,
202         icons: [{
203             icon: lineSymbol,
204             offset: '1%'
205         }],
206         strokeColor: '#418f02',
207         //travelMode: google.maps.DirectionsTravelMode.DRIVING, 
208         map: map
209     });
210     linePath=line.getPath();
211     new google.maps.Marker(
212             {
213                 position: points[0],
214                 icon:startIcon,
215                 map: map 
216             }
217 
218     );
219     new google.maps.Marker(
220             {
221                 position: points[points.length - 1],
222                 icon:endIcon,
223                 map: map 
224             }
225     );
226 }
227 
228 
229 var timer; // 定时器
230 var index = 0; // 记录播放到第几个point
231 var statue = true; // 默认停止
232 
233 var count = 0;
234 
235 function Operate() {
236     $("#paly").parent().toggleClass("pause");
237     if (statue) {
238         statue = false;
239         play();
240     } else {
241         statue = true;
242         pause();
243     }
244 }
245 var marker = null;  
246 
247 function play() {
248     var timeat = $("#palyTime").val();
249     var point = points[index];
250     var speed = gpsSpeeds[index];
251     var time = gpsTimes[index];
252     timeat = 1000 - timeat;
253     if(allMapType == 'googleMap'){   //Googel
254         var geocoder = new google.maps.Geocoder();
255         geocoder.geocode({'latLng': point}, function(results, status) {  
256             if (status == google.maps.GeocoderStatus.OK) {  
257                 if (results[0]) {
258                     var address=results[0].formatted_address;
259                     var sindex=address.indexOf("邮政编码");
260                     if(sindex>0){
261                         $("#address").text(address.substring(0,sindex));
262                     }else{
263                         $("#address").text(address);
264                     }
265                     
266                 }
267             }});
268         map.panTo(point);
269         if(index < points.length){
270             index++;
271             if (!marker){  
272                 marker = new google.maps.Marker(
273                         { 
274                             position: points[index], 
275                             icon:cariconImg,
276                             map: map 
277                         });  
278             }else{  
279                 if(index < points.length){  
280                     marker.setPosition(points[index]);  
281                 }else{  
282                     map.panTo(point);
283                 }  
284             }
285             timer = window.setTimeout("play(" + index + ")", timeat);
286         }        
287     }else{   //baidu
288         if (index > 0) {
289             allMap.addOverlay(
290                     new BMap.Polyline(
291                             [ points[index - 1], point ], 
292                             {
293                                 strokeColor : "red",
294                                 strokeWeight : 1,
295                                 strokeOpacity : 1
296                             }
297                     )
298             );
299         }
300         // 通过当前经纬度获取当前位置
301         var geoc = new BMap.Geocoder();
302         geoc.getLocation(point, function(rs) {
303             if (rs && rs.address)
304                 $("#address").text(rs.address);
305         });
306         cars.setPosition(point);
307         index++;
308         allMap.panTo(point);
309         if (index < points.length) {
310             timer = window.setTimeout("play(" + index + ")", timeat);
311         } else {
312             allMap.panTo(point);
313         }
314     }
315     $("#gpsTime").text(time);
316     $("#gpsSpeed").text(speed);
317 }
318 
319 function pause() {
320     if (timer) {
321         window.clearTimeout(timer);
322     }
323 }
324 
325 function reset() {
326     if (timer) {
327         window.clearTimeout(timer);
328     }
329     index = 0;
330     cars.setPosition(points[0]);
331     allMap.panTo(centerPoint);
332 
333     Operate();
334 
335 }
View Code

 围栏设置与控制

百度:

 

谷歌:

 

百度 JS

  1 //0:电子围栏,1:地标
  2 var flag = $("#flag").val();
  3 $(document).ready(function(){
  4     var allMapType=$("#selectGeozoneMap").val();
  5     if(allMapType=='googleMap'){
  6         $("#map-pin").hide();
  7         initGoogleMap();
  8         intoGoogleTools();//初始化google地图绘制工具
  9     }else{
 10         $("#map-pin").show();
 11         initBaiDuMap();//默认自动加载百度地图
 12         intoBaiDuMapTools();
 13         searchAddrTip();
 14     }
 15     
 16 });
 17 
 18 $("#selectGeozoneMap").change(function(){
 19     var mapType=$(this).children('option:selected').val();//这就是selected的值 
 20     if(mapType=='googleMap'){
 21         $("#map-pin").hide();
 22         initGoogleMap();//初始化google地图
 23         intoGoogleTools();//初始化google地图绘制工具
 24     }else{
 25         $("#map-pin").show();
 26         initBaiDuMap();//初始化百度地图
 27         intoBaiDuMapTools();//初始化百度地图绘制工具
 28     }
 29 });
 30 
 31 //多边形清除
 32 function initToDrawing(){
 33     //drawingManagerBaidu.setDrawingMode(BMAP_DRAWING_POLYGON);//默认进入地图开启画多边形
 34     clearAll();
 35     intoBaiDuMapTools();
 36 }
 37 
 38 
 39 /**
 40  * 百度绘制工具加载
 41  * */
 42 
 43 var baiduoverlays = [];
 44 function intoBaiDuMapTools(){
 45     allMap.removeEventListener("click", initToDrawing);
 46     //实例化鼠标绘制工具
 47     var drawingManagerBaidu = new BMapLib.DrawingManager(allMap, {
 48         isOpen: false, //是否开启绘制模式
 49         enableDrawingTool: true, //是否显示工具栏
 50         drawingToolOptions: {
 51             anchor: BMAP_ANCHOR_TOP_RIGHT, //位置
 52             //drawingModes: [BMAP_DRAWING_POLYGON,BMAP_DRAWING_CIRCLE],
 53             drawingModes: [BMAP_DRAWING_POLYGON],
 54             offset: new BMap.Size(150, 5), //偏离值
 55             scale: 0.8 //工具栏缩放比例
 56         },
 57         polygonOptions: {
 58             strokeColor : "#0000FF",
 59                strokeOpacity : 0.8,
 60                strokeWeight : 2,
 61                fillColor : "#FF0000",
 62             fillOpacity : 0.4,
 63                editable:false, //是否可以编辑
 64                draggable:false //是否可拖动    
 65         } //多边形的样式
 66     });
 67     drawingManagerBaidu.setDrawingMode(BMAP_DRAWING_POLYGON);//默认进入地图开启画多边形
 68     //添加鼠标绘制工具监听事件,用于获取绘制结果
 69     drawingManagerBaidu.addEventListener('overlaycomplete', overlaycomplete);
 70     var htmlcontent = '';
 71     var opts = '';
 72     var strName="围栏";
 73     if(flag != 0){
 74         strName="地标";
 75     }
 76     
 77     htmlcontent += '<div class="p-tb10">';
 78     htmlcontent += '<div>';
 79     htmlcontent += '<table>';
 80     htmlcontent += '<tr>';
 81     htmlcontent += '<td class="ta-r"><label><font color="#ff0000">*</font>&nbsp;名称:&nbsp;&nbsp;</label></td>';
 82     htmlcontent += '<td><input type="text" id="geoname" name="geoname" size="20"  placeholder="请输入'+strName+'标题" class="form-control" style="width:160px;" /></td>';
 83     htmlcontent += '</tr>';
 84     htmlcontent += '<tr>';
 85     htmlcontent += '<td class="ta-r p-t7"><label>描述:&nbsp;</label></td>';
 86     htmlcontent += '<td class="p-t7"><input type="text" id="description" name="description"  placeholder="请输入'+strName+'描述信息" class="form-control" size="50" style="width:160px;" /></td>';
 87     htmlcontent += '</tr>';
 88     htmlcontent += '<tr>';
 89     htmlcontent += '<td>&nbsp;</td>';
 90     htmlcontent += '<td  class="p-t7"><input type="submit" value="提交"  class="btn btn-primary btn-block" onclick="saveGoogleGeozoneInfo();"  /></td>';
 91     htmlcontent += '</tr>';
 92     htmlcontent += '</table>';
 93     htmlcontent += '</div>';
 94     htmlcontent += '</div>';
 95     opts = {
 96             width : 200,     // 信息窗口宽度
 97             height: 156,     // 信息窗口高度
 98             title : "创建"+strName , // 信息窗口标题
 99             enableMessage:false,//设置允许信息窗发送短息
100             message:htmlcontent
101     };
102     
103     
104     var infoWindow = new BMap.InfoWindow(htmlcontent,opts);  // 创建信息窗口对象 
105     
106     //回调获得覆盖物信息
107     function overlaycomplete(e){
108         drawingManagerBaidu.setDrawingMode(BMAP_DRAWING_POLYGON);//默认进入地图开启画多边形
109         baiduoverlays.push(e.overlay);
110         try{
111             var array= e.overlay.getPath();
112               showLonLat(array);
113         }catch(e){
114         }
115         //添加单击事件
116            allMap.addEventListener("click",initToDrawing);
117      }
118     //获取所画围栏点经纬度
119     function showLonLat(arr){
120           var info=""; 
121           for(var i=0; i<arr.length;i++){
122                //纬度&经度
123               info+="|("+arr[i].lat+","+arr[i].lng+")";
124           }
125           var coors=info.substring(1);
126           var str="多边形节点数:" + (arr.length) + "&nbsp;节点坐标:"+info;
127           //document.getElementById('mapinfo').innerHTML = "手动绘制多边形节点数:" + arr.length + "<br>节点坐标:"+info;
128           console.log("overlaycomplete:"+str);
129           var falgs=false;
130           var len=arr.length;
131           len=Number(len);
132           if(len>=3){
133               falgs=true;
134           }else{
135               intoBaiDuMapTools();
136               if(flag == 0){
137                   layer.msg('围栏为封闭的多边形!');
138               }else{
139                   layer.msg('地标为封闭的多边形!');
140               }
141              }
142           if(falgs){
143               $("#maptype").val("baidu");
144               $("#coors").val(coors);
145               var point = new BMap.Point(arr[0].lng,arr[0].lat);
146               allMap.openInfoWindow(infoWindow,point); //开启信息窗口
147           }
148       } 
149 }
150 
151 //清除围栏
152 function clearAll() {
153     for(var i = 0; i < baiduoverlays.length; i++){
154         allMap.removeOverlay(baiduoverlays[i]);
155         allMap.clearOverlays();
156    }
157     baiduoverlays.length = 0;
158  }

谷歌:

  1 //0:电子围栏,1:地标
  2 var flag = $("#flag").val();
  3 /**
  4  * Google绘制工具加载
  5  * */
  6 function intoGoogleTools(){
  7     //图形绘制工具控加载此AIP链接后面加上&libraries=drawing
  8     var drawingManager = new google.maps.drawing.DrawingManager({
  9             drawingMode: google.maps.drawing.OverlayType.POLYGON,
 10             drawingControl: true,
 11             drawingControlOptions: {
 12             position: google.maps.ControlPosition.TOP_CENTER,
 13             drawingModes: [
 14               //google.maps.drawing.OverlayType.MARKER,
 15               //google.maps.drawing.OverlayType.CIRCLE,
 16               google.maps.drawing.OverlayType.POLYGON, //仅使用多边形绘制工具
 17               //google.maps.drawing.OverlayType.POLYLINE,
 18              // google.maps.drawing.OverlayType.RECTANGLE
 19             ]
 20           },
 21           circleOptions: {
 22             strokeColor : "#0000FF",
 23             strokeOpacity : 0.8,
 24             strokeWeight : 2,
 25             fillColor : "#FF0000",
 26             fillOpacity : 0.4,
 27             editable:false, //是否可以编辑
 28             draggable:false //是否可拖动
 29             },
 30             polygonOptions: {//设置画线样式
 31               strokeColor: "#0000FF",  
 32               strokeOpacity: 0.8,  
 33               strokeWeight: 3,  
 34               fillColor: "#FF0000",  
 35               fillOpacity: 0.35,  
 36               editable: false 
 37               } 
 38         });
 39     drawingManager.setMap(allMap);
 40     
 41     //注册 多边形 绘制完成事件  
 42     var geozonePolygon = null;
 43     google.maps.event.addListener(drawingManager, 'polygoncomplete', function(polygon) {  
 44         drawingManager.setDrawingMode(null); //切换为选择模式
 45         geozonePolygon=polygon;
 46         showLonLat(polygon);
 47     });
 48     var htmlcontent = '';
 49     var strName="围栏";
 50     if(flag != 0){
 51         strName="地标";
 52     }
 53     
 54     htmlcontent += '<div class="p-t10 p-b5">';
 55     htmlcontent += '<div>';
 56     htmlcontent += '<table>';
 57     htmlcontent += '<tr>';
 58     htmlcontent += '<td class="ta-r"><label><font color="#ff0000">*</font>&nbsp;名称:&nbsp;&nbsp;</label></td>';
 59     htmlcontent += '<td><input type="text" id="geoname" name="geoname" size="20"  placeholder="请输入'+strName+'标题" class="form-control" style="width:160px;" /></td>';
 60     htmlcontent += '</tr>';
 61     htmlcontent += '<tr>';
 62     htmlcontent += '<td class="ta-r p-t7"><label>描述:&nbsp;</label></td>';
 63     htmlcontent += '<td class="p-t7"><input type="text" id="description" name="description"  placeholder="请输入'+strName+'描述信息" class="form-control" size="50" style="width:160px;" /></td>';
 64     htmlcontent += '</tr>';
 65     htmlcontent += '<tr>';
 66     htmlcontent += '<td>&nbsp;</td>';
 67     htmlcontent += '<td  class="p-t7"><input type="submit" value="提交"  class="btn btn-primary btn-block" onclick="saveGoogleGeozoneInfo();"  /></td>';
 68     htmlcontent += '</tr>';
 69     htmlcontent += '</table>';
 70     htmlcontent += '</div>';
 71     htmlcontent += '</div>';
 72 
 73     var infowindow = new google.maps.InfoWindow({
 74         content: htmlcontent,
 75         zIndex: 1000
 76     });
 77     //循环显示 经纬度  
 78     function showLonLat(polygon){
 79         var array= polygon.getPath().getArray();
 80         var paths = polygon.getPath();
 81         var geozone=""; 
 82         for(var i=0; i<array.length;i++){  
 83             geozone+="|"+array[i];
 84         };
 85         geozone=geozone.substring(1);
 86         //document.getElementById('mapinfo').innerHTML = "手动绘制多边形节点数:" + arr.length + "<br>节点坐标:"+info;
 87         var falg=false;
 88         var len=array.length;
 89         len=Number(len);
 90         if(len>=3){
 91             falg=true;
 92         }else{
 93             infowindow.setMap(null);
 94             geozonePolygon.setMap(null);
 95             drawingManager.setDrawingMode(google.maps.drawing.OverlayType.POLYGON);
 96             if(flag == 0){
 97                 layer.msg('围栏为封闭的多边形!');
 98             }else{
 99                 layer.msg('地标为封闭的多边形!');
100             }
101          }
102         if(falg){
103             $("#maptype").val("google");
104                 $("#coors").val(geozone);
105                 infowindow.setPosition(paths.getAt(0));
106                 infowindow.open(allMap);
107         }
108     }  
109     
110     //信息框弹出关闭
111     google.maps.event.addListener(infowindow,'closeclick', function() {
112         geozonePolygon.setMap(null);
113         drawingManager.setDrawingMode(google.maps.drawing.OverlayType.POLYGON);
114     });
115 
116     //点击地图页面
117     google.maps.event.addListener(allMap, 'click', function(event) {
118          infowindow.setMap(null);
119          geozonePolygon.setMap(null);
120          drawingManager.setDrawingMode(google.maps.drawing.OverlayType.POLYGON);
121     });
122 }
123 
124 
125 
126 
127 //弹框后输入围栏信息保存
128 function saveGoogleGeozoneInfo(){
129     var mapType=$("#maptype").val();
130     var coors=$("#coors").val();
131     var geoname=$("#geoname").val();
132     var description=$("#description").val();
133     ajaxMapFencingSave(mapType,coors,geoname,description);
134 }
135 
136 //围栏保存到后台  flag:0为电子围栏
137 var postSaveUrl=_ctx+"/geozone/editGeozone";
138 function ajaxMapFencingSave(mapType,coors,geoname,description){
139     if(geoname!=''){
140         $.ajax({
141             type:'POST',
142             url:postSaveUrl,
143             data:{"geom":coors,
144                 "mapType":mapType,
145                 "type":"polygon",
146                 "geoname":geoname,
147                 "description":description,
148                 "flag":flag},
149             dataType:'json',
150             success: function(rest){
151                 if(rest.ok){
152                     if(flag == 0){
153                         layer.msg('围栏设置成功!');
154                         window.location.href=_ctx+"/geozone/giveanalarm?id="+rest.data.id+"&geonames="+rest.data.geoname;
155                     }else{
156                         layer.msg('地标设置成功!');
157                         window.location.href=_ctx+"/geozone/landMarkList";
158                     }
159                     //$("#id").val(rest.data.id);
160                     //$("#geonames").val(rest.data.geoname);
161                     //$("#giveanalarmForm").submit();
162                 }else{
163                     if(flag == 0){
164                         layer.msg('围栏设置失败!');
165                     }else{
166                         layer.msg('地标设置失败!');
167                     }
168                 }
169             }
170         });
171     }else{
172         document.getElementById('geoname').focus();
173         if(flag == 0){
174             layer.msg('围栏名称必须填写!');
175         }else{
176             layer.msg('地标名称必须填写!');
177         }
178     }
179 }
180 
181 
182 /**
183  * 地址查询 
184  * 自动提示功能
185  * @param inputId
186  */
187 function initSeachBaidu(inputId){
188     //建立一个自动完成的对象
189     var autoComplete= new BMap.Autocomplete({"input" : inputId    ,"location" :allMap});
190     //鼠标点击下拉列表后的事件
191     //查询输入 TODO 是否去掉查询按钮
192 //    autoComplete.addEventListener("onconfirm", function(e) {    
193 //        var _value = e.item.value;
194 //        var searchValue = _value.province +  _value.city +  _value.district +  _value.street +  _value.business;
195 //    });
196 }
197 
198 
199 function searchAddrTip(){
200     var allMapType=$("#selectGeozoneMap").val();
201     if(allMapType=='baiduMap'){
202         baiduInit();
203     }else{
204         //googleSeach(inputId);
205     }
206 }
207 /**
208  * 地址查询 
209  * 自动提示功能
210  * @param inputId
211  */
212 function baiduInit(){
213     // 百度地图API功能
214     function G(id) {
215         return document.getElementById(id);
216     }
217 
218     var ac = new BMap.Autocomplete(    //建立一个自动完成的对象
219         {"input" : "mapSearchText"
220         ,"location" : allMap
221     });
222 
223     ac.addEventListener("onhighlight", function(e) {  //鼠标放在下拉列表上的事件
224     var str = "";
225         var _value = e.fromitem.value;
226         var value = "";
227         if (e.fromitem.index > -1) {
228             value = _value.province +  _value.city +  _value.district +  _value.street +  _value.business;
229         }    
230         str = "FromItem<br />index = " + e.fromitem.index + "<br />value = " + value;
231         
232         value = "";
233         if (e.toitem.index > -1) {
234             _value = e.toitem.value;
235             value = _value.province +  _value.city +  _value.district +  _value.street +  _value.business;
236         }    
237         str += "<br />ToItem<br />index = " + e.toitem.index + "<br />value = " + value;
238         G("searchResultPanel").innerHTML = str;
239     });
240 
241     var myValue;
242     ac.addEventListener("onconfirm", function(e) {    //鼠标点击下拉列表后的事件
243     var _value = e.item.value;
244         myValue = _value.province +  _value.city +  _value.district +  _value.street +  _value.business;
245         G("searchResultPanel").innerHTML ="onconfirm<br />index = " + e.item.index + "<br />myValue = " + myValue;
246         setPlace();
247     });
248 
249     function setPlace(){
250         allMap.clearOverlays();    //清除地图上所有覆盖物
251         function myFun(){
252             var pp = local.getResults().getPoi(0).point;    //获取第一个智能搜索的结果
253             allMap.centerAndZoom(pp, 18);
254             allMap.addOverlay(new BMap.Marker(pp));    //添加标注
255         }
256         var local = new BMap.LocalSearch(allMap, { //智能搜索
257           onSearchComplete: myFun
258         });
259         local.search(myValue);
260     }
261 }
262 
263 /**
264  * Google搜索
265  * */
266 function googleSeach(inputId){
267     var options = {
268               bounds: defaultBounds,
269               types: ['establishment']
270     };
271     autocomplete = new google.maps.places.Autocomplete(inputId, options);
272 }

围栏显示:

 

  1 var geozId=$("#geozId").val();
  2 echoGeozone();
  3 var data;
  4 
  5 //围栏回显
  6 $("#selectGeozoneMap").change(function(){
  7     var mapType=$(this).children('option:selected').val();//这就是selected的值 
  8     if(mapType=='googleMap'){
  9         initGoogleMap();
 10         echoGeozoneGoogleMapData(data);//google回显
 11     }else{
 12         initBaiDuMap();
 13         echoGeozoneBaiduMapData(data);//百度回显
 14     }
 15 });
 16 function echoGeozone(){
 17     $.ajax({
 18         type:'POST',
 19         url:_ctx+"/geozone/getgeozone",
 20         data:{"geozId":geozId},
 21         dataType:'json',
 22         success: function(ret){
 23             if(ret.ok){
 24                 data=ret.data;
 25                 //initBaiDuMap();
 26                 echoGeozoneBaiduMapData(data);
 27             }
 28         }
 29     });
 30 }
 31 
 32 //百度地图回显
 33 function echoGeozoneBaiduMapData(data){
 34     var typeMap=data.mapType;
 35     var datas=null;
 36     if(typeMap=='google'){
 37         datas=data.backGeom;
 38     }else{
 39         datas=data.geom;
 40     }
 41     var coords=datas.point;
 42     
 43     var centerAndZoomPointLat;
 44     var centerAndZoomPointLng;
 45     var BmapPointArray=[];
 46     for(var i=0;i<coords.length;i++){
 47         var lat=coords[i].lat;
 48         var lng=coords[i].lng;
 49         centerAndZoomPointLat=coords[0].lat;
 50         centerAndZoomPointLng=coords[0].lng;
 51         var BmapPoint=new BMap.Point(lng,lat);
 52         BmapPointArray.push(BmapPoint);
 53     }
 54     //回显多边形
 55     var polygon = new BMap.Polygon(BmapPointArray,{
 56            strokeColor : "#0000FF",
 57            strokeOpacity : 0.8,
 58            strokeWeight : 2,
 59            fillColor : "#FF0000",
 60         fillOpacity : 0.4,
 61            editable:false, //是否可以编辑
 62            draggable:false //是否可拖动    
 63        });  //创建多边形
 64     allMap.centerAndZoom(new BMap.Point(centerAndZoomPointLng,centerAndZoomPointLat),11); //设置中心点坐标和地图级别
 65     allMap.addOverlay(polygon);   //增加多边形
 66 }
 67 //google 地图回显示
 68 function echoGeozoneGoogleMapData(data){
 69     var typeMap=data.mapType;
 70     var datas=null;
 71     if(typeMap=='baidu'){
 72         datas=data.backGeom;
 73     }else{
 74         datas=data.geom;
 75     }
 76     var coords=datas.point;
 77     
 78     var centerAndZoomPointLat;
 79     var centerAndZoomPointLng;
 80     var GmapPointArray=[];
 81     for(var i=0;i<coords.length;i++){
 82         var lat=coords[i].lat;
 83         var lng=coords[i].lng;
 84         centerAndZoomPointLat=coords[0].lat;
 85         centerAndZoomPointLng=coords[0].lng;
 86         var pointArray= new google.maps.LatLng(lat,lng);
 87         GmapPointArray.push(pointArray);
 88     }
 89     var centerPoint= new google.maps.LatLng(centerAndZoomPointLat,centerAndZoomPointLng);
 90     
 91     var myLatlng = new google.maps.LatLng(centerAndZoomPointLat,centerAndZoomPointLng);
 92     var mapOptions = {
 93       zoom: 13,
 94       center: centerPoint,
 95       mapTypeId: google.maps.MapTypeId.ROADMAP
 96     };
 97     //var maps = new google.maps.Map(document.getElementById("allmap"), mapOptions);
 98     var polygonGoogle = new google.maps.Polygon({
 99         path : GmapPointArray,
100         strokeColor : "#0000FF",
101         strokeOpacity : 0.8,
102         strokeWeight : 2,
103         fillColor : "#FF0000",
104         fillOpacity : 0.4,
105         editable:false, //是否可以编辑
106         draggable:false //是否可拖动
107     });
108     polygonGoogle.setMap(allMap);
109 }

 

 

 

先这样了.........了解详细讨论 

https://gitee.com/ibyte/M-Pass

 

posted @ 2015-06-25 11:31  小码哥、iByte  阅读(38716)  评论(9编辑  收藏  举报