// DataDashboard ~~ MIT License // Widget controller // Imports import { Chart, ChartConfiguration, ChartDataset, ChartTypeRegistry, Point, TooltipItem } from 'chart.js'; import { fetchJson } from 'fetch-json'; import { DataTable } from 'simple-datatables'; // Modules import { webAppLookup } from '../../modules/lookup.js'; import { webAppUtil } from '../../modules/util.js'; class DT extends DataTable {} declare namespace simpleDatatables { class DataTable extends DT {} } //eslint-disable-line @typescript-eslint/no-namespace // { // root: { // stations: { // station: [ // { // name: '12th St. Oakland City Center', // abbr: '12TH', // gtfs_latitude: '37.803768', // gtfs_longitude: '-122.271450', // address: '1245 Broadway', // city: 'Oakland', // county: 'alameda', // state: 'CA', // zipcode: '94612' // }, // ... // Types type Station = { name: string, abbr: string, gtfs_latitude: string, gtfs_longitude: string, city: string, county: string, }; type RawData = { root: { stations: { station: Station[] } }, }; type DataPoint = { x: number, y: number, label: string, }; type Point$ = Point & { label: string }; //patch library type const webAppWidgetTransBartStations = { displayDataChart(widgetElem: Element, stations: Station[]): void { const dataset: ChartDataset = { label: 'Geolocation', backgroundColor: webAppLookup.chartColor.green!.value, data: stations.map((item: Station): DataPoint => ({ x: parseFloat(item.gtfs_longitude), y: parseFloat(item.gtfs_latitude), label: item.abbr + ' (' + item.name + ')', })), }; const latLong = (item: TooltipItem): string => { // Returns a string formatted like: "37.77°N 122.42°W" (San Francisco) const lat = item.parsed.y ?? 0; const long = item.parsed.x ?? 0; const fixed = (degrees: number) => Math.abs(degrees).toFixed(2); return `${fixed(lat)}°${lat > 0 ? 'N' : 'S'} ${fixed(long)}°${long > 0 ? 'E' : 'W'}`; }; const makeTooltip = (item: TooltipItem): string => `${(item.dataset.data[item.dataIndex]).label} ${latLong(item)}`; const chartInfo: ChartConfiguration = { type: 'scatter', data: { datasets: [dataset], }, options: { maintainAspectRatio: false, plugins: { title: { display: true, text: ['BART Stations', 'San Francisco Bay Area'] }, tooltip: { callbacks: { label: makeTooltip } }, }, }, }; const canvas = widgetElem.querySelector('canvas')!; dna.dom.state(widgetElem).chart = new Chart(canvas, chartInfo); }, displayDataTable(widgetElem: Element, stations: Station[]): void { const tableElem = widgetElem.querySelector('figure table'); const dataTable = new simpleDatatables.DataTable(tableElem); const headers = [ 'Name', 'Code', 'Latitude', 'Longitude', 'City', 'County', ]; const rows = stations.map(station => [ station.name, station.abbr, station.gtfs_latitude, station.gtfs_longitude, station.city, station.county, ]); dataTable.insert({ headings: headers, data: rows }); dna.dom.state(widgetElem).table = dataTable; }, show(widgetElem: Element): void { const handleData = (data: RawData) => { webAppUtil.spinnerStop(widgetElem); const stations = data.root.stations.station; webAppWidgetTransBartStations.displayDataChart(widgetElem, stations); webAppWidgetTransBartStations.displayDataTable(widgetElem, stations); }; const url = 'https://api.bart.gov/api/stn.aspx'; const params = { cmd: 'stns', key: 'MW9S-E7SL-26DU-VV8V', json: 'y' }; webAppUtil.spinnerStart(widgetElem); fetchJson.get(url, params).then(handleData); }, }; export { webAppWidgetTransBartStations };