이틀 전 echarts에서 영감을 얻으려고 했을 때 비슷한 지도, 지도 위치 지정 등의 예를 많이 봤는데 지하철 노선도가 없는 것 같아서 이 대화형 지하철 지도 데모를 만지작거리며 시간을 보냈습니다. 지하철 노선의 포인트는 인터넷에서 무작위로 다운로드되었습니다. 이 기사에는 제가 얻은 것 중 일부(결국 저는 아직 신인입니다)와 코드 구현이 일부 친구들에게 도움이 되기를 바랍니다. 물론, 의견이 있으시면 직접 말씀해 주셔도 됩니다. 함께 소통해야만 발전할 수 있습니다.
렌더링
http://www.hightopo.com/demo/subway/index.html
지도에 내용이 좀 많아서 다 표시하고 싶으면 글꼴이 조금 작게 나오겠지만 필요에 따라 확대하거나 축소해도 상관없습니다. . 역시 다 벡터로 그린거군요~
인터페이스 생성기본 div는 ht.graph.GraphView 구성 요소를 통해 생성됩니다. 그런 다음 웹용 HT에서 제공하는 좋은 방법을 사용하고 캔버스 브러시를 호출하여 기본 div를 생성하는 방법을 먼저 살펴보겠습니다.
var dm = new ht.DataModel();//데이터 컨테이너 var gv = new ht.graph.GraphView(dm);//토폴로지 구성 요소 gv.addToDOM();//본문에 토폴로지 그래프 구성 요소 추가
addToDOM 함수는 다음과 같이 선언됩니다.
addToDOM = function(){ var self = this, view = self.getView(), style = view.style; document.body.appendChild(view); //본문에 구성 요소의 기본 div 추가 style.left = '0';//기본 구성 요소는 절대 위치이므로 위치를 설정합니다. style.right = '0'; style.bottom = '0'; () { self.iv() }, false); //창 변경 이벤트}
이제 이 div에 낙서를 할 수 있어요~ 먼저 다운로드한 지하철 노선도에서 포인트를 구해서 Subway.js에 넣습니다. 이 js 파일은 다운로드한 내용이 전부이고 제가 한 일은 없습니다. 다른 변경 사항은 주로 이것들을 추가하는 것입니다. 다음과 같이 라인에 따라 배열을 가리킵니다.
mark_Point13 = [];//선 배열에는 선의 시작 및 끝 좌표와 선 이름이 포함됩니다. t_Point13 = [];//역 배열에는 선의 환승역 좌표와 역 이름이 포함됩니다. n_Point13 = [ ];//소형 역 배열에는 해당 노선의 소역 좌표와 소역 이름이 포함됩니다. mark_Point13.push({ name: '13호선', value: [113.4973,23.1095]}); mark_Point13.push({ 이름: '라인 13', 값: [113.4155,23.1080]}) t_Point13.push({ 이름: 'Yu Zhu', 값: [113.41548,23.10547 ]} ); n_Point13.push({ 이름: 'Yufengwei', 값: [113.41548,23.10004]});
다음으로 지하철 노선을 그리기 위해 js에서 모든 지하철 노선의 번호를 담는 lineNum 배열과 모든 지하철 노선의 색상을 담는 color 배열을 선언했습니다. lineNum의 행 번호가 매겨진 인덱스는 1대1에 해당합니다.
var lineNum = ['1', '2', '3', '30', '4', '5', '6', '7', '8', '9', '13', '14 ', '32', '18', '21', '22', '60', '68'];var color = ['#f1cd44', '#0060a1', '#ed9b4f', '#ed9b4f', '#007e3a', '#cb0447', '#7a1a57', '#18472c', '#008193', '#83c39e', '#8a8c29', '#82352b', '#82352b', '#09a1e0', '#8a8c29', '#82352b', '#b6d300', '#09a1e0'];
그런 다음 lineNum을 순회하고 lineNum의 요소와 색상을 createLine 함수에 전달하고 이 두 매개변수에 따라 지하철 노선과 색상을 그립니다. 결국 js 파일의 명명 방법도 Add 뒤에 이름이 지정됩니다. 해당 숫자이므로 js에서 해당 배열을 얻으려면 문자열을 이 숫자와 결합하기만 하면 됩니다.
let lineName = 'Line' + num; let line = window[lineName]; createLine의 정의도 매우 간단합니다. 제 코드에는 많은 스타일이 설정되어 있어 좀 과해 보입니다. ht.Polyline 파이프라인을 생성하려면 polyline.addPoint() 함수를 통해 이 변수에 특정 점을 추가하고 setSegments를 통해 점의 연결 방법을 설정할 수 있습니다. function createLine(num, color) {//맵 라인 그리기 var polyline = new ht.Polyline();//다각형 파이프라인 polyline.setTag(num);//노드 태그 레이블을 유일한 레이블로 설정 if(num = == '68') 폴리라인.setToolTip('AP M');//프롬프트 정보 설정 else if(num === '60') 폴리라인.setToolTip('G F') else 폴리라인.setToolTip('Line' + num); if(color) { 폴리라인.s({//s는 setStyle의 약어입니다. 스타일 'shape.border.width'를 설정합니다: 0.4,//테두리 너비를 설정합니다. 다각형 'shape .border.color': color,//다각형 'select.width'의 테두리 색상 설정: 0.2,//선택한 노드의 테두리 너비 설정'select.color': color//선택한 노드의 테두리 색상 설정}) } let lineName = 'Line' + num; for(let i = 0; i < line.length; i++) { for(let j = 0; j < line[i].coords.length; j++) { 폴리라인.addPoint({x: line[i].coords[j][0]*300, y: -line[i].coords[j][1]*300}); if(num === '68'){//APM 라인 (두 개가 있지만 점은 동일한 배열에 있습니다) if(i === 0 && j === 0) { polyline.setSegments([1]) } else if(i === 1 && j === 0) { 폴리라인.getSegments().push(1); } else { 폴리라인.getSegments().push(2) } } } } 폴리라인.setLayer('0');//라인 설정 하위 레이어에서는 상위 레이어 상단에 포인트가 설정됩니다. dm.add(polyline);//저장을 위해 데이터 컨테이너에 파이프라인을 추가합니다. 그렇지 않으면 파이프라인이 자유 상태가 되어 토폴로지 맵 반환 폴리라인에 표시되지 않습니다.}
위 코드에서 지하철 노선에 포인트를 추가하는 경우는 여러 가지가 있습니다. 이는 Line68이 js에서 노선을 설정할 때 점프 지점이 있기 때문에 Line68의 특정 선언에 대해서는 점프해야 하는 공간이 있기 때문입니다. 배열, Subway.js를 참조하세요.
여기서 주의할 점은 addPoint 함수를 사용하고 선분을 설정하지 않으면 기본적으로 추가된 점은 직선으로 연결된다는 점입니다. 선분의 정의는 다음과 같습니다.
1: moveTo는 1개의 포인트 정보를 차지하며 새 경로의 시작점을 나타냅니다.
2: lineTo는 1개의 포인트 정보를 차지하며 마지막 포인트에서 이 포인트까지의 연결을 나타냅니다.
3: QuadraticCurveTo는 2개의 포인트 정보를 차지하며, 첫 번째 포인트는 커브 제어점으로, 두 번째 포인트는 커브 끝점으로 사용됩니다.
4: bezierCurveTo는 3개의 점 정보를 차지하며 첫 번째와 두 번째 점은 곡선 제어점으로 사용되며 세 번째 점은 곡선 끝점으로 사용됩니다.
5: closePath는 포인트 정보를 차지하지 않으며 이 경로 그리기의 끝을 나타내고 경로의 시작점에 가깝습니다.
따라서 점프 동작을 수행하려면 세그먼트를 1로 설정하면 됩니다.
마지막으로 지하철 노선의 이러한 점들이 그려집니다. 이 부분도 Subway.js에서 구분됩니다. 이름은 이전 js 표시 부분에서 설명했습니다. 가운데 손가락을 움직여 스크롤할 수 있습니다. 보기까지.
이 지점에 ht.Node 노드를 추가합니다. 노드가 dm 데이터 컨테이너에 추가되면 토폴로지 맵에 표시됩니다. 물론, 토폴로지 맵 구성 요소 gv에 의해 설정된 데이터 컨테이너는 이 dm입니다. . 공간이 제한되어 있으므로 지하철 노선에 포인트를 추가하는 코드 부분만 보여드리겠습니다.
var tName = 't_Point' + num;var tP = window[tName];//대형 역 if(tP) {//일부 노선에는 환승역이 없습니다. for(let i = 0; i < tP.length; i++) { 노드 = createNode(tP[i].name, tP[i].value, color[index]);//노드 추가 node.s({//노드 스타일 스타일 'label.scale' 설정: 0.05,//브라우저 제한을 피하기 위해 텍스트 크기 조정 최소 글꼴 크기 문제'label.font': ' 굵은 12px arial, sans-serif'//텍스트 글꼴 설정 }) node.setSize(0.6, 0.6);//노드 크기 설정. js의 각 지점 사이의 오프셋이 너무 작기 때문에 노드를 더 작게 설정해야 했습니다. node.setImage('images/rotating arrow.json');//노드의 이미지 설정 node.a('alarmColor1 ', ' RGB(150, 150, 150)'); //attr 속성은 여기서 무엇이든 설정할 수 있습니다. AlarmColor1은 위에서 설정한 이미지의 json에 바인딩된 속성입니다. 자세한 내용은 웹 벡터 매뉴얼(http://www.hightopo)을 참조하세요. .com/guide/guide/core/Vector/ht-Vector-guide.html#ref_bind) node.a('alarmColor2', 'rgb(150, 150, 150)');//위와 동일 node.a('tpNode', true);//이 속성 설정은 전송 사이트와 소규모 사이트를 구분하는 데에만 사용되며 나중에 사용됩니다.}}
모든 지하철 노선과 역이 추가되었습니다. 하지만! 그래프가 너무 작아서 보이지 않을 수도 있습니다. 이때 graphView 토폴로지 구성 요소에서 fitContent 함수를 설정할 수도 있습니다. 그런데 토폴로지 그래프의 모든 항목도 움직이지 않도록 설정합니다.
gv.fitContent(false, 0.00001);//적응형 크기, 매개변수 1은 애니메이션 여부, 매개변수 2는 gv 및 테두리의 패딩 값입니다. gv.setMovableFunc(function(){ return false;//gv의 노드를 다음으로 설정합니다. 움직이지 않아야 합니다 });
이제 지하철 노선도가 표시됩니다~ 상호작용을 살펴보겠습니다.
상호 작용첫 번째는 마우스 이동 이벤트입니다. 특정 선 위로 마우스를 이동하면 선이 굵어집니다. 잠시 동안 마우스를 이동하면 이 선의 번호도 표시됩니다. 작은 사이트의 경우 해당 사이트에 해당하는 아이콘이 커지고, 색상이 변경되면 글꼴도 커지며, 마우스를 이동하면 아이콘이 원래 색상으로 돌아가고 글꼴도 작아집니다. 차이점은 마우스가 전송 스테이션으로 이동하면 전송 스테이션이 회전한다는 것입니다.
마우스 슬라이딩 이벤트의 경우 gv의 기본 div를 기반으로 mousemove 이벤트를 직접 수행하고, ht로 캡슐화된 getDataAt 함수를 통해 이벤트 매개변수를 전달하고, 이벤트 아래에 해당 노드를 얻은 다음 마음대로 노드를 조작할 수 있습니다. :
gv.getView().addEventListener('mousemove', function(e) { var data = gv.getDataAt(e);//논리적 좌표점 또는 대화형 이벤트 이벤트 매개변수를 전달하고 현재 지점 아래의 프리미티브를 반환합니다. if( name ) { OriginNode(name);//노드를 항상 원래 크기로 유지} if (data instanceof ht.Polyline) {//이벤트 노드 유형 결정 dm.sm().ss(data);//파이프 이름 선택 = '';clearInterval(interval) } else if (data instanceof ht.Node) { if(data. getTag( ) !== name && data.a('tpNode')) {//동일한 노드가 아니고 mousemove 이벤트 객체가 ht.Node 유형인 경우 노드의 회전 간격을 설정합니다. = setInterval(function() { data.setRotation(data.getRotation() - Math.PI/16); //자체 회전을 기준으로 회전}, 100) } if(data.a('npNode')) {/ /마우스가 작은 사이트로 이동하면 애니메이션을 중지합니다.clearInterval(interval) }expandNode(data, name);////사용자 정의된 확대/축소 노드 기능, 비교적 쉽습니다. 더 이상 코드에 집착하지 않습니다. http://hightopo.com/으로 이동하여 dm.sm().ss(data)를 볼 수 있습니다. //선택한 노드 이름 설정 = data.getTag();//이전 노드의 저장변수로 이 값을 통해 노드를 구할 수 있습니다.} else {//그 외의 경우에는 아무것도 선택되지 않고 애니메이션이 실행됩니다. 전송 사이트가 삭제되었습니다. dm.sm( ).ss(null) name = ''; 클리어간격(간격) }});
마우스를 지하철 노선 위로 가져가면 특정 노선 정보가 표시됩니다. 툴팁을 설정하면 됩니다(참고: gv의 툴팁 스위치를 켜야 합니다).
gv.enableToolTip();//툴팁 스위치 켜기 if(num === '68') polyline.setToolTip('AP M');//프롬프트 정보 설정 else if(num === '60') 폴리라인.setToolTip('G F'); else 폴리라인.setToolTip('Line' + num);
그런 다음 오른쪽 하단에 있는 양식 양식을 사용하여 양식의 특정 줄을 클릭하거나 토폴로지 맵의 사이트나 줄을 두 번 클릭하면 토폴로지 맵이 해당 부분에 맞게 조정되고 두 번 클릭한 부분이 표시됩니다. 토폴로지 맵의 중앙에 표시됩니다.
아직 폼의 선언 부분을 설명하지 못한 것 같습니다. . . 즉, 새로운 ht.widget.FomePane 클래스를 통해 폼 폼 컴포넌트를 생성하고, form.getView()를 통해 폼 컴포넌트의 기본 div를 얻고, 이 div를 본문의 오른쪽 하단에 배치한 다음 행을 추가합니다. addRow 함수를 통해 양식 양식 항목을 추가하려면 addRow를 통해 이 행에 항목을 원하는 만큼 추가할 수 있습니다. 함수의 두 번째 매개변수(배열)는 추가된 양식 항목의 너비를 설정하고, 세 번째 매개변수는 행의 높이를 설정합니다.
function createForm() {//오른쪽 하단에 양식 양식을 생성합니다. var form = new ht.widget.FormPane(); form.setWidth(200);//양식 너비 설정 form.setHeight(416);// 양식 높이 설정 let view = form.getView(); document.body.appendChild(view);//본문에 양식 추가 view.style.zIndex = 1000; view.style.bottom = '10px'; // 거의 모든 ht 구성요소는 절대 경로를 설정합니다. view.style.right = '10px'; view.style.Background = 'rgba(211, 211, 211, 0.8)'; forEach(function(nameString) { form.addRow([//양식에 행 추가{//이 행의 첫 번째 양식 항목 버튼: {//양식에 버튼 아이콘 추가: 'images/Line'+nameString.value+'.json',//버튼 아이콘 배경 설정: '',//버튼 배경 borderColor 설정: '',//The 버튼의 테두리 색상을 클릭 가능: false//버튼을 클릭할 수 없도록 설정} }, {//두 번째 양식 항목 버튼: { label: nameString.name, labelFont: 'bold 14px arial, sans-serif', labelColor: '#fff', background: '', borderColor: '', onClicked: function() {//버튼 클릭 콜백 이벤트 gv.sm().ss(dm.getDataByTag(nameString.value) );//선택한 누른 버튼에 해당하는 라인을 설정합니다. gv.fitData(gv.sm().ld(), true, 5);//선택한 지하철 노선을 토폴로지 맵 중앙에 표시} } } ], [0.1, 0.2], 23);//두 번째 매개변수는 첫 번째 매개변수에 배열의 너비를 설정하는 것입니다. 1보다 큰 것은 비율이고, 1보다 큰 것은 실제 너비입니다. 세 번째 매개변수는 행의 높이});}입니다.
해당 사이트를 클릭하면 빨간색 마크가 표시되고, 노드를 더블 클릭하면 토폴로지 맵 중앙에 적응적으로 배치되며, 빈 공간을 더블 클릭하면 빨간색 마크가 숨겨집니다. 해당 콘텐츠는 토폴로지 구성 요소의 이벤트 모니터링을 통해 제어됩니다. gv. 코드는 다음과 같이 매우 명확하고 이해하기 쉽습니다.
var node = createRedLight();//빨간색 표시등 스타일로 표시되는 새 노드 생성 gv.mi(function(e) {//ht if(e.kind === 'clickData'의 토폴로지 구성 요소에서 이벤트 모니터링 && (e.data.a('tpNode') || e.data.a('npNode'))) {//e.kind는 현재 이벤트 유형을 가져오고, e.data는 현재 이벤트 아래의 노드를 가져옵니다. node.s('2d.visible', true);//노드가 표시되도록 설정 node.setPosition(e. data.getPosition() .x, e.data.getPosition().y);//노드의 좌표를 현재 이벤트 아래의 노드 위치로 설정} else if(e.kind === 'doubleClickData') {//gv.fitData(e.data, false, 10) 노드를 두 번 클릭합니다. //이벤트 아래의 노드를 토폴로지 맵의 중심으로 조정합니다. 매개변수 1은 적응형 노드이고, 매개변수 2는 애니메이션 여부입니다. , 매개변수 3은 gv 및 테두리의 패딩입니다. } else if(e.kind === 'doubleClickBackground') {//빈 공간을 두 번 클릭합니다. node.s('2d.visible', false);// node 노드가 보이지 않게 됨 웹용 View HT 스타일 매뉴얼(http://www.hightopo.com/guide/guide/core/theme/ht-theme-guide.html#ref_style) }});
s(style)와 a(attr)는 다음과 같이 정의됩니다. s는 ht에서 미리 정의한 일부 스타일 속성이고, a는 사용자가 사용자 정의한 속성입니다. 이 문자열은 일반적으로 문자열을 호출하여 호출됩니다. 상수이거나 매우 유연한 함수일 수 있습니다.
마지막으로 작은 부분이 만들어집니다. 사이트를 선택하면 해당 사이트 위에 빨간색 호흡 아이콘이 표시되어 현재 선택된 사이트를 나타냅니다.
호흡 부분은 ht의 setAnimation 함수를 사용하여 완성됩니다. 이 함수를 사용하기 전에 먼저 데이터 컨테이너의 애니메이션 스위치를 켜고 애니메이션을 설정해야 합니다.
dm.enableAnimation();//데이터 컨테이너의 애니메이션 스위치 기능을 켜십시오. createRedLight() { var node = new ht.Node(); node.setImage('images/RedLight.json');//이미지 설정 노드 .setSize(1, 1);//노드 크기 설정 node.setLayer('firstTop');//gv의 최상위 레이어에 표시될 노드 설정 node.s('2d.visible', false);//The 노드는 보이지 않습니다 node.s( 'select.width', 0);//노드가 선택될 때의 테두리는 0이고 보이지 않습니다 node.s('2d.selectable', false);//이 속성을 설정하면 노드를 선택할 수 없습니다. node.setAnimation({//애니메이션 설정에 대한 자세한 내용은 HT for Web Animation 매뉴얼(http://www.hightopo.com/guide/guide)을 참조하세요. /plugin/animation/ht- animation-guide.html) ExpandWidth: { property: width,//이 속성을 설정하고 accessType이 설정되지 않은 경우 기본값은 setWidth/getWidth를 통해 속성을 설정하고 가져오는 것입니다. 아래 높이를 사용합니다. 모두 이전에 설정된 크기에 따라 획득됩니다: 0.5, //애니메이션 시작 부분의 속성 값: 1,//애니메이션 끝 부분의 속성 값 다음: 붕괴Width//문자열 유형, 이후에 실행할 항목 지정 현재 애니메이션이 완료되었습니다. 다음 애니메이션은 여러 애니메이션을 병합할 수 있습니다.}, 붕괴Width: { property: width, from: 1, to: 0.5, next: ExpandWidth }, ExpandHeight: { property: height, from: 0.5, to: 1, next: 붕괴Height }, 붕괴Height: { property: height, from: 1, to: 0.5, next: ExpandHeight }, start: [expandWidth, ExpandHeight]//Array, 시작될 하나 이상의 애니메이션을 지정하는 데 사용됨} ) ; dm.add(노드); 반환 노드;}
모든 코드가 끝났습니다!
요약이 데모를 완료하는 데 이틀이 걸렸고 항상 그렇게 하고 싶지 않다는 느낌이 들었습니다. 하지만 때로는 머리를 감을 수 없었고 시간이 많이 걸렸지만 전반적으로 많은 것을 얻었습니다. 그냥 getPoints().push를 사용하여 폴리곤에 포인트를 추가하면 된다고 생각했는데, 마스터에게 도움을 요청한 후 이 방법은 우회할 뿐만 아니라 포인트를 얻기 전에도 다양한 문제를 일으킨다는 것을 알았습니다. , 다각형에 이미 점이 있어야 합니다. 가능하지만 많은 경우 초기화된 점을 설정하기가 쉽지 않고 코드도 매우 번거로울 것입니다. addPoint 메소드를 통해 다각형 변수에 점을 직접 추가하고 점은 기본적으로 직선으로 연결됩니다. 세그먼트를 따로 설정할 필요가 없다는 게 정말 멋진 기능이네요.
또한 ht의 기본 확대/축소 크기는 20이고 내 데모의 간격이 매우 작기 때문에 최대로 확대하면 지하철 노선도 표시도 매우 작아서 htconfig에서 ht의 기본 ZoomMax 속성을 변경했습니다. , 변경 htconfig에 설정된 값은 나중에 변경할 수 없으므로 이 값은 모든 ht 호출 이전에 와야 합니다.
위 내용은 에디터가 소개하는 HTML5 Canvas 기반의 인터랙티브 지하철 노선도입니다. 궁금한 사항이 있으시면 메시지를 남겨주시면 에디터가 시간 맞춰 답변해 드리겠습니다. 또한 VeVb 무술 웹사이트를 지원해 주신 모든 분들께 감사드립니다!