D3.JS Metro Rail Transportation Project

The last chapter says how to make a line diagram, of course, the last chapter is a handwritten JSON data, of course, the handwritten JSON data has a lot of benefits, for example, the customer’s various BT needs, but most cases We all use the ready-made JSON files from the Metro company, and if we don’t say, let’s take a look at Baidu official line diagram.

d3.js 地铁轨道交通项目实战 That is, today we will complete most of its needs, as well as the needs of Metro Dad.

The demand is as follows:

1. Display the subway line according to different colors, display the corresponding site. 2. Users can click on gesture scaling and translation (this item is Android development).

3. Users to click on the line in the line MENU, and the corresponding line flat value screen center is high.


4. According to the background data, rendering the problem road section.

5. Click on the problem road site to display the problem details.

The general demand is these, look at the code


1. Define some constants and variables


const dataset = SubwayData; // Line diagram Data Source Let Subway = New Subway (Dataset); // Line Diagram of the class file let basescale = 2; // Basic zoom ratio LET DEVICESCALE = 1400/2640; // Appliances and Canvas Width Ratio LET WIDTH = 2640; // Canvas width let height = 1760; // Canvas high let transx = 1320 + 260; // Map X-axis translation (slide the origin X-axis flush) Let Transy = 580; // Map x-axis Translation (will Canvas origin Y-axis flush) let scaleextent = [0.8, 4]; // the zoom magnification limiting let currentScale = 2; // current scale value let currentX = 0; // this canvas X axis shift amount let currentY = 0; // current canvas Y-axis shift amount let selected = false; // whether the line is selected (selected in the upper right corner of the menu line) let scaleStep = 0.5; // click zoom button zoom step default 0.5 times let tooltip = d3.select ( ‘# tooltip’); // prompt box let bugArray = []; // problem link array let svg = d3.select ( ‘# sw’) append ( ‘svg’);.. // canvas let group = svg.append ( ‘transform’ ( ‘g’) attr, ` translate ($ {transX}, $ {transY}) scale (1) `); // define groups and translational let whole = group.append ( ‘g’) attr ( ‘class’, ‘whole-line’) /. / virtual circuit attr ( ‘class’, ‘path’) (top right corner response is used when the center of the field lines may be positioned, not the only method) let path = group.append ( ‘g’); // define lines let point. = group.append ( ‘g’) attr ( ‘class’, ‘point’);.. // define the site const zoom = d3.zoom () scaleExtent (scaleExtent) .on ( “zoom”, zoomed); // defined zoom events


this is the number of constants and variables we want to use. Note transX than half the width, because Beijing subway line west line network is more dense.
2 read official JSON
   Use D3.js data is essential, but the official data is not easy to understand, let's first interpret the official JSON data. 

Each line object has an L_Xmlattr property and a P property, and l_xmlattr is the properties of the whole line. P is an array of site, let’s see The attribute we need in the site. Is the EX is a transfer station, LB is a station name, SID is the id, rx, ry is a text offset, and ST is a site (because some points are not site but to render the beser curve), x, y is the site coordinate.

3. Constructing your own method

The official gave us the data, but it is not that we can use directly, so we need to construct your method

d3.js 地铁轨道交通项目实战

