Quando eu estava procurando inspiração em echarts há dois dias, vi muitos exemplos semelhantes de mapas, posicionamento de mapas, etc., mas parecia não haver nenhum mapa do metrô, então passei algum tempo mexendo nesta demonstração interativa do mapa do metrô, o. pontos da linha do metrô foram baixados aleatoriamente da Internet. Este artigo registra alguns dos meus ganhos (afinal, ainda sou um novato) e a implementação do código, espero que possa ajudar alguns amigos. Claro, se você tiver alguma opinião, pode me dizer diretamente. Somente nos comunicando podemos progredir.
renderizações
http://www.hightopo.com/demo/subway/index.html
O mapa tem muito conteúdo. Se você quiser exibir tudo, as fontes parecerão um pouco pequenas, mas não importa. Você pode aumentar e diminuir o zoom conforme necessário. Afinal, todos eles são desenhados com vetores ~.
Geração de interfaceO div subjacente é gerado por meio do componente ht.graph.GraphView. Então você pode usar os bons métodos fornecidos pelo HT for Web e apenas chamar o pincel de tela para desenhar casualmente.
var dm = new ht.DataModel();//Contêiner de dados var gv = new ht.graph.GraphView(dm);//Componente de topologia gv.addToDOM();//Adiciona o componente gráfico de topologia ao corpo
A função addToDOM é declarada da seguinte forma:
addToDOM = function(){ var self = this, view = self.getView(), style = view.style; document.body.appendChild(view); '0 ';//O componente padrão é posicionado de forma absoluta, então defina a posição style.right = '0'; style.top = '0'; () { self.iv(); }, false); //Evento de mudança de janela}
Agora posso rabiscar neste div ~ Primeiro pego os pontos no mapa do metrô baixado e os coloco em Subway.js. Este arquivo js é todo o conteúdo baixado, não fiz nada. Outras alterações são principalmente para adicioná-los. aponta para a matriz de acordo com a linha, como:
mark_Point13 = [];//A matriz de linha contém as coordenadas dos pontos inicial e final da linha e o nome da linha t_Point13 = [];//A matriz de estação contém as coordenadas da estação de transferência na linha e o nome da estação n_Point13 = [];//O array da estação pequena contém as coordenadas das estações pequenas na linha e os nomes das estações pequenas mark_Point13.push({ name: 'Line 13', value: [113.4973,23.1095]}); mark_Point13.push({ nome: 'Linha 13', valor: [113.4155,23.1080]}); );n_Point13.push({ nome: 'Yufengwei', valor: [113.41548,23.10004]});
A seguir, para desenhar as linhas do metrô, declarei um array lineNum para armazenar os números de todas as linhas do metrô em js, e um array color para armazenar as cores de todas as linhas do metrô. linha em lineNum Os índices numerados correspondem um a um:
var lineNum = ['1', '2', '3', '30', '4', '5', '6', '7', '8', '9', '13', '14 ', '32', '18', '21', '22', '60', '68'];var cor = ['#f1cd44', '#0060a1', '#ed9b4f', '#ed9b4f', '#007e3a', '#cb0447', '#7a1a57', '#18472c', '#008193', '#83c39e', '#8a8c29', '#82352b', '#82352b', '#09a1e0', '#8a8c29', '#82352b', '#b6d300', '#09a1e0'];
Em seguida, atravesse lineNum, passe os elementos e cores em lineNum para a função createLine e desenhe as linhas do metrô e a correspondência de cores de acordo com esses dois parâmetros. Afinal, o método de nomenclatura no arquivo js também é regular. o número correspondente, então só precisamos combinar a string com este número para obter o array correspondente em js:
let lineName = 'Line' + num; let line = window[lineName]; A definição de createLine também é muito simples. Para criar um pipeline ht.Polyline, podemos adicionar pontos específicos a esta variável por meio da função polyline.addPoint() e definir o método de conexão dos pontos por meio de setSegments. function createLine(num, color) {//Desenhe uma linha do mapa var polyline = new ht.Polyline();//Polygon pipeline polyline.setTag(num); //Defina o rótulo da tag do nó como o único rótulo if(num = == '68') polyline.setToolTip('AP M');//Definir informações de prompt else if(num === '60') polyline.setToolTip('G F'); polyline.setToolTip('Line' + num); if(color) { polyline.s({//s é a abreviatura de setStyle, defina o estilo 'shape.border.width': 0.4,//Defina a largura da borda de o polígono 'shape .border.color': color, // Define a cor da borda do polígono 'select.width': 0.2,//Definir a largura da borda do nó selecionado'select.color': color//Definir a cor da borda do nó selecionado} } let lineName = 'Line' + num; for(deixe i = 0; i < line.length; i++) { for(deixe j = 0; j < line[i].coords.length; j++) { polyline.addPoint({x: linha[i].coords[j][0]*300, y: -line[i].coords[j][1]*300}); if(num === '68'){//linha APM (Existem dois, mas os pontos estão na mesma matriz) if(i === 0 && j === 0) { polyline.setSegments([1] } else if(i === 1 &&); j === 0) { polyline.getSegments().push(1 } else { polyline.getSegments().push(2); Na camada inferior, o ponto é definido no topo da camada superior dm.add(polyline);//Adiciona o pipeline ao contêiner de dados para armazenamento, caso contrário, o pipeline estará em estado livre e não será exibido na polilinha de retorno do mapa de topologia;}
Existem várias situações para adicionar pontos na linha do metrô no código acima. Isso ocorre porque Line68 tem um ponto de salto ao definir a linha em js, então devemos pular para ele. O espaço é limitado. declaração específica do array Line68.
Uma coisa a notar aqui é que se você usar a função addPoint e não definir segmentos, os pontos adicionados serão conectados com linhas retas por padrão. A definição de segmentos é a seguinte:
1: moveTo, ocupa 1 ponto de informação, representando o ponto inicial de um novo caminho
2: lineTo, ocupa 1 ponto de informação, representando a conexão do último ponto até este ponto
3: quadraticCurveTo, ocupa informações de 2 pontos, o primeiro ponto é usado como ponto de controle da curva e o segundo ponto é usado como ponto final da curva
4: bezierCurveTo, ocupa informações de 3 pontos, o primeiro e o segundo pontos são usados como pontos de controle da curva e o terceiro ponto é usado como ponto final da curva
5: closePath, não ocupa informação de ponto, representa o final deste desenho de caminho e fecha até o ponto inicial do caminho
Então, se quisermos fazer um comportamento de salto, basta definir os segmentos como 1.
Finalmente, esses pontos na linha do metrô são desenhados. Esta parte também é separada em Subway.js. Os nomes começam com mark_Point, t_Point e n_Point. Expliquei essas matrizes na parte de exibição js anterior. role para cima para ver a aparência.
Adicionamos nós ht.Node nesses pontos. Quando os nós são adicionados ao contêiner de dados dm, eles serão exibidos no mapa de topologia. Obviamente, a premissa é que o contêiner de dados definido pelo componente do mapa de topologia gv seja este dm. . Devido ao espaço limitado, mostrarei apenas a parte do código para adição de pontos na linha do metrô:
var tName = 't_Point' + num;var tP = window[tName];//Estação grande if(tP) {//Algumas linhas não possuem estações de transferência for(let i = 0; i < tP.length; i++) { deixe node = createNode(tP[i].nome, tP[i].valor, color[index]);//Adicionar nó node.s({//Definir o estilo do nó 'label.scale': 0.05,//Escala de texto para evitar restrições do navegador O problema do tamanho mínimo da fonte'label.font': ' negrito 12px arial, sans-serif'//Definir a fonte do texto }); node.setSize(0.6, 0.6);//Definir o tamanho do nó. Como o deslocamento entre cada ponto em js é muito pequeno, tive que definir o nó menor node.setImage('images/rotating arrow.json');//Definir a imagem do nó node.a('alarmColor1 ', ' rgb(150, 150, 150)'); //atributo attr, você pode definir qualquer coisa aqui. alarmColor1 é o atributo vinculado ao json da imagem definida acima. .com/guide/guide/core/vector/ht-vector-guide.html#ref_binding) node.a('alarmColor2', 'rgb(150, 150, 150)');//Igual ao acima node.a('tpNode', true);//Esta configuração de atributo é usada apenas para distinguir sites de transferência e sites pequenos, que serão usados posteriormente}}
Todas as linhas e estações de metrô foram adicionadas. mas! Talvez você não consiga ver os gráficos que desenhou porque eles são muito pequenos. Neste momento, você pode definir a função fitContent no componente de topologia graphView. A propósito, também definimos tudo no gráfico de topologia como imóvel:
gv.fitContent(false, 0,00001);//Tamanho adaptativo, o parâmetro 1 é se deseja animar, o parâmetro 2 é o valor de preenchimento de gv e borda gv.setMovableFunc(function(){ return false;//Define o nó em gv para ser imóvel });
Agora seu mapa de rotas do metrô pode ser exibido ~ Vamos dar uma olhada na interação.
interaçãoO primeiro é o evento de movimento do mouse. Quando o mouse desliza sobre uma linha específica, a linha fica mais espessa e você pode ver o número dessa linha passando o mouse por um tempo. , o ícone correspondente ao site ficará maior e Quando a cor mudar, a fonte também ficará maior. Ao mover o mouse, o ícone retornará à sua cor original e a fonte ficará menor. A diferença é que quando o mouse se move para a estação de transferência, a estação de transferência irá girar.
Para o evento de deslizamento do mouse, executo diretamente o evento mousemove com base no div subjacente de gv. Passo os parâmetros do evento por meio da função getDataAt encapsulada por ht, obtenho o nó correspondente no evento e então posso operar o nó em. vai:
gv.getView().addEventListener('mousemove', function(e) { var data = gv.getDataAt(e);//Passe o ponto de coordenada lógica ou parâmetro de evento de evento interativo e retorne o primitivo sob o ponto atual if( name ) { originNode(name); //Mantenha o nó em seu tamanho original sempre} if (data instanceof ht.Polyline) {//Determine o tipo de nó de evento dm.sm().ss(data);//Selecione o nome do pipe = ''; clearInterval(interval } else if (data instanceof ht.Node) { if(data. getTag() !== name && data.a('tpNode')) {//Se não for o mesmo nó e o objeto de evento mousemove for do tipo ht.Node, defina o intervalo de rotação do nó = setInterval(function() { data.setRotation(data.getRotation() - Math.PI/16); //Rota com base em sua própria rotação}, 100 } if(data.a('npNode')) {/ /Se o mouse for para um site pequeno, pare a animação clearInterval(interval } expandNode(data, name);////Função de nó de zoom personalizada, relativamente fácil, não me prendo mais ao código, você pode acessar http://hightopo.com/ para visualizar dm.sm().ss(data); //Defina o nome do nó selecionado = data.getTag();//Como variável de armazenamento do nó anterior, você pode obter o nó através deste valor} else {//Em qualquer outro caso, nada é selecionado e a animação é ativada o site de transferência está limpo dm.sm( ).ss(null name =); ''; clearInterval(intervalo);
Quando o mouse passa sobre uma linha de metrô, as informações específicas da linha são exibidas. Eu faço isso configurando a dica de ferramenta (nota: a opção de dica de ferramenta do gv deve estar ativada):
gv.enableToolTip();//Ativa a opção de dica de ferramenta if(num === '68') polyline.setToolTip('AP M');//Define as informações do prompt else if(num === '60') polyline.setToolTip('GF'); senão polyline.setToolTip('Linha' + num);
Então eu uso o formulário no canto inferior direito para clicar em uma linha específica do formulário, ou clico duas vezes em qualquer site ou linha no mapa de topologia, e o mapa de topologia se adaptará à parte correspondente, e o clique duplo parte será exibida no centro do mapa de topologia.
Parece que ainda não expliquei a parte da declaração do formulário. . . Isso é criar um componente de formulário de formulário por meio da nova classe ht.widget.FomePane, obter o div subjacente do componente de formulário por meio de form.getView(), colocar esse div no canto inferior direito do corpo e, em seguida, adicionar uma linha para o formulário através da função addRow Itens de formulário, você pode adicionar qualquer número de itens nesta linha, através de addRow O segundo parâmetro da função (um array) define a largura do item de formulário adicionado e define a altura da linha por meio do terceiro parâmetro:
function createForm() {//Cria o formulário no canto inferior direito var form = new ht.widget.FormPane();//Define a largura do formulário form.setHeight(416);// Defina a altura do formulário let view = form.getView(); document.body.appendChild(view);//Adicione o formulário ao corpo view.style.zIndex = 1000; view.style.bottom = '10px'; // Quase todos os componentes ht definem caminhos absolutos view.style.right = '10px'; forEach(function(nameString) { form.addRow([//Adicionar uma linha ao formulário{//O primeiro botão de item de formulário nesta linha: {//Adicione o ícone do botão ao formulário: 'images/Line'+nameString.value+'.json',//Defina o fundo do ícone do botão: '',//Defina o fundo do botão borderColor: '',//Defina o cor da borda do botão clicável: false//Definir o botão como não clicável} }, {//O segundo botão do item do formulário: { label: nameString.name, labelFont: 'bold 14px arial, sans-serif', labelColor: '#fff', background: '', borderColor: '', onClicked: function() {//Evento de retorno de chamada de clique no botão gv.sm().ss(dm.getDataByTag(nameString.value) );//Define a linha correspondente ao botão pressionado selecionado gv.fitData(gv.sm().ld(), true, 5);//Exibe a linha de metrô selecionada no centro do mapa de topologia} } } ], [0.1, 0.2], 23);//O segundo parâmetro é definir a largura do array no primeiro parâmetro, menos que 1 é a proporção, maior que 1 é a largura real. O terceiro parâmetro é a altura da linha});}.
Clique no site para exibir a marca vermelha, clique duas vezes no nó para colocá-lo de forma adaptativa no centro do mapa de topologia e clique duas vezes no espaço em branco para ocultar a marca vermelha. O conteúdo é controlado por meio do monitoramento de eventos do componente de topologia. gv. É muito claro e fácil de entender.
var node = createRedLight();//Cria um novo nó, exibido como um estilo de luz vermelha gv.mi(function(e) {//Monitoramento de eventos no componente de topologia em ht if(e.kind === 'clickData ' && (e.data.a('tpNode') || e.data.a('npNode'))) {//e.kind obtém o tipo de evento atual, e.data obtém o nó sob o evento atual node.s('2d.visible', true);//Define o nó node como visível node.setPosition(e. data.getPosition() .x, e.data.getPosition().y);//Define as coordenadas do nó para a posição do nó sob o evento atual} else if(e.kind === 'doubleClickData') {//Clique duas vezes no nó gv.fitData(e.data, false, 10);//Adapte o nó sob o evento ao centro do mapa de topologia. O parâmetro 1 é o nó adaptativo, o parâmetro 2 é se deve ser animado. , e o parâmetro 3 é Padding of gv and border } else if(e.kind === 'doubleClickBackground') {//Clique duas vezes no espaço em branco node.s('2d.visible', false);//Defina o nó nó será invisível Ver HT para Web Manual de Estilo (http://www.hightopo.com/guide/guide/core/theme/ht-theme-guide.html#ref_style) }});
Observe que s (style) e a (attr) são definidos assim. s são alguns atributos de estilo predefinidos por ht, e a é um atributo personalizado por nossos usuários. O resultado geralmente é chamado chamando uma string. ser uma constante ou uma função, que é muito flexível.
Finalmente, uma pequena parte é feita. Quando um site é selecionado, um ícone vermelho de respiração será exibido acima do site para indicar o site atualmente selecionado.
A parte respiratória é concluída usando a função setAnimation de ht. Antes de usar esta função, você deve primeiro ativar a opção de animação do contêiner de dados e, em seguida, definir a animação:
dm.enableAnimation();//Ativa a função de troca de animação do contêiner de dados createRedLight() { var node = new ht.Node(); nó do nó .setSize(1, 1);//Defina o tamanho do nó node.setLayer('firstTop');//Defina o nó a ser exibido na camada superior do gv node.s('2d.visible', false);//O o nó é invisível node.s( 'select.width', 0);//A borda quando o nó é selecionado é 0 e invisível node.s('2d.selectable', false);//Defina este atributo, o nó não pode ser selecionado node.setAnimation({//Para obter detalhes sobre como configurar a animação, consulte o Manual do HT para animação na Web (http://www.hightopo.com/guide/guide /plugin/animation/ht-animation-guide.html) expandWidth: { property: width,//Defina esta propriedade, e se accessType não estiver definido, a largura aqui e a altura abaixo são definidas e obtidas por padrão. Todos eles são obtidos através do tamanho definido anteriormente de: 0,5, //Valor do atributo no início da animação até: 1,//Valor do atributo no final da animação próximo: colapsoWidth//Tipo String, especifica o que executar depois a animação atual é concluída A próxima animação pode mesclar várias animações}, colapsoWidth: { propriedade: largura, de: 1, a: 0,5, próximo: expandWidth }, expandHeight: { propriedade: altura, de: 0,5, a: 1, próximo: colapsoHeight }, colapsoHeight: { propriedade: altura, de: 1, a: 0,5, próximo: expandHeight }, início: [expandWidth, expandHeight]//Array, usado para especificar uma ou mais animações a serem iniciadas} ) ;dm.add(nó); retornar nó;}
Todo o código acabou!
ResumirEssa demonstração demorou dois dias para ser concluída e sempre me senti um pouco sem vontade de fazê-lo. Porém, às vezes meu pensamento não conseguia mudar e demorava muito, mas no geral ganhei muito. pensar que, desde que eu passe, basta usar getPoints().push para adicionar pontos ao polígono. Depois de pedir ajuda a um mestre, descobri que esse método não apenas desvia, mas também causa vários problemas. , você já deve ter pontos no polígono. É possível, mas em muitos casos, os pontos inicializados não são fáceis de definir e o código será muito complicado. Os pontos são adicionados diretamente à variável polígono através do método addPoint e os pontos são conectados por linhas retas por padrão. Não há necessidade de definir segmentos, que função adorável.
Além disso, como o tamanho de zoom padrão de ht é 20 e o espaçamento da minha demonstração é muito pequeno, a exibição do mapa da linha de metrô também é muito pequena quando ampliada ao máximo, então alterei o atributo zoomMax padrão de ht em htconfig. , change Este valor deve estar antes de todas as chamadas ht, pois os valores definidos em htconfig não podem ser alterados posteriormente.
O texto acima é o mapa interativo da linha de metrô baseado em HTML5 Canvas que o editor apresenta a você. Espero que seja útil para você. Se você tiver alguma dúvida, deixe-me uma mensagem e o editor responderá a tempo. Gostaria também de agradecer a todos pelo apoio ao site de artes marciais VeVb!