Je recherchais une solution solide qui me permettrait de créer une carte Web et de superposer des polygones vectoriels sans prendre un temps fou pour charger de telles données dans le but de permettre à chaque polygone d'afficher une couleur différente lors d'un survol.
Autant que je sache, il existe 3 options spécifiques pour y parvenir, que ce soit canvas, SVG ou Flash.
Flash semble être la meilleure solution si cela fonctionnait sur Apple iphones / ipads, car il semble offrir le rendu le plus rapide et l’affichage le plus propre. Canvas semble être le deuxième meilleur choix mais prend TRÈS longtemps si vous avez des centaines de polygones affichés sur une carte alors que SVG prend encore plus de temps à afficher.
J'ai presque perdu tout espoir de trouver une solution à ce problème, mais aujourd'hui je suis tombé sur une société appelée GISCloud http://www.giscloud.com (actuellement en version bêta avec inscription gratuite).
Cette société a réussi à trouver un moyen étonnant de rendre des centaines de vecteurs sur une carte en temps quasi réel. J'ai été surpris par leur approche et ma question à la communauté concerne la manière de reproduire leur approche pour une utilisation avec les technologies existantes telles que dépliants, openlayers, wax ...
Jetez un coup d'oeil par vous-même en visionnant cette incroyable démo: http://www.giscloud.com/map/284/africa
Assurez-vous de survoler les polygones de la page et testez les commandes de zoom pour vous assurer que ces polygones sont bien des vecteurs.
Ce que j’ai remarqué en examinant les requêtes avec Firebug, c’est que la carte demande des fichiers JSON spécifiques. Il semble que, selon le niveau / la zone de zoom, plusieurs fichiers json soient demandés.
Je devrais également mentionner ici qu'une fois que giscloud charge les données de la page survolant un vecteur, la couleur change immédiatement sans créer de nouvelle demande.
EXEMPLES:
- http://cft1.giscloud.com/t/1316509973/map284/layer1156/3/3/3.json
- http://cft1.giscloud.com/t/1316509973/map284/layer1156/3/5/3.json
- http://cft1.giscloud.com/t/1316509973/map284/layer1156/3/4/4.json
- http://cft1.giscloud.com/t/1316509973/map284/layer1156/3/3/4.json
- http://cft1.giscloud.com/t/1316509973/map284/layer1156/3/5/4.json
Je suppose que la structure de l'URL suit la logique du service de mosaïque standard (par exemple, le troisième au dernier dossier est le niveau de zoom ...).
Dans tous les cas, j’ai analysé les données réelles de ces fichiers json et il semble que la logique qu’ils utilisent suive un type de logique selon lequel ils créent leurs vecteurs à partir de ces valeurs de données:
- width / height: ils définissent la largeur et la hauteur des données servies dans chaque requête json
- pixels: ici, ils définissent des valeurs de pixels qui, je suppose, sont en quelque sorte liées à des coordonnées générales de pixels x / y pour des niveaux de points généralisés? Je suppose qu'ils ont en quelque sorte un moyen de simplifier automatiquement la région en fonction du niveau de zoom. Je suppose qu'en utilisant des coordonnées en pixels, je suppose qu'ils réduisent considérablement la taille des données à charger par rapport aux données lat / long.
- styles: ils définissent ici deux valeurs css RVB. "F" représentant la couleur du fichier de polygone et "S" représentant la couleur de la bordure du polygone.
- geom: voici où je suppose qu'ils définissent en quelque sorte de manière spécifique la définition de chaque polygone dans la tuile en cours de chargement, là où de telles données sont définies à partir de la fenêtre du conteneur de carte. Ce qui est également intéressant, c’est que chaque entrée a une valeur "S" qui, je suppose, est utilisée comme attribut optionnel ou valeur de lien de caractéristique. À la fin de chaque entrée, il existe une zone qui semble définir un identifiant par vecteur spécifique avec L'ID de couche que je devine est utilisé pour joindre d'une manière ou d'une autre les données de chaque demande de mosaïque json appelée.
Je suppose également qu'ils ont en quelque sorte trouvé un moyen de déterminer et de scinder automatiquement les données à charger pour chaque mosaïque en fonction de la taille des données devant être chargées pour la mosaïque demandée.
Voici une ventilation extraite de l'une de ces demandes:
{"width":256,"height":256,"tile":
{"pixels":
[0,6461,-1,0,5,148,0,509,-1,10715,-1,1,-1,251,-1,1,-1,1,-1,251,-2,3,-1,255,-1,249,-2,5,-2,247,-1,509,-3,251,-1,2,-2,253,-2,252,-2,254,-1,255,-1,254,-1,255,-1,1276,-2,13,-1,233,-1,2,-1,253,-1,1,-1,255,-1,247,-1,1306,-1,1533,-1,1269,-1,1276,-1,2303,-1]},
"styles":
[{"f":"rgb(99,230,101)","s":"rgb(5,148,0)","lw":"0"}],
"geom":
[
{"s":0,"p":[4,143,5,144,3,146,1,146,2,143,4,143],"c":"layer1156_5098"},
{"s":0,"p":[-2,143,0,140,2,141,2,144,1,146,-2,144,-2,143],"c":"layer1156_5067"},
{"s":0,"p":[7,143,5,144,4,143,2,143,2,141,5,138,6,139,5,141,7,143],"c":"layer1156_5051"},
{"s":0,"p":[10,141,11,137,12,137,14,137,12,142,9,143,9,142,10,141],"c":"layer1156_5041"},
{"s":0,"p":[1,136,0,140,-2,143,-2,136,1,136],"c":"layer1156_5038"},
{"s":0,"p":[8,143,5,141,5,137,8,136,10,137,10,141,8,143],"c":"layer1156_5033"},
{"s":0,"p":[5,137,2,141,0,140,1,136,1,136,2,135,3,136,5,137],"c":"layer1156_5028"},
{"s":0,"p":[10,134,12,136,11,138,8,135,10,134],"c":"layer1156_5020"},
{"s":0,"p":[-2,133,0,136,-2,136,-2,133],"c":"layer1156_5005"},
{...}
...
]
}
Comment pouvons-nous reproduire le même type de vitesse (ou un type similaire) en utilisant des postgis (que je semble utiliser aussi)?
la source
Réponses:
J'ai vu cette technique utilisée dans le passé. Il m'a été expliqué par Zain Memon (de Trulia) qui a contribué à la création de TileStache par Michal Migurski. Zain l'a expliqué en expliquant sa démo Trulia qui utilise cette technique lors d'une de nos plus anciennes réunions SF GeoMeetup il y a quelque temps . En fait, si vous êtes à SF la semaine prochaine (c’est ma tentative boiteuse de brancher, il abordera ce sujet , alors n'hésitez pas à vous montrer :)
OK, passons maintenant à l'explication.
Premièrement, vous regardez légèrement au mauvais endroit lorsque vous regardez les fichiers json ci-dessus.
Laissez-moi vous expliquer (aussi court que possible), pourquoi.
Les tuiles sont passées comme des tuiles ordinaires, ce n’est pas grave, nous savons le faire et je n’ai donc pas besoin d’expliquer cela.
Si vous l'inspectez dans Firebug, vous verrez que vous obtenez également tout un tas d'images qui semblent être vides, comme celle-ci .
Pourquoi est-il vide? Ce n'est pas. Les pixels contiennent des données - mais pas des données d'image visibles traditionnelles. Ils utilisent une technique très intelligente pour transmettre des données encodées dans les pixels eux-mêmes.
Ce qui se passe depuis dix ans, c’est que les gens ont échangé des données de lisibilité et de portabilité de formats au détriment de l’efficacité du stockage.
Prenons cet exemple d’exemple de données XML:
OK, combien de piqûres pour transférer ça? À condition que nous soyons utf8 (1 octet par caractère pour traiter ce contenu). Eh bien, nous avons environ 176 caractères (sans compter les tabulations ni les espaces), ce qui donne ces 176 octets (c'est optimiste pour diverses raisons que je vais omettre pour des raisons de simplicité). Attention, c'est pour 2 points!
Pourtant, un petit malin qui ne comprend pas ce dont il parle parle quelque part dira que "json vous donne une compression plus élevée".
Bien, mettons le même non-sens XML que JSON:
Combien d'octets ici? Disons environ 115 caractères. J'ai même triché un peu et l'ai rendu plus petit.
Supposons que ma zone couvre 256x256 pixels et que je suis à un niveau de zoom si élevé que chaque caractéristique est rendue sous la forme d’un pixel et que j’ai tellement de caractéristiques qu’elle est pleine. De combien de données ai-je besoin pour montrer que 65 536 fonctionnalités?
54 caractères (ou octets utf - et j'ignore même certaines choses) par entrée de "fonctionnalité" multipliée par 65 536 = 3 538 944 ou environ 3,3 Mo
Je pense que tu as la photo.
Mais c’est ainsi que nous transportons les données dans une architecture orientée services. Merde gonflable lisible.
Et si je voulais tout transporter dans un schéma binaire que j'ai moi-même inventé? Disons plutôt que j'ai codé cette information en image bande unique (c'est-à-dire en noir et blanc). Et j’ai décidé que 0 signifie vendu et 1 signifie disponible et 2 signifie que je ne sais pas. Heck, dans un octet, j'ai 256 options que je peux utiliser - et je n'en utilise que deux ou trois pour cet exemple.
Quel est le coût de stockage de cela? 256x256x 1 (une seule bande). 65 536 octets ou 0,06 Mo. Et cela ne tient même pas compte des autres techniques de compression que je tire gratuitement de plusieurs décennies de recherche sur la compression d'images.
À ce stade, vous devriez vous demander pourquoi les gens n'envoient pas simplement des données codées au format binaire au lieu de les sérialiser en json. Eh bien d’abord, javascript est une grosse perte de temps pour le transport de données binaires , c’est pourquoi les gens n’ont pas fait cela de manière historique.
Certaines personnes ont utilisé une méthode de travail géniale lors de la sortie des nouvelles fonctionnalités de HTML5, notamment de la toile . Alors, quel est ce travail génial? En fin de compte, vous pouvez envoyer des données codées sur ce qui semble être une image par la fil, puis insérer cette image dans un canevas HTML5, ce qui vous permet de manipuler les pixels directement ! Vous avez maintenant un moyen de récupérer ces données, de les décoder du côté client et de générer les objets JSON dans le client.
Arrêtez-vous un instant et réfléchissez-y.
Vous pouvez encoder une quantité énorme de données géoréférencées significatives dans un format fortement compressé, avec des ordres de grandeur plus petits que tout ce qui est fait traditionnellement dans les applications Web, et les manipuler en javascript.
Le canevas HTML n'a même pas besoin d'être utilisé pour dessiner, il n'est utilisé que comme mécanisme de décodage binaire!
C’est l’objet de toutes ces images que vous voyez dans Firebug. Une image, avec les données encodées pour chaque mosaïque téléchargée. Ils sont super petits, mais ils ont des données significatives.
Alors, comment les encoder côté serveur? Vous devez bien généraliser les données côté serveur et créer une vignette explicite pour chaque niveau de zoom contenant les données codées. Actuellement, pour ce faire, vous devez créer votre propre solution - une solution open source prête à l'emploi n'existe pas, mais vous avez tous les outils dont vous avez besoin pour le faire. PostGIS fera la généralisation via GEOS, TileCache peut être utilisé pour mettre en cache et vous aider à déclencher la génération des tuiles. Côté client, vous devrez utiliser HTML5 Canvas pour transmettre les "fausses mosaïques", puis utiliser OpenLayers pour créer de vrais objets javascript côté client qui représentent les vecteurs avec des effets de survol.
Si vous devez encoder plus de données, n'oubliez pas que vous pouvez toujours générer des images RGBA par pixel (ce qui vous donne 4 octets par pixel ou 4 294 967 296 nombres que vous pouvez représenter par pixel ). Je peux penser à plusieurs façons de l'utiliser :)
Mise à jour : réponse à la question QGIS ci-dessous.
QGIS, comme la plupart des autres SIG de bureau , n’a pas d’ensemble de niveaux de zoom fixes. Ils ont la possibilité de zoomer à n'importe quelle échelle et de simplement le rendre. Peuvent-ils afficher des données provenant de sources WMS ou basées sur des tuiles? Bien sûr, ils le peuvent, mais la plupart du temps, ils sont vraiment stupides: zoomez différemment, calculez le cadre de sélection, calculez les mosaïques requises, saisissez-les, montrez-les. La plupart du temps, ils ignorent d'autres éléments, tels que les caches d'en-tête http, qui leur évitent d'avoir à récupérer des données. Parfois, ils implémentent un mécanisme de cache simple (stockez la vignette, si vous le demandez, vérifiez la vignette, ne le demandez pas). Mais ce n'est pas assez.
Avec cette technique, les carreaux et les vecteurs doivent être récupérés à chaque niveau de zoom . Pourquoi? Parce que les vecteurs ont été généralisés pour s'adapter aux niveaux de zoom.
En ce qui concerne le truc de placer les mosaïques sur un canevas HTML5 afin que vous puissiez accéder aux tampons, tout cela n'est pas nécessaire. QGIS vous permet d'écrire du code en Python et C ++. Les deux langages offrent un excellent support pour la gestion des tampons binaires. Ce travail de contournement n'est donc pas pertinent pour cette plate-forme.
* MISE À JOUR 2 **:
Il y avait une question sur la façon de créer les tuiles vectorielles généralisées en premier lieu (bébé étape 1 avant de pouvoir sérialiser les résultats en images). Peut-être que je n'ai pas clarifié assez. Tilestache vous permettra de créer des "tuiles vectorielles" efficaces de vos données à chaque niveau de zoom (il a même une option qui vous permet de couper ou de ne pas couper les données quand il passe la limite de la tuile). Cela permet de séparer les vecteurs en mosaïques à différents niveaux de zoom. Je choisirais l'option "pas de clip" (mais il choisira une tuile quelconque où il couvre plus de surface). Ensuite, vous pouvez insérer chaque grand vecteur dans GEOS generalize option avec un grand nombre. En fait, vous voulez que les polylignes et les polygones s’effondrent sur eux-mêmes, car s’ils le font, vous pouvez les supprimer du niveau de zoom, car ils sont sans importance. Tilestache vous permet même d'écrire facilement des fournisseurs de données pythonic dans lesquels vous pouvez mettre cette logique. À ce stade, vous pouvez choisir de les servir comme fichiers json (comme ils le font avec certains exemples de cartes africaines) ou comme géométries sérialisées dans les pngs, comme ils le font dans d’autres exemples (ou celui de Trulia) que j'ai donné ci-dessus.
la source
En direct du développeur Dino Ravnic sur un récent message de la liste de diffusion :
Il semble donc que le côté client est la partie la plus facile. C'est impressionnant que les données soient rendues sans aucune mise en cache.
Il mentionne également un service d'hébergement qui pourrait vous intéresser. Vous voudrez peut-être peser le coût d’essayer de recréer cela avec le coût d’utilisation d’un service prêt à l'emploi.
la source
Comme je l'ai décrit dans la liste OSGeo, la clé consiste à fournir des données sous forme de mosaïques JSON vectorielles comportant des pixels pour la géométrie sous-pixel et une géométrie généralisée pour les entités qui seront réellement visibles à un certain niveau. Les performances sont excellentes car cette technique élimine toutes les informations vectorielles inutiles et ne laisse que les vecteurs qui auront réellement un impact visuel sur la carte. Les pixels sont là pour combler les lacunes et être placés à la place des vecteurs de sous-pixels. C'est ce qui concerne le format de tuile.
Sur le côté arrière se trouve le véritable travail lourd. Nous n'utilisons ni TileStache ni aucun autre moteur de carte, car nous avons écrit notre propre logiciel qui peut, avec de nombreuses optimisations, produire de tels graphiques vectoriels en temps réel.
Nous avons d'abord commencé par fournir des mosaïques de carte sous forme de fichiers SWF, puis récemment nous avons simplement activé la sortie au format JSON afin de pouvoir utiliser HTML5 Canvas pour le rendu des graphiques. Vous trouverez ci-dessous un repère comparant ce type de technologie vectorielle à la technologie matricielle (mapnik). Pour une comparaison équitable, recherchez uniquement les résultats en mode CGI.
http://www.giscloud.com/blog/realtime-map-tile-rendering-benchmark-rasters-vs-vectors/
Nous prévoyons de fournir cette technologie en tant que service d'hébergement de tuiles de carte. L'idée est d'héberger vos données géographiques sur le nuage et de les transmettre via HTML5 à n'importe quel client de carte à haute vitesse, sans qu'il soit nécessaire de mettre en cache les tuiles. Si vous êtes intéressé pour rejoindre cette beta, n'hésitez pas à nous contacter ici: http://www.giscloud.com/contact/
la source
On dirait qu’une question très similaire a récemment été posée sur le forum OSGeo Open Layers , les développeurs GIS Cloud décrivant leur approche, qui est un mélange intéressant de géométries GeoJSON et de pixels statiques. Ils génèrent en fait toutes les tuiles vectorielles à la volée au lieu d'utiliser un cache pré-construit de fichiers GeoJSON.
Esri a mis en œuvre une approche similaire, utilisant ArcGIS Server et les couches de fonctions , qui permet de généraliser les géométries à la volée et de les envoyer par la voie au format JSON.
Pour une méthode simple que vous pouvez réellement mettre en œuvre maintenant, vous pouvez créer des tuiles vectorielles avec Tilestache (qui prend en charge PostGIS ) et les utiliser dans Polymaps . Polymaps utilise SVG, mais les performances sont assez bonnes et les règles CSS définissent le style des éléments de la carte. Le rendu des fonctionnalités dépend donc totalement de vous. Voici un article de blog travaillant à travers quelque chose de similaire à ce que vous demandez.
la source
J'ai utilisé OpenLayers avec Canvas et obtenu des résultats raisonnables.
Comme indiqué dans les autres réponses: fournir et afficher les vecteurs à la volée - ils doivent être généralisés pour chaque niveau de zoom et chaque jeu de données. En outre, vous pouvez utiliser le codage polyligne de Google pour réduire considérablement la taille.
J'ai utilisé un mécanisme de livraison simple. Chaque géométrie était une fonction JavaScript dans une réponse HTTP JavaScript. pas aussi avancé que la livraison vectorielle basée sur des tuiles, mais simple et Open Source!
Je n’ai pas essayé Google Maps v3 avec Canvas, mais j’ai vu deux démos du New York Times qui l’ont impressionné.
la source
Je ne sais pas exactement quelle solution est utilisée par cette société (vous pouvez peut-être leur demander directement) mais j'ai une idée.
La solution clé pour améliorer le transfert réseau et la vitesse de rendu des données vectorielles consiste à les généraliser en fonction du niveau de zoom: le transfert et le rendu à un niveau de zoom élevé, des milliers d’objets conçus pour un niveau de zoom beaucoup plus faible prennent inutile car l'affichage final n'est généralement pas lisible - voir par exemple cette image ). Pour implémenter cela, la base de données de votre serveur postgis doit être multi-échelle : pour chaque niveau de zoom, il doit exister une représentation de l'objet adaptée à ce niveau de zoom. Ces différentes représentations peuvent être calculées automatiquement à l'aide de techniques de généralisation. De plus, les données vectorielles envoyées par le serveur au client ne doivent pas uniquement dépendre de l'étendue spatiale, mais également du niveau de zoom: Le serveur envoie des données appropriées en fonction du niveau de zoom. C'est l'approche défendue dans cet excellent article :-)
la source
Il existe un article intéressant, une démo et le code source d'un logiciel développé par Stanford Visualization Group qui utilise un cube de données pour chaque mosaïque afin de visualiser et d'explorer un grand ensemble de données géographiques. Il ne peut être utilisé que pour un jeu de données ponctuel mais peut être un moyen intéressant.
http://vis.stanford.edu/papers/immens
Vizzuality, avec sa plate-forme CartoDB et la bibliothèque appelée Torque, expérimente aussi en quelque sorte comment dessiner un volume élevé de données.
http://cartodb.github.io/torque/
https://github.com/CartoDB/torque/tree/new_torque
la source