Class Subway {Constructor (DATA) {this.data = Data; this.buglineArray = [];} getinvent () {} // Get virtual line data getPatharray ()} // Get Path Data getPointArray () {} // Get Site Array GetCurrentPatharray () {} // Gets the path array of selected lines getCurrentPointArray () {} // Get Site Arch of the selected line GetLineNameArray () {} // Get line Name Array GetBugLineArray () {} // Get Problem Section An Array}

The following is our method content, the operation inside is not very elegant (everyone will look)


Getinvent () {let linearray = []; this.data.Foreach (D => {Let {LOOP, LC, LBX, Lby, LB, LID} = D.L_Xmlattr; Let Allpoints = DPSLICE (0); Loop && Allpoints.push (AllPoints [0]); let path = this . formatpath (AllPoints, 0, Allpoints.Length – 1); lineArray.push ({LID: LID, PATH: PATH,})}) Return lineArray;} getPatharray () {let patharray = []; this.data.ForeAach (D => {Let {LOOP, LC, LBX, Lby, LB, LID} = D.L_Xmlattr; Let Allpoints = DPSLICE (0); Loop && Allpoints.push (AllPoints [0]) Let allstations = []; Allpoints.Foreach (item, index) => item.p_xmlattr.st && allstations.push ({… item.p_xmlattr, index})) Let arr = []; for (let i = 0; i

{Let {LID, LC, LB} = D.L_Xmlattr; let allpoints = dp; let allstations = []; allpoints.foreach (item => {if (item.p_xmlattr.st&&! item.p_xmlattr.ex) {Allstations.push ({… item.p_xmlattr, lid, pn: lb, lc: lc.replace (/ 0x /, ‘#’)}} else if (item.p_xmlattr.ex) {ix (TemppointsArray.indexof (item.p_xmlattr.sid) == -1) {AllStations.push ({… item.p_xmlattr, lid, pn: lb, lc: lc.replace (/ 0x /, ‘#’)}) TemppointsArray.push (item.p_xmlattr.sid);}}}); PointArray.push (allstations);}) Return PointArray;} getCurrentPatharray (name) {let D = this.data.filter (D => D.L_Xmlattr.lid == Name) [0]; Let {LOOP, LC, LBX, Lby, LB, LID = D.L_Xmlattr; Let AllPoints = DPSLICE (0); Loop && AllPoints.push (AllPoints [0]) Let allstations = [] Allpoints.Foreach ((item, index) => item.p_xmlattr.st && allstations.push ({… item.p_xmlattr, index})) Let arr = []; for (let i = 0; i

D.L_Xmlattr.LID == Name) [0]; Let {LID, LC, LB}= D.L_Xmlattr; let allPoints = dp; let allstations = []; allpoints.foreick (item => {if (item.p_xmlattr.st &&! item.p_xmlattr.ex) {allstations.push ({… item. P_Xmlattr, LID, PN: LB, LC: lc.replace (/ 0x /, ‘#’)})} else if (item.p_xmlattr.ex) {allstations.push ({… item.p_xmlattr, limited, pn : lb, lc: lc.replace (/ 0x /, ‘#’)}}}}); Return AllStations;} getLineNameArray () {let nameArray = this.data.map (D => {return {lb: d. L_xmlattr.lb, LID: D.L_Xmlattr.lid, LC: D.L_Xmlattr.lc.replace (/ 0x /, ‘#’)}} Return NameArray;} getBugLineArray (arr) {if (! arr ||! arr .length) Return []; this.buglineArray = []; arr.foreach (item => {let {Start, end, cause, duration, limited, lb} = item; let line = []; let point point = [] Let tempobj = this.data.filter (d => d.l_xmlattr.lid == lid) [0]; let loop = tempObj.l_xmlattr.loop; let lc = tempObj.l_xmlattr.lc; let allPoints = tempObj.p; let allStations = []; allPoints.forEach (item => { if (item.p_xmlattr.st) {allStations.push (item.p_xmlattr.sid)}}); loop && allStations.push (allStations [0]); for (let i = allStations.indexOf (start); i

   
in this way we do not understand, know what passed, what can be entered, this is our way to class.


4.d3 canvas rendering and add method

 here is js core code, since class files are finished, the operation here on a lot of convenience the main method is the following few people,    <=allStations.lastIndexOf(end); i++) {
   points.push(allStations[i])
  }
  for(let i=allStations.indexOf(start); i<allStations.lastIndexOf(end); i++) {
   lines.push(`${allStations[i]}_${allStations[i+1]}`)
  }
  this.bugLineArray.push({cause,duration,lid,lb,lines,points,lc: lc.replace(/0x/, '#'),start: points[0],end:points[points.length - 1]});
 })
 return this.bugLineArray; 
renderInventLine (); // rendering virtual new way renderAllStation (); // render all of the line name (upper right corner ) renderBugLine (); // rendering problems road renderAllLine (); // render all lines renderAllPoint (); // render all points renderCurrentLine () // render the currently selected line renderCurrentPoint () // render the currently selected sites zoomed ( ) // method getCenter executed when scaling () // get virtualMethod for clicking on the center point of the line [12]


The following is the corresponding method body

svg.call (zoom); svg.call (Zoom.Transform, D3.ZoomIdentity.translate (1 – Basescale) * Transx, (1 – Basescale) * Transy). scale (baseScale)); let pathArray = subway.getPathArray (); let pointArray = subway.getPointArray (); renderInventLine (); renderAllStation (); renderBugLine (); function renderInventLine () {let arr = subway.getInvent (); Whole.selectall (‘Path’) .data (arr) .Enter () .append (‘Path’) .attr (‘D’, D => D.Path) .attr (‘Class’, D => D. LID) .attr (‘stroke’, ‘none’) .attr (‘Fill’, ‘None’)} Function RenderalLine () {for (Let i = 0; i

d.path) .attr (‘LID ‘, D => D.LID .attr (‘ id ‘, d => d.id) .attr (‘ Class’) .attr (‘stroke’, d => d.color).Attr (‘stroke-width’, 7) .attr (‘stroud-linecap’, ’round’) .attr (‘Fill’, ‘None’) path.Append (‘text’) .attr (‘x’, Patharray [i] .lbx) .attr (‘y’, Patharray [i] .lby) .attr (‘DY’, ‘1em’) .attr (‘DX’, ‘-0.3em’) .attr (‘Fill’ Patharray [i] .lc) .attr (‘LID’, Patharray [i] .lid) .attr (‘Class’, ‘Line-Text Origin’) .attr (‘Font-Size’, 14) .attr ( ‘font-weight’, ‘bold’) .Text (Patharray [i] .lb)}} function renderallpoint ()} function renderalallpoint ()} (let i = 0; i
d.path) .attr (‘LID’, D => D.LID) .attr (‘id’, d => d.id) .attr (‘stroke’, d => d.color) .attr (‘stroke-width’, 7) .attr (‘stroke -LineCap ‘,’ Round ‘) .attr (‘ Fill ‘,’ None ‘) path.append (‘ text ‘) .attr (‘ Class’, ‘Temp’) .attr (‘x’, arr.lbx). Attr (‘y’, arr.lby) .attr (‘DY’, ‘1em’) .attr (‘DX’, ‘-0.3em’) .attr (‘Fill’, Arr.lc) .attr (‘LID ‘, Arr.liD) .attr (‘font-size’, 14) .attr (‘font-weight’, ‘bold’) .Text (arr.lb)} Function RenderCurrentPoint (Name) {let arr = subway.getCurrentPointArray (Name); For (Let i = 0; i

{console.log (d) d.Lines.Foreach (DD => {D3.Selectall (`Path # $ {dd}`) .attr (‘stroke’, ‘# Eee ‘);}) D.Points.Foreach (DD => {D3.Selectall (`Circle # $ {DD}`) .attr (‘ stroke ‘,’ #ddd ‘) D3.Selectall (`Text # $ { DD} `) .attr (‘Fill’, ‘#aaa’)}}) D3.Selectall (‘. Points’). on (‘Click’, Function () {let id = D3.Select (this). Attr (‘ID’); Let Bool = JudgebugPoint (BUGLINEARRAY, ID); if (bool) {let x, y; if (D3.Select (this) .attr (‘href’)) {x = parsefloat (D3. SELECT (this) .attr (‘x’)) + 8; y = parsefloat (D3.Select (this) .attr (‘y’)) + 8;} else {x = D3.select (this) .attr ( ‘cx’); y = D3.SELECT (THIS) .attr (‘cy’);} let toolx = (x * currentscale + transx – (1 – currentscale) * Transx – currentx) * DEVICESCALE; Let tool = (Y * Currentscale + Transy – (1 – Currentscale) * Transy – currenty) * Devicescale; let tooh = document.getElementByid (‘tooltip’). OffsetHeight; Let Toolw = 110; if (Tooly
{Return D.Points.indexof (ID)> -1} ); if (bugline.Length) {RemoveTooltip () Tooltip.select (‘# Tool-head’). HTML (` $ {id}
  × `); bugline.ForeAach (D => {let item = Tooltip.select ('# Tool-body'). Append ('div "). Attr (' Class'); item.html (` 


$ {d.duration}
  Road cause  < pointArray.length; i++) {
  for (let j = 0; j  $ {d.cause}    Sealing section 
$ {D.Start} - $ {d.end}
`)}) D3.Select ('# Tooltip'). Style 'Display', 'block'); return true;} else {return false;}} function removetooltip () {d3.selectall ('. Tool-item'). Remove (); D3.SELECT ('# Tooltip') .style ('Display', 'None');} function zoomed () {transovetooltip (); let {x, y, k} = D3.Event.Transform; currentscale = k; currentx = x; currenty = y; group .Transition (). Duration (50) .ease (D3.Easelinear) .attr ("Transform", () => `Translate ($ {x + transx * k}, $ {y + transy * k}) scale $ {k})} Function getCenter (STR) {if (! str) return null; let x, y; let temparr = []; let tempx = []; let tempy = []; str.split (' ') .foreach (D => {IF (! isnan (d)) {Temparr.push (d)} Temparr.Foreach ((D, I) => {IF (i% 2 == 0){TEMPX.PUSH (PARSEFLOAT (D))} else {tempy.push (Parsefloat (D))}} = (D3.min (Tempx) + D3.max (TEMPX)) / 2; Y = (D3. MIN (TEMPY) + D3.MAX (TEMPY)) / 2; Return [x, y]} Function RenderaLLStation () {let nameArray = Subway.getLineNameArray (); let get = math.ceil (nameArray.Length / 5); Let Box = D3.Select ('# menu'). Append ('div ") .attr (' Class', 'Name-Box') for (Let i = 0; i d.lid) .attr ( 'Class', 'Name-item') Item.each (Function (D) {D3.Select (this) .append ('span'). Attr ('Class', 'p_mark'). style ('Background', D.LC); D3.Select (this) .Append ('span'). Attr ('class',' p_name '). Text (d.lb); d3.select (this) .on (' click ", D => {SELECTED = true; d3.selectall ('. Origin'). style ('Opacity', 0.1); D3.Selectall ('. Temp'). Remove (); rendercurrentline (D.LID); RendeRcurrentPoint (D.LID); Let Arr = getcenter (D3.Select (`Path. $ {D.LID}`) .attr ('d')); svg.call (zoom.Transform, D3.ZoomIdentity.translate (Width / 2 - Transx) - Arr [0] - (Arr [0] + Transx) * (Currentscale - 1), (HEIGHT / 2 - Transy) - Arr [1] - (Arr [1] + Transy) * (Currentscale - 1))). Scale (curRentscale);})}}}} function scale (type) {if (Type && currentscale + scalestep
= scaleextent [0]) {svg.call (Zoom.Transform, d3.zoomIdentity.translate ((1 - (currentScale - scaleStep)) * transX - ((1 - currentScale) * transX - currentX) * (currentScale - scaleStep) / currentScale, (1 - (currentScale - scaleStep)) * transY - ((1 - currentscale) * (Currentscale - ScaleStep) / currentscale) .scale (currentscale - scalestep);}}
above is most Code, want to seeAll can be viewed by Demo.
Want to view friends from Demo or code, please move to the original http://www.bettersmile.cn
Summary
It is a practical battle for the D3.JS subway rail transit project introduced to you. I hope that everyone will help everyone. If you have any questions, please leave a message, the small package will reply to everyone. Thank you very much for your support of Tumi Cloud Website!
If you think this article helps you, welcome to reprint, please indicate the source, thank you!
© Copyright Notice
THE END
Just support it if you like
like0
share
comment Grab the couch

Please log in to comment