gtfs-to-chart 2.0.3 → 2.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.eslintrc.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "env": {
3
+ "node": true,
4
+ "es2021": true
5
+ },
6
+ "extends": ["xo", "prettier"],
7
+ "parserOptions": {
8
+ "ecmaVersion": 12,
9
+ "sourceType": "module"
10
+ },
11
+ "rules": {
12
+ "arrow-parens": ["error", "always"],
13
+ "camelcase": [
14
+ "error",
15
+ {
16
+ "properties": "never"
17
+ }
18
+ ],
19
+ "indent": "off",
20
+ "object-curly-spacing": ["error", "always"],
21
+ "no-unused-vars": [
22
+ "error",
23
+ {
24
+ "varsIgnorePattern": "^[A-Z]"
25
+ }
26
+ ]
27
+ }
28
+ }
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env sh
2
+ . "$(dirname -- "$0")/_/husky.sh"
3
+
4
+ npx pretty-quick --staged && npm run lint
package/CHANGELOG.md CHANGED
@@ -4,13 +4,31 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
- ## [Unreleased]
7
+ ## [2.0.5] - 2022-12-31
8
+ ### Updated
9
+ - Update to node-gtfs v4
10
+ - Dependency updates
11
+ - Add Husky
12
+
13
+ ## [2.0.4] - 2022-11-09
14
+ ### Updated
15
+ - Dependency updates
16
+
17
+ ### Fixed
18
+ - Fixed charts path in generated charts HTML
19
+
20
+ ## [2.0.3] - 2022-06-25
8
21
  ### Updated
9
22
  - Dependency updates
10
23
 
11
24
  ### Fixed
12
25
  - Fixed charts path in generated index.html
13
26
 
27
+ ## [2.0.2] - 2022-06-25
28
+ ### Updated
29
+ - Dependency updates
30
+ - Readme udpates
31
+
14
32
  ## [2.0.1] - 2021-08-17
15
33
  ### Updated
16
34
  - Dependency updates
@@ -20,4 +38,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
20
38
 
21
39
  ## [2.0.0] - 2021-05-14
22
40
  ### Breaking Changes
23
- - Converted to ES6 Module
41
+ - Converted to ES6 Module
package/README.md CHANGED
@@ -9,7 +9,6 @@
9
9
  <br /><br />
10
10
  <a href="https://www.npmjs.com/package/gtfs-to-chart" rel="nofollow"><img src="https://img.shields.io/npm/v/gtfs-to-chart.svg?style=flat" style="max-width: 100%;"></a>
11
11
  <a href="https://www.npmjs.com/package/gtfs-to-chart" rel="nofollow"><img src="https://img.shields.io/npm/dm/gtfs-to-chart.svg?style=flat" style="max-width: 100%;"></a>
12
- <a href="https://github.com/BlinkTagInc/gtfs-to-chart/actions?query=workflow%3A%22Node+CI%22"><img src="https://img.shields.io/github/workflow/status/BlinkTagInc/gtfs-to-chart/Node%20CI.svg" alt="CircleCI" style="max-width: 100%;"></a>
13
12
  <img src="https://img.shields.io/badge/License-MIT-yellow.svg">
14
13
  <br /><br />
15
14
  Generate stringline charts from GTFS transit data.
@@ -100,7 +99,7 @@ All files starting with `config*.json` are .gitignored - so you can create multi
100
99
  | ------ | ---- | ----------- |
