Lorsque je cherchais de l'inspiration sur echarts il y a deux jours, j'ai vu de nombreux exemples similaires de cartes, de positionnement des cartes, etc., mais il ne semblait pas y avoir de plan de métro, j'ai donc passé du temps à bricoler cette démo interactive de carte de métro, la. les points sur la ligne de métro ont été téléchargés au hasard depuis Internet.Cet article enregistre certains de mes gains (après tout, je suis encore un débutant) et la mise en œuvre du code, j'espère qu'il pourra aider certains amis. Bien sûr, si vous avez des opinions, vous pouvez me le dire directement. Ce n'est qu'en communiquant ensemble que nous pourrons progresser.
rendus
http://www.hightopo.com/demo/subway/index.html
La carte a un peu trop de contenu. Si vous souhaitez tout afficher, les polices apparaîtront un peu petites, mais cela n'a pas d'importance. Vous pouvez zoomer et dézoomer selon vos besoins. Les polices et le contenu dessiné ne seront pas déformés. . Après tout, ils sont tous dessinés avec des vecteurs~.
Génération d'interfacesLe div sous-jacent est généré via le composant ht.graph.GraphView. Ensuite, vous pouvez utiliser les bonnes méthodes fournies par HT pour le Web et appeler simplement le pinceau canevas pour dessiner avec désinvolture. Voyons d'abord comment générer le div sous-jacent :
var dm = new ht.DataModel();//Conteneur de données var gv = new ht.graph.GraphView(dm);//Composant de topologie gv.addToDOM();//Ajouter le composant graphique de topologie dans le corps
La fonction addToDOM est déclarée comme suit :
addToDOM = function(){ var self = this, view = self.getView(), style = view.style; document.body.appendChild(view); //Ajoute le div sous-jacent du composant au corps style.left = '0 ';//Le composant par défaut est positionné de manière absolue, donc définissez la position style.right = '0'; style.top = '0'; style.bottom = '0'; () { self.iv(); }, false); //Événement de changement de fenêtre}
Maintenant, je peux griffonner sur ce div ~ D'abord, je récupère les points sur le plan du métro téléchargé, et je les mets dans metro.js. Ce fichier js contient tout le contenu téléchargé, je n'ai rien fait. Les autres changements consistent principalement à les ajouter. pointe vers le tableau en fonction de la ligne, tel que :
mark_Point13 = [];//Le tableau de lignes contient les coordonnées des points de départ et d'arrivée de la ligne ainsi que le nom de la ligne t_Point13 = [];//Le tableau de stations contient les coordonnées de la station de transfert dans la ligne et le nom de la station n_Point13 = [];//Le tableau des petites stations contient les coordonnées des petites stations de la ligne et les noms des petites stations mark_Point13.push({ nom : 'Ligne 13', valeur : [113.4973,23.1095]}); mark_Point13.push({ nom : 'Ligne 13', valeur : [113.4155,23.1080]}); t_Point13.push({ nom : 'Yu Zhu', valeur : [113.41548,23.10547 ]} ); n_Point13.push({ nom : 'Yufengwei', valeur : [113.41548,23.10004]});
Ensuite, pour dessiner les lignes de métro, j'ai déclaré un tableau lineNum pour contenir les numéros de toutes les lignes de métro en js, et un tableau de couleurs pour contenir les couleurs de toutes les lignes de métro. L'index de ces couleurs est le même que celui du métro. line in lineNum Les index numérotés correspondent un à un :
var lineNum = ['1', '2', '3', '30', '4', '5', '6', '7', '8', '9', '13', '14 ', '32', '18', '21', '22', '60', '68'];var couleur = ['#f1cd44', '#0060a1', '#ed9b4f', '#ed9b4f', '#007e3a', '#cb0447', '#7a1a57', '#18472c', '#008193', '#83c39e', '#8a8c29', '#82352b', '#82352b', '#09a1e0', '#8a8c29', '#82352b', '#b6d300', '#09a1e0'];
Ensuite, parcourez lineNum, transmettez les éléments et les couleurs de lineNum à la fonction createLine et dessinez les lignes de métro et la correspondance des couleurs en fonction de ces deux paramètres. Après tout, la méthode de dénomination dans le fichier js est également régulière. Quelle ligne est nommée d'après Add. le numéro correspondant, il suffit donc de combiner la chaîne avec ce numéro pour obtenir le tableau correspondant en js :
let lineName = 'Line' + num; let line = window[lineName]; La définition de createLine est également très simple. Mon code a défini beaucoup de styles, donc cela semble un peu excessif. Pour créer un pipeline ht.Polyline, nous pouvons ajouter des points spécifiques à cette variable via la fonction polyline.addPoint() et définir la méthode de connexion des points via setSegments. function createLine(num, color) {//Dessiner une ligne de carte var polyline = new ht.Polyline();//Polygon pipeline polyline.setTag(num);//Définir l'étiquette de balise de nœud comme seule étiquette if(num = == '68') polyline.setToolTip('AP M');//Définir les informations d'invite sinon if(num === '60') polyline.setToolTip('GF' else); polyline.setToolTip('Line' + num); if(color) { polyline.s({//s est l'abréviation de setStyle, définissez le style 'shape.border.width' : 0,4,//Définissez la largeur de la bordure de le polygone 'shape .border.color': color,//Définir la couleur de la bordure du polygone 'select.width' : 0.2,//Définir la largeur de la bordure du nœud sélectionné'select.color' : color//Définir la couleur de la bordure du nœud sélectionné}); } let lineName = 'Line' + num; for(let i = 0; i < line.length; i++) { for(let j = 0; j < line[i].coords.length; j++) { polyline.addPoint({x : ligne[i].coords[j][0]*300, y : -line[i].coords[j][1]*300} ; if(num === '68'){//ligne APM (Il y en a deux, mais les points sont dans le même tableau) if(i === 0 && j === 0) { polyline.setSegments([1] } else if(i === 1 && j === 0) { polyline.getSegments().push(1); } else { polyline.getSegments().push(2); } } } } polyline.setLayer('0');//Définir la ligne Sur le calque inférieur, le point est placé sur le dessus du calque supérieur dm.add(polyline);//Ajouter le pipeline au conteneur de données pour le stockage, sinon le pipeline est dans un état libre et ne sera pas affiché sur la polyligne de retour de la carte topologique ;}
Il existe plusieurs situations pour ajouter des points sur la ligne de métro dans le code ci-dessus. En effet, Line68 a un point de saut lors de la définition de la ligne dans js, nous devons donc y accéder. L'espace est limité. déclaration spécifique du tableau Line68.
Une chose à noter ici est que si vous utilisez la fonction addPoint et ne définissez pas de segments, les points ajoutés seront connectés par défaut par des lignes droites. La définition des segments est la suivante :
1 : moveTo, occupe 1 point d'information, représentant le point de départ d'un nouveau chemin
2 : lineTo, occupe 1 point d'information, représentant la connexion du dernier point à ce point
3 : quadraticCurveTo, occupe 2 points d'information, le premier point est utilisé comme point de contrôle de la courbe et le deuxième point est utilisé comme point final de la courbe.
4 : bezierCurveTo, occupe 3 informations de points, les premier et deuxième points sont utilisés comme points de contrôle de courbe et le troisième point est utilisé comme point final de courbe
5 : closePath, n'occupe pas d'informations de point, représente la fin de ce tracé de chemin et se ferme au point de départ du chemin
Donc, si nous voulons adopter un comportement de saut, définissez simplement les segments sur 1.
Enfin, ces points sur la ligne de métro sont dessinés. Cette partie est également séparée dans metro.js. Les noms commencent par mark_Point, t_Point et n_Point. J'ai expliqué ces tableaux dans la partie d'affichage js précédente. faites défiler vers le haut pour voir.
Nous ajoutons des nœuds ht.Node à ces points. Lorsque les nœuds sont ajoutés au conteneur de données dm, ils seront affichés sur la carte topologique. Bien sûr, le principe est que le conteneur de données défini par le composant de carte topologique gv est ce dm. . En raison de l'espace limité, je ne montrerai que la partie code pour l'ajout de points sur la ligne de métro :
var tName = 't_Point' + num;var tP = window[tName];//Grande station if(tP) {//Certaines lignes n'ont pas de stations de transfert pour (let i = 0; i < tP.length; i++) { let node = createNode(tP[i].name, tP[i].value, color[index]);//Ajouter un nœud node.s({//Définir le style de style de nœud 'label.scale' : 0,05,//Mise à l'échelle du texte pour éviter les restrictions du navigateur. Le problème de taille de police minimale'label.font' : ' bold 12px arial, sans-serif'//Définissez la police du texte }); node.setSize(0.6, 0.6);//Définissez la taille du nœud. Comme le décalage entre chaque point dans js est trop petit, j'ai dû définir le nœud plus petit node.setImage('images/rotating arrow.json');//Définir l'image du nœud node.a('alarmColor1 ', ' RVB (150, 150, 150)'); //attribut attr, vous pouvez définir n'importe quoi ici. alarmColor1 est l'attribut lié dans le json de l'image définie ci-dessus. Pour plus de détails, veuillez vous référer au manuel HT for Web Vector (http://www.hightopo). .com/guide/guide/core/vector/ht-vector-guide.html#ref_binding) node.a('alarmColor2', 'rgb(150, 150, 150)');//Identique à ci-dessus node.a('tpNode', true);//Ce paramètre d'attribut est uniquement utilisé pour distinguer les sites de transfert et les petits sites, qui seront utilisés plus tard}}
Toutes les lignes et stations de métro ont été ajoutées. mais! Vous ne pourrez peut-être pas voir les graphiques que vous avez dessinés car ils sont trop petits. À ce stade, vous pouvez définir la fonction fitContent sur le composant topologique graphView. À propos, nous avons également défini tout ce qui se trouve sur le graphique topologique pour qu'il soit immobile :
gv.fitContent(false, 0.00001);//Taille adaptative, le paramètre 1 indique s'il faut animer, le paramètre 2 est la valeur de remplissage de gv et la bordure gv.setMovableFunc(function(){ return false;//Définit le nœud sur gv sur être immobile });
Votre carte des itinéraires de métro peut maintenant être affichée ~ Jetons un coup d'œil à l'interaction.
interactionLe premier est l'événement de mouvement de la souris. Lorsque la souris glisse sur une ligne spécifique, la ligne devient plus épaisse et vous pouvez voir le numéro de cette ligne en survolant pendant un moment lorsque la souris se déplace vers un site de transfert ou un petit site. , l'icône correspondant au site deviendra plus grande et lorsque la couleur changera, la police deviendra également plus grande. Lorsque vous déplacerez la souris, l'icône retrouvera sa couleur d'origine et la police deviendra plus petite. La différence est que lorsque la souris se déplace vers la station de transfert, celle-ci tourne.
Pour l'événement de glissement de la souris, j'exécute directement l'événement mousemove basé sur le div sous-jacent de gv. Je passe les paramètres de l'événement via la fonction getDataAt encapsulée par ht, j'obtiens le nœud correspondant sous l'événement, puis je peux faire fonctionner le nœud à volonté:
gv.getView().addEventListener('mousemove', function(e) { var data = gv.getDataAt(e);//Passez le point de coordonnée logique ou le paramètre d'événement d'événement interactif et renvoyez la primitive sous le point actuel if( name ) { originNode(name);//Conserver le nœud à sa taille d'origine à tout moment} if (instance de données de ht.Polyline) {//Déterminez le type de nœud d'événement dm.sm().ss(data);//Sélectionnez le nom du canal = ''; clearInterval(interval); else if (data instanceof ht.Node) { if(data. getTag( ) !== name && data.a('tpNode')) {//S'il ne s'agit pas du même nœud et que l'objet d'événement mousemove est de type ht.Node, définissez l'intervalle de rotation du nœud = setInterval(function() { data.setRotation(data.getRotation() - Math.PI/16); //Rotation en fonction de sa propre rotation}, 100 } if(data.a('npNode')) {/ /Si la souris se déplace vers un petit site, arrêtez l'animation clearInterval(interval } expandNode(data, name);////Fonction de nœud de zoom personnalisée, relativement simple, je ne m'en tiens plus au code, vous pouvez aller sur http://hightopo.com/ pour voir dm.sm().ss(data); //Définissez le nom du nœud sélectionné = data.getTag();//En tant que variable de stockage du nœud précédent, vous pouvez obtenir le nœud via cette valeur} else {//Dans tous les autres cas, rien n'est sélectionné et l'animation est activée le site de transfert est effacé dm.sm( ).ss(null name =); ''; clearInterval(intervalle); }});
Lorsque la souris survole une ligne de métro, les informations spécifiques à la ligne sont affichées en réglant l'info-bulle (remarque : le commutateur d'info-bulle de gv doit être activé) :
gv.enableToolTip();//Activez le commutateur d'info-bulle if(num === '68') polyline.setToolTip('AP M');//Définissez les informations d'invite sinon if(num === '60') polyline.setToolTip('GF'); sinon polyline.setToolTip('Line' + num);
Ensuite, j'utilise le formulaire dans le coin inférieur droit pour cliquer sur une ligne spécifique du formulaire, ou double-cliquez sur n'importe quel site ou ligne sur la carte topologique, et la carte topologique s'adaptera à la partie correspondante, et le double-clic La partie sera affichée au centre de la carte topologique.
Je ne semble pas avoir encore expliqué la partie déclaration du formulaire. . . Il s'agit de créer un composant de formulaire via la nouvelle classe ht.widget.FomePane, d'obtenir le div sous-jacent du composant de formulaire via form.getView(), de placer ce div dans le coin inférieur droit du corps, puis d'ajouter une ligne à le formulaire via la fonction addRow Éléments de formulaire, vous pouvez ajouter n'importe quel nombre d'éléments dans cette ligne, via addRow Le deuxième paramètre de la fonction (un tableau) définit la largeur de l'élément de formulaire ajouté et définit la hauteur de la ligne via le troisième paramètre :
function createForm() {//Créez le formulaire form dans le coin inférieur droit var form = new ht.widget.FormPane(); form.setWidth(200);//Définissez la largeur du formulaire form.setHeight(416);// Définissez la hauteur du formulaire let view = form.getView(); document.body.appendChild(view);//Ajoutez le formulaire dans le corps view.style.zIndex = 1000; view.style.bottom = '10px'; // Presque tous les composants ht définissent des chemins absolus view.style.right = '10px'; view.style.background = 'rgba(211, 211, 211, 0.8)'; forEach(function(nameString) { form.addRow([//Ajouter une ligne au formulaire{//Le premier bouton d'élément de formulaire dans cette ligne : {//Ajouter l'icône du bouton au formulaire : 'images/Line'+nameString.value+'.json',//Définir l'arrière-plan de l'icône du bouton : '',//Définir la couleur de la bordure de l'arrière-plan du bouton : '',//Définir le couleur de la bordure du bouton cliquable : false//Définissez le bouton pour qu'il ne soit pas cliquable} }, {//Le deuxième bouton d'élément de formulaire : { label: nameString.name, labelFont: 'bold 14px arial, sans-serif', labelColor : '#fff', background : '', borderColor : '', onClicked : function() {//Événement de rappel de clic sur le bouton gv.sm().ss(dm.getDataByTag(nameString.value) );//Définit la ligne correspondant au bouton enfoncé sélectionné gv.fitData(gv.sm().ld(), true, 5);//Afficher la ligne de métro sélectionnée au centre de la carte topologique} } } ], [0.1, 0.2], 23);//Le deuxième paramètre consiste à définir la largeur du réseau dans le premier paramètre, moins supérieur à 1 est le ratio, supérieur à 1 est la largeur réelle. Le troisième paramètre est la hauteur de la ligne});}.
Cliquez sur le site pour afficher la marque rouge, double-cliquez sur le nœud pour le placer de manière adaptative au centre de la carte topologique et double-cliquez sur l'espace vide pour masquer la marque rouge. Le contenu est contrôlé via la surveillance des événements du composant topologique. gv. C'est très clair et facile à comprendre. Le code est le suivant :
var node = createRedLight();//Créer un nouveau nœud, affiché sous la forme d'un style de feu rouge gv.mi(function(e) {//Surveillance des événements dans le composant topologique dans ht if(e.kind === 'clickData ' && (e.data.a('tpNode') || e.data.a('npNode'))) {//e.kind obtient le type d'événement actuel, e.data obtient le nœud sous l'événement actuel node.s('2d.visible', true);//Définissez le nœud du nœud pour qu'il soit visible node.setPosition(e. data.getPosition() .x, e.data.getPosition().y);//Définir les coordonnées du nœud à la position du nœud sous l'événement en cours} else if(e.kind === 'doubleClickData') {//Double-cliquez sur le nœud gv.fitData(e.data, false, 10);//Adaptez le nœud sous l'événement au centre de la carte topologique, le paramètre 1 est le nœud adaptatif, le paramètre 2 indique s'il faut animer. , et le paramètre 3 est le remplissage de gv et border } else if(e.kind === 'doubleClickBackground') {//Double-cliquez sur l'espace vide node.s('2d.visible', false);//Définissez le node le nœud doit être invisible View HT for Web Manuel de style (http://www.hightopo.com/guide/guide/core/theme/ht-theme-guide.html#ref_style) }} );
Notez que s (style) et a (attr) sont définis comme ceci. s est un attribut de style prédéfini par ht, et a est un attribut personnalisé par nos utilisateurs. Le résultat est généralement appelé en appelant une chaîne. Cette chaîne correspond à can. être une constante ou une fonction, ce qui est très flexible.
Enfin, une petite partie est réalisée Lorsqu'un site est sélectionné, une icône de respiration rouge s'affichera au-dessus du site pour indiquer le site actuellement sélectionné.
La partie respiration est complétée à l'aide de la fonction setAnimation de ht. Avant d'utiliser cette fonction, vous devez d'abord activer le commutateur d'animation du conteneur de données, puis définir l'animation :
dm.enableAnimation();//Activer la fonction de changement d'animation du conteneur de données createRedLight() { var node = new ht.Node(); node.setImage('images/RedLight.json');//Définir l'image nœud du nœud .setSize(1, 1);//Définir la taille du nœud node.setLayer('firstTop');//Définir le nœud à afficher sur la couche supérieure de gv node.s('2d.visible', false);//Le le nœud est invisible node.s( 'select.width', 0);//La bordure lorsque le nœud est sélectionné est 0 et invisible node.s('2d.selectable', false);//Définissez cet attribut, le nœud ne peut pas être sélectionné node.setAnimation({//Pour plus de détails sur la configuration de l'animation, veuillez vous référer au manuel HT for Web Animation (http://www.hightopo.com/guide/guide /plugin/animation/ht- animation-guide.html) expandWidth: { property: width,//Définissez cette propriété, et si accessType n'est pas défini, la largeur ici et la hauteur en dessous sont définies et obtenues par défaut. Ils sont tous obtenus grâce à la taille précédemment définie de : 0,5, //Valeur de l'attribut au début de l'animation à : 1,//Valeur de l'attribut à la fin de l'animation suivant : collapseWidth//Type de chaîne, spécifie ce qu'il faut exécuter après l'animation actuelle est terminée. L'animation suivante peut fusionner plusieurs animations}, collapseWidth : { property : width, from : 1, to : 0.5, next : expandWidth }, expandHeight : { property : height, from : 0.5, to : 1, suivant : collapsHeight }, collapsHeight : {propriété : hauteur, de : 1, à : 0,5, suivant : expandHeight }, start : [expandWidth, expandHeight]//Array, utilisé pour spécifier une ou plusieurs animations à démarrer} ) ; dm.add(node); return node;}
Tout le code est terminé !
RésumerCette démo m'a pris deux jours et je me suis toujours senti un peu réticent à le faire. Cependant, parfois, ma réflexion ne pouvait pas être inversée et cela prenait beaucoup de temps, mais en général, j'ai beaucoup gagné. penser que tant que j'ai réussi, utilisez simplement getPoints().push pour ajouter des points au polygone. Après avoir demandé l'aide d'un maître, j'ai découvert que cette méthode ne faisait pas que des détours mais causait également divers problèmes, par exemple, avant d'obtenir des points. , vous devez déjà avoir des points dans le polygone. C'est possible, mais dans de nombreux cas, les points initialisés ne sont pas faciles à définir et le code sera très fastidieux. Les points sont directement ajoutés à la variable polygone via la méthode addPoint, et les points sont connectés par des lignes droites par défaut. Il n'est pas nécessaire de définir des segments, quelle belle fonction.
De plus, comme la taille de zoom par défaut de ht est de 20 et que l'espacement de ma démo est très petit, l'affichage de la carte des lignes de métro est également très petit lorsqu'il est zoomé au maximum, j'ai donc modifié l'attribut zoomMax par défaut de ht dans htconfig. , change Cette valeur doit être avant tous les appels ht, car les valeurs définies dans htconfig ne peuvent pas être modifiées ultérieurement.
Ce qui précède est le plan interactif des lignes de métro basé sur HTML5 Canvas que l'éditeur vous présente. J'espère qu'il vous sera utile. Si vous avez des questions, veuillez me laisser un message et l'éditeur vous répondra à temps. Je tiens également à remercier tout le monde pour votre soutien au site d'arts martiaux VeVb !