カードがこのように見える場合はどうなりますか?

Ezem.ru-土地





こんにちは、私の名前はVladです。 私はEzem.ruプロジェクトの主要な開発者です。 上の写真では、モスクワ地域のユーザーが投稿したすべてのサイト(8000以上のサイト)が表示されています。 この問題をどのように解決し、どのような落とし穴が生じたのかをお伝えしたいと思います。



主な問題は、マップ上に500を超えるオブジェクトがあると、平均的なオフィスコンピューターの速度が著しく低下し、マップの使用が困難になることです。 主な問題に加えて、すべてのセクションを表示する場合、特定のマーカーをクリックすることはできませんが、モスクワでは、ある種のブラックホールがありました:) Google Maps APIの他のユーザーがこの問題をどのように解決したかを確認しました。 GPS-Club:POI:高速カメラこの家はどこにあるのかMirTesenPushkino.org (最初に思い浮かんだ)は、「ブレーキ」の問題を解決できなかったか、単に画面上のオブジェクトの数を制限しました。 そして、ここでの問題はむしろGoogleマップAPIではなく、DOMモデル自体にあり、インターネットキラー(IE 6)ではすでに非常に遅いです。



松葉杖1.標準製品を使用します。

ビューはGMarkerManagerに当てはまりました 。 その動作の原理は単純です。 現在画面に表示されているマーカーのみをDOMに読み込むことにより、DOMオブジェクトの数を減らし、ブラウザーの困難な生活を促進します...

しかし、 ドキュメントをより詳細に見ると少し混乱していました。

このクラスは非推奨です。 開発者は、代わりにオープンソースのMarkerManagerを使用することをお勧めします。






松葉杖2.サードパーティのツールを使用します。

インターネットをさまよい、通行人に尋ねた後、「 MarkerManager 」というすばらしい名前のすばらしい図書館に出会いました。 操作の原理はGMarkerManagerの原理と同じですが、わずかな違いがあります。 画面上のすべてのマーカーを削除し、特定のマーカーを削除する機能があります。 この松葉杖は正常に機能しましたが、マーカーの数が3,000を超えるまでのみでした。別の石は、マーカーがページに初めて入ったときに読み込まれ、クライアント側で処理された(200kb XML)かなり時間がかかりました。 一般的に、AJAXリクエストをジャグリングし、現在表示されているエリアマーカーとズームのみをプルすることが決定されました。 このオプションは、わずかな修正を加えて、当社のWebサイトで機能します。





松葉杖3.グループ化マーカー。

上記で述べたように、あるポイントに集中するマーカーが多いほど、マップを使用することが難しくなります。 実際、特定のマーカーを取得することは、時には不可能でした。 画面上のマーカーの数を減らし、サーバー側にマーカーのグループを導入することが決定されました。 解決策は非常に簡単ですが、あまり正確ではありません。 各マップズームについて、正しいサイズの長方形が選択され(右の図を参照)、この領域にあるマーカーは子としてマークされ、このズームではそのうちの1つだけが表示されました。 そして、グループ化されていないマーカーごと、ズームごとに。 このアプローチの利点は、マップを使用できるようになったことです。 しかし、このアプローチには大きな欠点があります。計算には約12分かかり、1日に1回行われました。 マップの遅さを克服しましたが、別の問題がありました。マーカーのカウントは1日に1回行われるため、フィルターにグループ化を実装できませんでした。 また、「個別の住宅建設(赤色のマーカーのみ)」タイプと0〜50ヘクタールのプロットサイズを選択することで、ブラウザーを簡単に折りたたむことができます。



松葉杖4.マーカーの動的なグループ化。

ブラウザをマウスを2回クリックするだけでひざまずくことができるという考えから、私たちは静かに眠ることができず、グループのより高度なバージョンを作成することにしました。



オプション1.静的な正方形

このアイデアは、 オレグ・フォルチコフによって提出されました。 すべての可能なズームで事前にマップの可能なすべての正方形を計算します。 各ズームの長方形係数が異なることを直ちに予約し、ロシアのみを考慮しました。 2,300万件以上のレコードを取得し、データベースを200 MB回復しました。 このアプローチの利点は、マーカーのグループ化が2番目のオプションよりも正確に実行されたことです。 欠点は、データを計算する必要があり(開発車で約1晩かかった)、既に計算されたデータを別のデータベースに分離する必要があり、これが何らかのリファクタリングにつながることでした。



オプション2.表示領域のみによるグループ化