101
100
  | [`agencies`](#agencies) | array | An array of GTFS files to be imported. |
102
101
  | [`beautify`](#beautify) | boolean | Whether or not to beautify the HTML output. |
103
- | [`chartDate`](#templatepath) | string | The date to use for generating the stringline chart. |
102
+ | [`chartDate`](#chartdate) | string | The date to use for generating the stringline chart. |
104
103
  | [`templatePath`](#templatepath) | string | Path to custom pug template for rendering chart html. |
105
104
 
106
105
  ### agencies
package/app/routes.js CHANGED
@@ -24,7 +24,7 @@ openDb(config);
24
24
  */
25
25
  router.get('/', async (request, response, next) => {
26
26
  try {
27
- const routes = await getRoutes();
27
+ const routes = getRoutes();
28
28
  const html = await generateOverviewHTML(config, routes);
29
29
  response.send(html);
30
30
  } catch (error) {
@@ -14,7 +14,7 @@ import { formatRouteName } from './formatters.js';
14
14
  /*
15
15
  * Generate HTML charts from GTFS
16
16
  */
17
- const gtfsToChart = async initialConfig => {
17
+ const gtfsToChart = async (initialConfig) => {
18
18
  const config = setDefaultConfig(initialConfig);
19
19
  config.log = log(config);
20
20
  config.logWarning = logWarning(config);
@@ -25,7 +25,7 @@ const gtfsToChart = async initialConfig => {
25
25
  throw new Error('No agencies defined in `config.json`');
26
26
  }
27
27
 
28
- return Promise.all(config.agencies.map(async agency => {
28
+ return Promise.all(config.agencies.map(async (agency) => {
29
29
  const timer = new Timer();
30
30
  const agencyKey = agency.agency_key;
31
31
  const exportPath = path.join(process.cwd(), 'charts', sanitize(agencyKey));
@@ -45,12 +45,12 @@ const gtfsToChart = async initialConfig => {
45
45
 
46
46
  await prepDirectory(exportPath);
47
47
 
48
- const routes = await getRoutes();
48
+ const routes = getRoutes();
49
49
  const bar = progressBar(`${agencyKey}: Generating charts [:bar] :current/:total`, { total: routes.length }, config);
50
50
 
51
51
  // Make directory if it doesn't exist
52
52
  await mkdir(exportPath, { recursive: true });
53
- config.assetPath = '';
53
+ config.assetPath = '../';
54
54
 
55
55
  /* eslint-disable no-await-in-loop */
56
56
  for (const route of routes) {
package/lib/log-utils.js CHANGED
@@ -36,7 +36,7 @@ export function logWarning(config) {
36
36
  return config.logFunction;
37
37
  }
38
38
 
39
- return text => {
39
+ return (text) => {
40
40
  process.stdout.write(`\n${formatWarning(text)}\n`);
41
41
  };
42
42
  }
@@ -49,7 +49,7 @@ export function logError(config) {
49
49
  return config.logFunction;
50
50
  }
51
51
 
52
- return text => {
52
+ return (text) => {
53
53
  process.stdout.write(`\n${formatError(text)}\n`);
54
54
  };
55
55
  }
@@ -79,20 +79,18 @@ export function progressBar(formatString, barOptions, config) {
79
79
 
80
80
  if (config.logFunction) {
81
81
  let barProgress = 0;
82
- const renderProgressString = () => {
83
- return formatString
82
+ const renderProgressString = () => formatString
84
83
  .replace(':current', barProgress)
85
84
  .replace(':total', barOptions.total)
86
85
  .replace('[:bar] ', '');
87
- };
88
86
 
89
87
  config.log(renderProgressString());
90
88
 
91
89
  return {
92
- interrupt: text => {
90
+ interrupt(text) {
93
91
  config.logWarning(text);
94
92
  },
95
- tick: () => {
93
+ tick() {
96
94
  barProgress += 1;
97
95
  config.log(renderProgressString());
98
96
  }
@@ -103,10 +101,10 @@ export function progressBar(formatString, barOptions, config) {
103
101
  bar.render();
104
102
 
105
103
  return {
106
- interrupt: text => {
104
+ interrupt(text) {
107
105
  bar.interrupt(text);
108
106
  },
109
- tick: () => {
107
+ tick() {
110
108
  bar.tick();
111
109
  }
112
110
  };
package/lib/utils.js CHANGED
@@ -49,12 +49,12 @@ const reverseStationDistances = (stations, oppositeDirectionDistance) => {
49
49
  /*
50
50
  * Find longest trip
51
51
  */
52
- const findLongestTrip = trips => maxBy(trips, trip => size(trip.stoptimes));
52
+ const findLongestTrip = (trips) => maxBy(trips, (trip) => size(trip.stoptimes));
53
53
 
54
54
  /*
55
55
  * Determine if a stoptime is a timepoint.
56
56
  */
57
- const isTimepoint = stoptime => {
57
+ const isTimepoint = (stoptime) => {
58
58
  if (stoptime.timepoint === null) {
59
59
  return stoptime.arrival_time !== '' && stoptime.departure_time !== '';
60
60
  }
@@ -62,9 +62,9 @@ const isTimepoint = stoptime => {
62
62
  return stoptime.timepoint === 1;
63
63
  };
64
64
 
65
- const getStationsFromTrip = async trip => {
66
- const stops = await Promise.all(trip.stoptimes.map(async stoptime => {
67
- const stops = await getStops({
65
+ const getStationsFromTrip = (trip) => {
66
+ const stops = trip.stoptimes.map((stoptime) => {
67
+ const stops = getStops({
68
68
  stop_id: stoptime.stop_id
69
69
  });
70
70
 
@@ -73,12 +73,12 @@ const getStationsFromTrip = async trip => {
73
73
  }
74
74
 
75
75
  return stops[0];
76
- }));
76
+ });
77
77
 
78
78
  let previousStationCoordinates;
79
79
  return trip.stoptimes.map((stoptime, index) => {
80
80
  const stop = stops[index];
81
- const hasShapeDistance = every(trip.stoptimes, stoptime => stoptime.shape_dist_traveled !== null);
81
+ const hasShapeDistance = every(trip.stoptimes, (stoptime) => stoptime.shape_dist_traveled !== null);
82
82
 
83
83
  if (!hasShapeDistance) {
84
84
  if (index === 0) {
@@ -107,24 +107,20 @@ const getStationsFromTrip = async trip => {
107
107
  /*
108
108
  * Get all trips and stoptimes for a given route
109
109
  */
110
- const getDataforChart = async (config, routeId) => {
111
- const db = await openDb(config);
110
+ const getDataforChart = (config, routeId) => {
111
+ const db = openDb(config);
112
112
  const notes = [];
113
113
  const dayOfWeek = moment(config.chartDate, 'YYYYMMDD').format('dddd').toLowerCase();
114
- const calendars = await db.all(`SELECT DISTINCT service_id FROM calendar WHERE start_date <= ? AND end_date >= ? AND ${sqlString.escapeId(dayOfWeek)} = 1`, [
115
- config.chartDate,
116
- config.chartDate
117
- ]);
114
+ const calendars = db.prepare(`SELECT DISTINCT service_id FROM calendar WHERE start_date <= $date AND end_date >= $date AND ${sqlString.escapeId(dayOfWeek)} = 1`).all({ date: config.chartDate });
118
115
 
119
116
  if (calendars.length === 0) {
120
117
  throw new Error(`No calendars found for route ${routeId} on ${moment(config.chartDate, 'YYYYMMDD').format('MMM D, YYYY')}`);
121
118
  }
122
119
 
123
- const serviceIds = calendars.map(calendar => calendar.service_id);
124
- const trips = await db.all(`SELECT service_id, trip_id, trip_headsign, direction_id, shape_id FROM trips where route_id = ? AND service_id IN (${serviceIds.map(() => '?').join(', ')})`, [
120
+ const serviceIds = calendars.map((calendar) => calendar.service_id);
121
+ const trips = db.prepare(`SELECT service_id, trip_id, trip_headsign, direction_id, shape_id FROM trips where route_id = ? AND service_id IN (${serviceIds.map(() => '?').join(', ')})`).all(
125
122
  routeId,
126
- ...serviceIds
127
- ]);
123
+ ...serviceIds);
128
124
 
129
125
  if (trips.length === 0) {
130
126
  throw new Error(`No trips found for route ${routeId} on ${moment(config.chartDate, 'YYYYMMDD').format('MMM D, YYYY')}`);
@@ -136,8 +132,8 @@ const getDataforChart = async (config, routeId) => {
136
132
  throw new Error('Route has no shapes.');
137
133
  }
138
134
 
139
- await Promise.all(trips.map(async trip => {
140
- const stoptimes = await getStoptimes(
135
+ for (const trip of trips) {
136
+ const stoptimes = getStoptimes(
141
137
  {
142
138
  trip_id: trip.trip_id
143
139
  },
@@ -153,11 +149,11 @@ const getDataforChart = async (config, routeId) => {
153
149
  ]
154
150
  );
155
151
 
156
- trip.stoptimes = stoptimes.filter(stoptime => isTimepoint(stoptime));
157
- }));
152
+ trip.stoptimes = stoptimes.filter((stoptime) => isTimepoint(stoptime));
153
+ }
158
154
 
159
155
  const longestTrip = findLongestTrip(trips);
160
- let stations = await getStationsFromTrip(longestTrip);
156
+ let stations = getStationsFromTrip(longestTrip);
161
157
  const tripDistance = max(map(stations, 'distance'));
162
158
  const directionGroups = groupBy(trips, 'direction_id');
163
159
 
@@ -165,13 +161,14 @@ const getDataforChart = async (config, routeId) => {
165
161
  if (size(directionGroups) > 1) {
166
162
  const oppositeDirection = longestTrip.direction_id === 1 ? '0' : '1';
167
163
  const longestTripOppositeDirection = findLongestTrip(directionGroups[oppositeDirection]);
168
- const stationsOppositeDirection = await getStationsFromTrip(longestTripOppositeDirection);
164
+ const stationsOppositeDirection = getStationsFromTrip(longestTripOppositeDirection);
169
165
 
170
166
  reverseStationDistances(stationsOppositeDirection, tripDistance);
171
167
 
172
168
  stations = [...stations, ...stationsOppositeDirection];
173
169
  }
174
- const hasShapeDistance = every(longestTrip.stoptimes, stoptime => stoptime.shape_dist_traveled !== null);
170
+
171
+ const hasShapeDistance = every(longestTrip.stoptimes, (stoptime) => stoptime.shape_dist_traveled !== null);
175
172
  if (!hasShapeDistance) {
176
173
  notes.push('Distance between stops calculated assuming a straight line.');
177
174
  }
@@ -201,7 +198,7 @@ export function setDefaultConfig(initialConfig) {
201
198
  * Generate the HTML for the agency overview page.
202
199
  */
203
200
  export async function generateOverviewHTML(config, routes) {
204
- const agencies = await getAgencies();
201
+ const agencies = getAgencies();
205
202
  if (agencies.length === 0) {
206
203
  throw new Error('No agencies found');
207
204
  }
@@ -215,7 +212,7 @@ export async function generateOverviewHTML(config, routes) {
215
212
  const templateVars = {
216
213
  agency,
217
214
  config,
218
- routes: sortBy(routes, r => Number.parseInt(r.route_short_name, 10))
215
+ routes: sortBy(routes, (r) => Number.parseInt(r.route_short_name, 10))
219
216
  };
220
217
  return renderTemplate('overview_page', templateVars, config);
221
218
  }
@@ -224,7 +221,7 @@ export async function generateOverviewHTML(config, routes) {
224
221
  * Generate the HTML for a chart.
225
222
  */
226
223
  export async function generateChartHTML(config, routeId) {
227
- const routes = await getRoutes({
224
+ const routes = getRoutes({
228
225
  route_id: routeId
229
226
  });
230
227
 
@@ -232,7 +229,7 @@ export async function generateChartHTML(config, routeId) {
232
229
  throw new Error('Invalid route id provided');
233
230
  }
234
231
 
235
- const chartData = await getDataforChart(config, routeId);
232
+ const chartData = getDataforChart(config, routeId);
236
233
 
237
234
  return renderTemplate('chart_page', {
238
235
  route: routes[0],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gtfs-to-chart",
3
- "version": "2.0.3",
3
+ "version": "2.0.5",
4
4
  "private": false,
5
5
  "description": "Generate stringline charts of a transit routes from GTFS",
6
6
  "keywords": [
@@ -24,30 +24,15 @@
24
24
  },
25
25
  "scripts": {
26
26
  "start": "node ./app",
27
- "test": "xo"
28
- },
29
- "xo": {
30
- "esnext": true,
31
- "rules": {
32
- "camelcase": [
33
- "error",
34
- {
35
- "properties": "never"
36
- }
37
- ],
38
- "object-curly-spacing": [
39
- "error",
40
- "always"
41
- ]
42
- },
43
- "space": true
27
+ "lint": "eslint app/**/*.js lib/**/*.js public/**/*.js --fix",
28
+ "prepare": "husky install"
44
29
  },
45
30
  "dependencies": {
46
31
  "better-copy": "^1.0.4",
47
- "chalk": "^5.1.2",
32
+ "chalk": "^5.2.0",
48
33
  "connect-slashes": "^1.4.0",
49
34
  "express": "^4.18.2",
50
- "gtfs": "^3.6.0",
35
+ "gtfs": "^4.0.1",
51
36
  "js-beautify": "^1.14.7",
52
37
  "lodash-es": "^4.17.21",
53
38
  "moment": "^2.29.4",
@@ -59,13 +44,30 @@
59
44
  "sqlstring": "^2.3.3",
60
45
  "timer-machine": "^1.1.0",
61
46
  "untildify": "^4.0.0",
62
- "yargs": "^17.6.0"
47
+ "yargs": "^17.6.2"
63
48
  },
64
49
  "devDependencies": {
65
- "xo": "^0.52.4"
50
+ "eslint": "^8.31.0",
51
+ "eslint-config-prettier": "^8.5.0",
52
+ "eslint-config-xo": "^0.43.1",
53
+ "husky": "^7.0.0",
54
+ "prettier": "^2.8.1",
55
+ "pretty-quick": "^3.1.3"
66
56
  },
67
57
  "engines": {
68
58
  "node": ">= 14.x"
69
59
  },
70
- "false": {}
60
+ "release-it": {
61
+ "github": {
62
+ "release": true
63
+ },
64
+ "plugins": {
65
+ "@release-it/keep-a-changelog": {
66
+ "filename": "CHANGELOG.md"
67
+ }
68
+ }
69
+ },
70
+ "prettier": {
71
+ "singleQuote": true
72
+ }
71
73
  }
@@ -15,9 +15,8 @@ function padTimeRange(range) {
15
15
  }
16
16
 
17
17
  function geStopsFromStoptimes(stoptimes, stations) {
18
- /* eslint-disable-next-line unicorn/no-array-reduce */
19
18
  return stoptimes.reduce((memo, stoptime) => {
20
- const station = stations.find(station => station.stop_id === stoptime.stop_id);
19
+ const station = stations.find((station) => station.stop_id === stoptime.stop_id);
21
20
  if (stoptime.arrival_time === stoptime.departure_time) {
22
21
  memo.push({
23
22
  station,
@@ -58,7 +57,7 @@ function formatStopTime(stop) {
58
57
 
59
58
  function getPrimaryDirectionId(stations) {
60
59
  const directionGroups = _.groupBy(stations, 'direction_id');
61
- const largestDirectionGroup = _.maxBy(Object.values(directionGroups), group => group.length);
60
+ const largestDirectionGroup = _.maxBy(Object.values(directionGroups), (group) => group.length);
62
61
  return largestDirectionGroup[0].direction_id;
63
62
  }
64
63
 
@@ -68,85 +67,85 @@ function renderChart(data) {
68
67
  stations
69
68
  } = data;
70
69
 
71
- const formattedTrips = trips.map(trip => ({
70
+ const formattedTrips = trips.map((trip) => ({
72
71
  number: trip.trip_id,
73
72
  direction: trip.direction_id,
74
73
  trip_headsign: trip.trip_headsign,
75
74
  stops: geStopsFromStoptimes(trip.stoptimes, stations)
76
75
  }));
77
76
 
78
- const stops = formattedTrips.flatMap(trip => trip.stops.map(stop => ({
77
+ const stops = formattedTrips.flatMap((trip) => trip.stops.map((stop) => ({
79
78
  trip,
80
79
  stop
81
80
  })));
82
81
 
83
82
  const height = 2400;
84
83
  const width = 800;
85
- const topMargin = 20 + (_.max(_.map(stations, station => station.name.length)) * 4.6);
84
+ const topMargin = 20 + (_.max(_.map(stations, (station) => station.name.length)) * 4.6);
86
85
  const margin = ({ top: topMargin, right: 30, bottom: topMargin, left: 50 });
87
86
 
88
87
  const primaryDirectionId = getPrimaryDirectionId(stations);
89
88
 
90
89
  const line = d3.line()
91
- .x(d => x(d.station.distance))
92
- .y(d => y(d.time));
90
+ .x((d) => x(d.station.distance))
91
+ .y((d) => y(d.time));
93
92
 
94
93
  const x = d3.scaleLinear()
95
- .domain(d3.extent(stations, d => d.distance))
94
+ .domain(d3.extent(stations, (d) => d.distance))
96
95
  .range([margin.left + 10, width - margin.right]);
97
96
 
98
97
  const y = d3.scaleUtc()
99
- .domain(padTimeRange(d3.extent(stops, s => s.stop.time)))
98
+ .domain(padTimeRange(d3.extent(stops, (s) => s.stop.time)))
100
99
  .range([margin.top, height - margin.bottom]);
101
100
 
102
- const xAxis = g => g
101
+ const xAxis = (g) => g
103
102
  .style('font', '10px sans-serif')
104
103
  .selectAll('g')
105
104
  .data(stations)
106
105
  .join('g')
107
- .attr('transform', d => `translate(${x(d.distance)},0)`)
108
- .call(g => g.append('line')
106
+ .attr('transform', (d) => `translate(${x(d.distance)},0)`)
107
+ .call((g) => g.append('line')
109
108
  .attr('y1', margin.top - 6)
110
109
  .attr('y2', margin.top)
111
110
  .attr('stroke', 'currentColor'))
112
- .call(g => g.append('line')
111
+ .call((g) => g.append('line')
113
112
  .attr('y1', height - margin.bottom + 6)
114
113
  .attr('y2', height - margin.bottom)
115
114
  .attr('stroke', 'currentColor'))
116
- .call(g => g.append('line')
115
+ .call((g) => g.append('line')
117
116
  .attr('y1', margin.top)
118
117
  .attr('y2', height - margin.bottom)
119
118
  .attr('stroke-opacity', 0.2)
120
119
  .attr('stroke-dasharray', '1.5,2')
121
120
  .attr('stroke', 'currentColor'))
122
- .call(g => g.append('text')
121
+ .call((g) => g.append('text')
123
122
  .attr('transform', `translate(0,${margin.top}) rotate(-90)`)
124
123
  .attr('x', 12)
125
124
  .attr('dy', '0.35em')
126
- .text(d => d.name))
127
- .style('display', d => d.direction_id === primaryDirectionId ? 'block' : 'none')
128
- .call(g => g.append('text')
125
+ .text((d) => d.name))
126
+ .style('display', (d) => d.direction_id === primaryDirectionId ? 'block' : 'none')
127
+ .call((g) => g.append('text')
129
128
  .attr('text-anchor', 'end')
130
129
  .attr('transform', `translate(0,${height - margin.top}) rotate(-90)`)
131
130
  .attr('x', -12)
132
131
  .attr('dy', '0.35em')
133
- .text(d => d.name));
132
+ .text((d) => d.name));
134
133
 
135
- const yAxis = g => g
134
+ const yAxis = (g) => g
136
135
  .attr('transform', `translate(${margin.left},0)`)
137
136
  .call(d3.axisLeft(y)
138
137
  .ticks(d3.utcHour)
139
138
  .tickFormat(d3.utcFormat('%-I %p')))
140
- .call(g => g.select('.domain').remove())
141
- .call(g => g.selectAll('.tick line').clone().lower()
139
+ .call((g) => g.select('.domain').remove())
140
+ .call((g) => g.selectAll('.tick line').clone().lower()
142
141
  .attr('stroke-opacity', 0.2)
143
142
  .attr('x2', width));
144
143
 
145
144
  const voronoi = d3.Delaunay
146
- .from(stops, d => x(d.stop.station.distance), d => y(d.stop.time))
145
+ .from(stops, (d) => x(d.stop.station.distance), (d) => y(d.stop.time))
147
146
  .voronoi([0, 0, width, height]);
148
147
 
149
- const tooltip = g => {
148
+ const tooltip = (g) => {
150
149
  const tooltip = g.append('g')
151
150
  .style('font', '10px sans-serif');
152
151
 
@@ -176,7 +175,7 @@ function renderChart(data) {
176
175
  .join('path')
177
176
  .attr('d', (d, i) => voronoi.renderCell(i))
178
177
  .on('mouseout', () => tooltip.style('display', 'none'))
179
- .on('mouseover', d => {
178
+ .on('mouseover', (d) => {
180
179
  tooltip.style('display', null);
181
180
  line1.text(`Trip ${d.trip.number} to ${d.trip.trip_headsign}`);
182
181
  line2.text(d.stop.station.name);
@@ -216,16 +215,16 @@ function renderChart(data) {
216
215
 
217
216
  vehicle.append('path')
218
217
  .attr('fill', 'none')
219
- .attr('stroke', d => 'rgb(34, 34, 34)')
220
- .attr('d', d => line(d.stops));
218
+ .attr('stroke', (d) => 'rgb(34, 34, 34)')
219
+ .attr('d', (d) => line(d.stops));
221
220
 
222
221
  vehicle.append('g')
223
222
  .attr('stroke', 'white')
224
- .attr('fill', d => 'rgb(34, 34, 34)')
223
+ .attr('fill', (d) => 'rgb(34, 34, 34)')
225
224
  .selectAll('circle')
226
- .data(d => d.stops)
225
+ .data((d) => d.stops)
227
226
  .join('circle')
228
- .attr('transform', d => `translate(${x(d.station.distance)},${y(d.time)})`)
227
+ .attr('transform', (d) => `translate(${x(d.station.distance)},${y(d.time)})`)
229
228
  .attr('r', 2.5);
230
229
 
231
230
  svg.append('g')