マーカーはなしでノーマルのマップを表示させたい
マップを表示させているコード(具体的に言うとmap = new ns.Map($("#map")[0], mapOptions);
までのコード)をsubmit
イベントの外に出せばいいですね。
今のマップに表示されている範囲のみマーカーを読み込むようにしたい
サーバで管理する方法と、クライアントで管理する方法があります。
サーバで管理する場合、実装によっては地図を移動させるたびに読み込みが発生し、結果として遅くなる可能性があります。地図をいくつかの範囲に分割し、表示エリアから読み込むべき範囲を取得し、再読み込みが必要であるかどうか制御する必要があるでしょう。位置情報DBに範囲IDフィールドを設けておくと応答が改善する可能性があるので、検討してみてください。参考:一次元ハッシュコードによる空間半径検索 - Qiita
クライアントで管理する場合、いくつかのライブラリがありますので利用をしてみるのもいいでしょう。ズームレベルによってはクラスタリングを検討するのもいいかもしれません。
https://github.com/googlemaps/v3-utility-library/blob/master/markermanager/examples/google_northamerica_offices.html
https://github.com/googlemaps/js-marker-clusterer
いずれにせよ、V2の時代よりもGoogleマップAPIは高速化しているので、100程度のマーカーであればそのままAPIに投げた方がよきにはからってもらえると思います。
追記
すっかり忘れてましたが、はるか昔にgeohash管理ライブラリを作ったことがありました。緯度経度を渡すとその範囲のgeohashの組み合わせを返します。読み込み済みの範囲も管理していて、内部でパズルみたいに組み合わせをしたりしてます。プロトタイプ汚染とかしててお行儀の悪いレガシーコードですが、せっかくなので貼っておきますね。
javascript
1function GeostringStack(max, min){
2 //定数
3 var GEOSTRING_LIMIT = max; //探索最小限度
4 var SLICE_MARGIN = 0.00001; //スライスマージン
5 var SLICE_LIMIT = Math.floor(min/2); //スライスグリッド
6 var DY = 1.0/(Math.pow(2,SLICE_LIMIT));
7 var DX = 1.0/(Math.pow(2,SLICE_LIMIT));
8 var MAP_SIZE = {y:180, x:360}; //世界地図座標の範囲
9
10 //Geohashモジュール
11 function Geostring (data, bound, depth){
12 var to_bits = function(f,depth){
13 re = [];
14 for (var i=1; i<depth+1; i++){
15 re.push( Math.floor(f*2).toString() )
16 f = (f*2)-Math.floor(f*2)
17 }
18 return re
19 }
20
21 var bitstring = function(data,bound,depth){
22 var y = data[0];
23 var x = data[1];
24 y = to_bits((y-bound[0])/(bound[2]-bound[0]),depth)
25 x = to_bits((x-bound[1])/(bound[3]-bound[1]),depth)
26 bits =''
27 for (var i=0; i<x.length; i++){
28 bits += x[i] + y[i]
29 }
30 return bits
31 }
32
33 this.toString = function(){
34 return this.hash;
35 }
36
37 this.union = function(yourHash){
38 var myHash = this.hash;
39 var yourHash = yourHash.toString();
40 var returnHash = '';
41 for ( var i=0; i<Math.min(myHash.length, yourHash.length); i++){
42 if (myHash.charAt(i) == yourHash.charAt(i)){
43 returnHash += myHash.charAt(i);
44 }else{
45 break;
46 }
47 }
48 return new this.myConstructor(returnHash, bound, depth)
49 }
50
51 this.bbox = function(){
52 var bits= this.hash;
53 var depth = Math.floor(bits.length/2);
54 var minx = 0.0;
55 var miny = 0.0;
56 var maxx = 1.0;
57 var maxy = 1.0;
58 for (var i=0; i<depth+1; i++){
59 if (bits.charAt(i*2)) minx += parseInt(bits.charAt(i*2))/(Math.pow(2,i+1));
60 if (bits.charAt(i*2+1)) miny += parseInt(bits.charAt(i*2+1))/(Math.pow(2,i+1));
61 }
62 if (depth){
63 maxx = minx + 1.0/(Math.pow(2,depth+bits.length%2));
64 maxy = miny + 1.0/(Math.pow(2,depth));
65 }else if (bits.length == 1){
66 // degenerate case
67 maxx = Math.min(minx + .5, 1.0);
68 }
69 minx = origin[1]+minx*size[1];
70 maxx = origin[1]+maxx*size[1];
71 miny = origin[0]+miny*size[0];
72 maxy = origin[0]+maxy*size[0];
73 return [miny, minx, maxy, maxx];
74 }
75
76 this.myConstructor = arguments.callee
77
78 var bound = bound ? bound : [-90,-180,90,180];
79 var depth = depth ? depth : 32;
80 var origin = bound.slice(0,2);
81 var size = [bound[2]-bound[0], bound[3]-bound[1]];
82 if (data instanceof Array){
83 this.hash = bitstring(data,bound,depth);
84 }else{
85 this.hash = data;
86 }
87 }
88
89 //配列関数の拡張
90 if (!Array.prototype.map){
91 Array.prototype.map = function(f){
92 var re = []
93 for ( var i=0; i<this.length; i++){
94 re.push( f(this[i]) )
95 }
96 return re;
97 }
98 }
99 if (!Array.prototype.max){
100 Array.prototype.max = function(){
101 return this.slice(0).sort().reverse()[0];
102 }
103 }
104 if (!Array.prototype.min){
105 Array.prototype.min = function(){
106 return this.slice(0).sort()[0];
107 }
108 }
109 if (!Array.prototype.contains){
110 Array.prototype.contains = function (v){
111 for( var i=0; i<this.length; i++){
112 if (this[i] == v) {return true; break;}
113 }
114 }
115 }
116 //定数
117 var IS_FOUND = 1;
118 var IS_EMPTY = 2;
119 var IS_PARTIAL = 3;
120
121 this.index = function(boxArray){
122 var slicedBox = this.slice(boxArray);
123 var boundsGeostring;
124 var boundsGeostrings = [];
125 for (var i=0; i<slicedBox.length; i++){
126 boundsGeostring =
127 new Geostring([slicedBox[i].sw.lat+SLICE_MARGIN, slicedBox[i].sw.lng+SLICE_MARGIN])
128 .union( new Geostring([slicedBox[i].ne.lat-SLICE_MARGIN, slicedBox[i].ne.lng-SLICE_MARGIN]) );
129 boundsGeostrings = boundsGeostrings.concat( this.search( boundsGeostring.toString().substring(0,GEOSTRING_LIMIT) ) );
130 }
131 return boundsGeostrings
132 }
133 this.slice = function(bbox){//SLICE_LIMITで切り分け
134 if (bbox instanceof Array) {
135 box = { sw:{lat:bbox[0]/MAP_SIZE.y, lng:bbox[1]/MAP_SIZE.x}, ne:{lat:bbox[2]/MAP_SIZE.y, lng:bbox[3]/MAP_SIZE.x} };
136 }else{
137 box = bbox;
138 }
139 return subSlice(box).map(function(b){
140 return { sw:{lat:b.sw.lat*MAP_SIZE.y, lng:b.sw.lng*MAP_SIZE.x}, ne:{lat:b.ne.lat*MAP_SIZE.y, lng:b.ne.lng*MAP_SIZE.x} }
141 });
142
143 function subSlice(box){//再帰関数
144 var yCutoff = box.sw.lat-box.sw.lat%DY+DY;
145 var xCutoff = box.sw.lng-box.sw.lng%DX+DX;
146 var f = ( ( yCutoff < box.ne.lat )<<1 ) + ( xCutoff < box.ne.lng )
147 switch (f){
148 case 0:
149 return [box];
150 break;
151 case 1:
152 return [{ sw:{lat:box.sw.lat, lng:box.sw.lng}, ne:{lat:box.ne.lat, lng:xCutoff} }].concat(
153 subSlice({ sw:{lat:box.sw.lat, lng:xCutoff}, ne:{lat:box.ne.lat, lng:box.ne.lng} }))
154 break;
155 case 2:
156 return [{ sw:{lat:box.sw.lat, lng:box.sw.lng}, ne:{lat:yCutoff, lng:box.ne.lng} }].concat(
157 subSlice({ sw:{lat:yCutoff, lng:box.sw.lng}, ne:{lat:box.ne.lat, lng:box.ne.lng} }))
158 break;
159 case 3:
160 return [{ sw:{lat:box.sw.lat, lng:box.sw.lng}, ne:{lat:yCutoff, lng:xCutoff} }].concat(
161 subSlice({ sw:{lat:box.sw.lat, lng:xCutoff}, ne:{lat:yCutoff, lng:box.ne.lng} })).concat(
162 subSlice({ sw:{lat:yCutoff, lng:box.sw.lng}, ne:{lat:box.ne.lat, lng:xCutoff} })).concat(
163 subSlice({ sw:{lat:yCutoff, lng:xCutoff}, ne:{lat:box.ne.lat, lng:box.ne.lng} }))
164 break;
165 }
166 }
167 }
168 this.search = function(geostr){//読み込むGeostringを探索
169 var isContain = false;
170 for ( var i=1; i<=geostr.length; i++){
171 if ( this.stack[i].contains( geostr.substring(0,i) ) ) {isContain = true; break;}
172 }
173 if (isContain) {
174 return []
175 }else{
176 var list = this.subSearch(geostr)
177 if (list.state == IS_FOUND){
178 return false;
179 }else{
180 this.stack[geostr.length].push(geostr);
181 return list.list;
182 }
183 }
184 }
185 this.subSearch = function(substr){//searchで使用する再帰関数
186 if ( this.stack[substr.length].contains( substr ) ){
187 return {'state': IS_FOUND, 'list': []};
188 }else{
189 if (substr.length>=GEOSTRING_LIMIT){
190 return {'state': IS_EMPTY, 'list': [substr]};
191 }else{
192 var add0 = this.subSearch(substr+'0');
193 var add1 = this.subSearch(substr+'1');
194 var state = add0.state | add1.state; //IS_FOUND同志の時IS_FOUND、IS_EMPTY同志の時IS_EMPTY
195 var list = (state == IS_EMPTY) ? [substr] : add0.list.concat(add1.list); //IS_EMPTY同志の時、リスト作り直し
196 return {'state': state, 'list': list}
197 }
198 }
199 }
200 this.clearStack = function(){
201 this.stack = new Array(GEOSTRING_LIMIT);
202 for (var i=0; i<=GEOSTRING_LIMIT; i++) this.stack[i] = [];
203 }
204
205 //イニシャライズ
206 this.clearStack();
207}
動作例
javascript
1var a = new GeostringStack(29,22);
2a.index([35.8,139.8,35.9,139.9]);
3//["1110110100001110011111", "1110110100001111001010"]
4a.index([35.8,139.8,35.9,139.9]);
5//[]
6a.index([35.85,139.85,35.95,139.95]);
7//["11101101000011101101010101", "111011010000111100101110", "11101101000011111000000", "11101101000011111000010000"]
8a.index([35.85,139.85,35.95,139.95]);
9//[]
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/02/10 15:49