このアイデアの作者はセルゲイ・コルチンです。 マップを移動するたびに、表示されているエリアの座標をサーバーに転送します。この長方形を分割し、マーカーをリアルタイムでグループ化するだけではどうでしょうか。 この場合の欠点は、短い距離を移動すると、マーカーがわずかに移動することです。 これは重要ではない問題であると考えました。第1に、マーカーはそれほど移動せず、第2に、ユーザーは通常、マップ上を移動するのではなく、関心のある領域にすぐにズームインします。 このオプションは、最初のオプションよりもシンプルで高速であるという事実により、当社のウェブサイトで引き続き使用されています。



概念的なコード:



リクエストの例: http : //ezem.ru/gmap/getmarkers/?appoi ..



虐殺されたマーカーマネージャー

 / *著作権(c)2007 Google Inc.
  *
  * Apacheライセンス、バージョン2.0(「ライセンス」)の下でライセンスされています。
  *ライセンスに準拠している場合を除き、このファイルを使用することはできません。
  *ライセンスのコピーは以下で入手できます。
  *
  * http://www.apache.org/licenses/LICENSE-2.0
  *
  *適用法で要求されている場合、または書面で同意されている場合を除き、ソフトウェア
  *ライセンスに基づいて配布されるものは、「現状のまま」で配布されます。
  *明示または黙示を問わず、いかなる種類の保証または条件もありません。
  *許可を管理する特定の言語については、ライセンスを参照してください。
  *ライセンスに基づく制限。
  *
  *バージョン:1.0
  *著者:ダグリケット、その他
  *
  *マーカーマネージャーは、マップとユーザーの間のインターフェイスであり、設計されています
  *ビューポートが変更されたときに多くのポイントを追加および削除する管理。
  *
  *
  *アルゴリズム:MMは、マップタイルと同様に、マーカーをグリッドに配置します。
  *ユーザーがビューポートを移動すると、MMはどのグリッドセルが持つかを計算します
  *ビューポートに出入りし、それらのすべてのマーカーを表示または非表示にします
  *セル。
  *(ユーザーが読み込まれたマーカーを超えてビューポートをスクロールすると、
  * EVENT_moveendが更新をトリガーするまでマーカーは表示されません。
  *
  *実際の結果として、これにより10,000個のマーカーを配布できます。
  *広い領域、および特定のビューポートで100〜200のみが見える限り、
  *ユーザーには、100個の可視マーカーに対応する良好なパフォーマンスが表示されます。
  *合計10,000個のマーカーに対応するパフォーマンスの低下ではなく。
  *
  *一部のコードはスペースよりも速度が最適化されていることに注意してください。
  *数千のマーカーを収容することを目標としています。
  *
  * /

ファイルが大きいため、アップロードしませんでした。 リンクhttp://ezem.ru/js/gmap/markermanager.jsで見ることができます




関数ハンドラー



    パブリック関数getmarkersAction()
     {
         $ params = array();
         foreach(array( 'zoom'、 'area_min'、 'area_max'、 'units')as $ k){
             $ params [$ k] =(int)$ this-> _ getParam($ k、0);
         }
         foreach(array( 'lat1'、 'lat2'、 'lng1'、 'lng2')as $ k){
             $ params [$ k] = round((float)$ this-> _ getParam($ k、0.0)、4);
         }
         $ params ['no_groups'] =( 'true' == $ this-> _ getParam( 'no_groups'、null));
         $ params ['deal_type'] =( 'sell' == $ this-> _ getParam( 'deal_type'、null))?  「販売」:「購入」;
         $ params ['appointment'] = explode( '、'、trim($ this-> _ getParam( 'appointment'、 '')));
         $ params ['except_objects'] = explode( '、'、trim($ this-> _ getParam( 'except_objects'、 '')));

         $ dbWhere = Medialab_Items :: getActiveItemsLimits();
         if(@ $ this-> user-> id){
             $ dbWhere = array( '(('。implode( 'AND'、$ dbWhere)。 ')OR o.uid ='。$ this-> user-> id。 ')');
         }
         $ dbWhere [] = "` deal`.`type` = '"。$ params [' deal_type ']。"' ";
         $ dbWhere [] = '`マーカー` .`is_polygon` = 0';

         $マーカー= Medialab_Gmap_Marker :: getMarkersDynamic($ params、$ dbWhere);

         $ qty = 0;
         $ s = "<m> \ n";
         foreach($マーカーとしての$マーカー){
             $ isGroup =(1 <$マーカー['qty']);
             $ s。= '<mi = "'。$ marker ['id']。 '"'
                 .'o = "'。$ marker [' object_id ']。'" '<BR />
                 .'t = "'。$ marker [' lat ']。'" ' 
                 .'g = "'。$ marker [' lng ']。'" ' 
                 .'q = "'。$ marker [' qty ']。'" ' 
                 .'a = "'。($ isGroup?'グループ ':$マーカー['アポイントメントタイプ '])。'" /> '。 "\ n";
             $ qty + = $ marker ['qty'];
         }
         $ s。= '<info count = "'。$ qty。" \ "/> \ n";
         $ s。= '</ m>';

         header( 'Content-Type:text / xml; charset = windows-1251');
         exit($ s);
     }




コードからBRを削除します。 私はそれを挿入しなければなりませんでした、さもなければhabraparserはバグが多いです。 理由はわかりませんが、それがないと、彼はコードを1行にまとめてスクロールします。



すべてを汚すクラス:)

 class Medialab_Gmap_Marker {/ * * *スケール0のブロックサイズ(度単位)。* 72x128は、可視領域に6x6ブロックを定義します。 > 96.0);  / ** *指定されたズームのマップブロックの寸法を計算します* * @param int $ズームマップのズーム* @return array lat / lngのブロック寸法* / public static function getBlockSize($ zoom = 10){$ rect = array() ;  foreach(array( 'lat'、 'lng')as $ k){$ rect [$ k] = round(self :: $ blockSize [$ k] /(1 << $ zoom)、4);  $ rect [$ k .'_ half '] = round($ rect [$ k] / 2、4);  } return rect;  } / ** *可視マップ領域のマーカーを取得し、必要に応じて動的にグループ化します* * @param array $ params検索パラメーターの配列、少なくとも(lat、lng)ペアを提供*左上/右下の角、および現在のズーム。  * @param array $ dbWhere追加のSQLクエリ条件(オプション)* @return array Found items * * TODO:整合性を高めるために左上/右下ではなくSW / NEコーナーw / Google Maps API * / public static function getMarkersDynamic(array $ params、array $ dbWhere = array()){$ block = self :: getBlockSize($ params ['zoom']);  $ dbWhere [] = '( `marker`.`lat` BETWEEN'。$ params ['lat1']。 'AND'。$ params ['lat2']。 ')';  //経度180-> -180度で回避策をラップif($ params ['lng2'] <$ params ['lng1']){$ dbWhere [] = '(( `` marker`.`lng` BETWEEN'。$ Params ['lng1']。 'AND 180.0)OR( `marker`.`lng` BETWEEN -180.0 AND'。$ params ['lng2']。 '))';  } else {$ dbWhere [] = '( `marker`.`lng` BETWEEN'。$ params ['lng1']。 'AND'。$ params ['lng2']。 ')';  } if(($ params ['area_min'] || $ params ['area_max'])&& $ params ['units']){$ unit = DB :: FindFirst( 'ezem_units'、array( 'rate')、 array( 'id' => $ params ['units']));  if($ params ['area_min']){$ dbWhere [] = '`o`.`area`> ='。($ params ['area_min'] * $ unit ['rate']);  } if($ params ['area_max']){$ dbWhere [] = '`o`.`area` <='。($ params ['area_max'] * $ unit ['rate']);  }} $ a = $ params ['appointment'];  if(count($ a)&& $ a [0]){$ dbWhere [] = "`アポイントメント `..type` IN( '" .implode( "'、 '"、$ a)。 "')";  } $ a = $ params ['except_objects'];  if(count($ a)&& $ a [0]){$ dbWhere [] = '' o`.`id` NOT IN( '.implode('、 '、$ a)。') ';  } $ dbGroupBy = '`marker`.`id``;  if(($ params ['zoom'] <13)&&!$ params ['no_groups']){//ズームのみ<= 12で、no 'no_groups'フラグを設定せずにグループ化grp_lng``;  } $ query = 'SELECT `marker`.`id`、` marker`.`object_id`、 `appointment`.`type AS` reservation_type`、AVG(` marker`.`lat`)AS` lat`、AVG ( `marker`.`lng`)AS` lng`、FLOOR((` marker`.`lat`-'。$ params [' lat1 ']。')/ '。$ block [' lat ']。') AS `grp_lat`、FLOOR((` marker`.`lng`-'。$ Params [' lng1 ']。')/ '。$ Block [' lng ']。')AS `grp_lng`、COUNT(`マーカーASアポイントメント `ON(` appointment`.`id` = `o`.`appointment_id`)JOIN` ezem_deal` AS`取引 `ON(` deal`.`id` = `o`.`deal_id`)WHERE (「AND」、$ dbWhere)。  GROUP BY '。$ DbGroupBy;  return DB :: Query($ query);  }} 




ポータルは、 Zend FrameworkSmartyYandex Server 、およびJqueryに実装されています 。 私が話したことの実例は、当社のウェブサイトで見ることができます。



ps近い将来の計画:ポリゴンのサポートを追加し、 Yandex検索sphinxに置き換えますが、これについては次の記事で詳しく説明します。

pps 賢明なプログラマを探しています



All Articles