Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
0da2c8e
Initial commit, re-target npm deploy and change tagline
tomstephen Dec 10, 2025
bcf3f60
Stop the deploy command trying (and failing) to set relative paths. D…
tomstephen Dec 10, 2025
4111886
misc splash page reformatting
tomstephen Dec 10, 2025
64aeb01
add aeq plugin, copied from xml viewer
tomstephen Dec 10, 2025
3bf93e2
Add to plugin repo
tomstephen Dec 10, 2025
92ac3d9
Flesh out reader.vue, add file system to extend http fs
tomstephen Dec 10, 2025
bfcfeb9
Clean up sqlite calls
tomstephen Dec 10, 2025
002d84c
update templates, config access, add yaml parsing, etc
tomstephen Dec 10, 2025
60dfa8f
Successfully reading tables from spatialite database
tomstephen Dec 10, 2025
ab746f9
remove comment
tomstephen Dec 10, 2025
5630df1
Complete architecture for dashboards etc
tomstephen Dec 10, 2025
fbe8332
refine dashboard functionality
tomstephen Dec 11, 2025
3ff2fd3
Remote hosted demo
tomstephen Dec 11, 2025
fc324e9
hit s3 bucket files, not the aws console
tomstephen Dec 11, 2025
8e9823f
Extend file system to support S3
tomstephen Dec 11, 2025
dbf1a86
Drop custom map component, use the existing one
tomstephen Dec 11, 2025
cddbb9e
.
tomstephen Dec 11, 2025
2f3f9cc
Trim comments
tomstephen Dec 11, 2025
d9ab411
Refactor
tomstephen Dec 11, 2025
61ea651
Add style by param
tomstephen Dec 11, 2025
165746b
Map centering and zoom
tomstephen Dec 11, 2025
ad6bb26
Adds ability to join another (results) database
tomstephen Dec 11, 2025
0b5490c
many small fixes
tomstephen Dec 11, 2025
56caa30
Revert irrelevant changes
tomstephen Dec 12, 2025
10b294a
Dont track changes to package-lock.json, bloating PR
tomstephen Dec 12, 2025
ca717dc
Did that last one wrong
tomstephen Dec 12, 2025
3ac4c54
Revert changes to scripts in package.json
tomstephen Dec 12, 2025
c499cad
drop erroneous notes
tomstephen Dec 12, 2025
935ac4c
Refactor of styling
tomstephen Dec 12, 2025
37cac33
stop tracking changes on package-lock.json
tomstephen Dec 12, 2025
dd767fe
.
tomstephen Dec 12, 2025
acfe7dd
Scaling by meters/pixels options
tomstephen Dec 12, 2025
ef9e36a
Main .vue refactor
tomstephen Dec 12, 2025
ab5b885
tweaks
tomstephen Dec 12, 2025
37c5383
Add dataRange to colours
tomstephen Dec 15, 2025
7ea39c7
Add ability to filter sql query from yaml
tomstephen Dec 15, 2025
b632dc3
Fix map resize bug
tomstephen Dec 15, 2025
16bbdd8
Manually defined legends
tomstephen Dec 16, 2025
b6896dc
.
tomstephen Dec 16, 2025
ead28f1
Fix S3 support for panels opening webworkers
tomstephen Dec 17, 2025
5031d56
revert changes to tile.vue
tomstephen Dec 17, 2025
5994627
Remove localhost from datasources on splash
tomstephen Dec 17, 2025
97e5c7a
add manual linewidths to styling
tomstephen Dec 17, 2025
4472d1f
Fix basemap and uncolour tiles
tomstephen Dec 17, 2025
8eb53a0
style tweaking in tile panel, plotly now supports fixed axis
tomstephen Dec 18, 2025
5e3ccbe
Meter or pixels for radius units
tomstephen Dec 18, 2025
23f42c3
Removed dark-matter, use internal options
tomstephen Dec 18, 2025
04d1677
Linting
tomstephen Dec 18, 2025
808e3cb
Drop dark matter
tomstephen Dec 18, 2025
0d843d7
rounding out styling, more careful loading and memory management, doc…
tomstephen Dec 19, 2025
b20fbeb
Cleaning, add sqlfilter to joined db
tomstephen Dec 19, 2025
6a3811b
cache database loading
tomstephen Jan 5, 2026
e7b334d
Refactoring
tomstephen Jan 12, 2026
ea2de21
Compacting code
tomstephen Jan 12, 2026
12d362d
Apply suggestions from code review
tomstephen Jan 12, 2026
afda3d1
Refactor aequlibrae plugin to sqlite-map to generalise
tomstephen Jan 13, 2026
5aca220
resolve merge
tomstephen Jan 13, 2026
d260879
sqlite-map: avoid caching remote DBs; clear join-data cache and expor…
tomstephen Jan 13, 2026
1528703
sqlite-map: re-enable DB caching for all paths; deck: honor initialVi…
tomstephen Jan 13, 2026
7cc344f
revert: undo DeckMapComponent.vue edits (restore previous behavior)
tomstephen Jan 13, 2026
8c1c7bc
refactoring, fixes to zoom. Issue with caching
tomstephen Jan 13, 2026
69a3fea
More refactoring
tomstephen Jan 13, 2026
5660709
Init. commit adding POLARIS features
tomstephen Jan 13, 2026
39ccaf5
Drop polaris again, extend db.ts for some better generality
tomstephen Jan 14, 2026
2367e05
Tom/extend tile panel (#4)
tomstephen Jan 15, 2026
174abfd
Revert erroneous changes
tomstephen Jan 15, 2026
60e3568
Cleaning, renaming
tomstephen Jan 15, 2026
cad550a
Refactoring sqlite-map, mostly styling
tomstephen Jan 16, 2026
2a651de
.
tomstephen Jan 16, 2026
4eb8fcc
Linting
tomstephen Jan 16, 2026
6318a64
Move docs out of comments
tomstephen Jan 16, 2026
1d94c35
rename to aequilibrae-map
tomstephen Jan 16, 2026
4d78432
Tidy, replace filesystem with default
tomstephen Jan 16, 2026
29781ab
Rename map 'readers' to 'mapComponents'
tomstephen Jan 16, 2026
ec15521
Fix legend
tomstephen Jan 16, 2026
38dce3f
Refactor
tomstephen Jan 16, 2026
cdddcbf
.
tomstephen Jan 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
"blob-util": "^2.0.2",
"buefy": "^0.9.29",
"bulma": "^1.0.0",
"cartocolor": "^5.0.2",
"color-string": "^1.9.1",
"colormap": "^2.3.1",
"comlink": "^4.4.2",
Expand Down Expand Up @@ -119,6 +120,10 @@
"sax-wasm": "^2.2.4",
"shallow-equal": "^1.2.1",
"shapefile": "^0.6.6",
"spatialite": "^0.1.0",
"spl.js": "^0.1.2",
"sql.js": "^1.13.0",

"the-new-css-reset": "^1.7.3",
"threads": "^1.7.0",
"three": "^0.127.0",
Expand Down
1 change: 1 addition & 0 deletions src/Globals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ export interface FileSystemConfig {
example?: boolean
isGithub?: boolean
isZIB?: boolean
isS3?: boolean // AWS S3 bucket with public access
flask?: boolean // Flask filesystem supports OMX open matrix API - see https://github.com/simwrapper/omx-server
}

Expand Down
30 changes: 25 additions & 5 deletions src/components/LegendColors.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
<template lang="pug">

.legend-colors.flex-col
h4 {{ title }}
p {{ description }}
h4(v-if="title") {{ title }}
p(v-if="description") {{ description }}
ul.list-items
li.legend-row(v-for="item in items" :key="item.value + item.value[0]")
.item-label(v-if="item.label") {{ item.label }}
.item-swatch(:style="`backgroundColor: rgb(${item.color})`")
li.legend-row(v-for="(item, idx) in items" :key="item.label + idx")
// Subtitle
span.legend-subtitle(v-if="item.type === 'subtitle'") {{ item.label }}
// Feature entry
template(v-else)
.item-swatch(v-if="item.shape === 'line' || item.type === 'line'"
:style="`width:32px;height:${item.size||4}px;background:rgb(${item.color});border-radius:2px;align-self:center;`"
)
.item-swatch(v-else-if="item.shape === 'polygon' || item.type === 'polygon'"
:style="`width:20px;height:20px;background:rgb(${item.color});border-radius:4px;border:1px solid #888;display:inline-block;`"
)
.item-swatch(v-else-if="item.shape === 'circle' || item.type === 'circle'"
:style="`width:${item.size||12}px;height:${item.size||12}px;background:rgb(${item.color});border-radius:50%;border:1px solid #888;display:inline-block;`"
)
.item-label {{ item.label }}

</template>

Expand All @@ -32,6 +45,13 @@ export default defineComponent({
margin: 0;
}

.legend-subtitle {
font-weight: bold;
margin-top: 0.5em;
margin-bottom: 0.25em;
display: block;
}

.item-label {
margin: '0 0.5rem 0.0rem 0';
font-weight: 'bold';
Expand Down
1 change: 1 addition & 0 deletions src/dash-panels/_allPanels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export const panelLookup: { [key: string]: AsyncComponent } = {
xml: defineAsyncComponent(() => import('./xml.vue')),

// full-screen map visualizations:
aequilibrae: defineAsyncComponent(() => import('./aequilibrae-map.vue')),
carriers: defineAsyncComponent(() => import('./carriers.vue')),
flowmap: defineAsyncComponent(() => import('./flowmap.vue')),
links: defineAsyncComponent(() => import('./links.vue')),
Expand Down
49 changes: 49 additions & 0 deletions src/dash-panels/aequilibrae-map.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<template lang="pug">
aeq-reader.aeq-panel(
:root="fileSystemConfig.slug"
:subfolder="subfolder"
:config="config"
:thumbnail="false"
@isLoaded="isLoaded"
@error="$emit('error', $event)"
)

</template>

<script lang="ts">
import { defineComponent } from 'vue'
import type { PropType } from 'vue'

import AeqReader from '@/plugins/aequilibrae-map/AequilibraEMapComponent.vue'

export default defineComponent({
name: 'AequilibraEMapPanel',
components: { AeqReader },
props: {
config: Object,
datamanager: Object,
fileSystemConfig: Object,
subfolder: String,
yamlConfig: String,
},
methods: {
isLoaded() {
this.$emit('isLoaded')
},
},
})
</script>

<style scoped lang="scss">
@import '@/styles.scss';

.aeq-panel {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
display: flex;
flex-direction: column;
}
</style>
191 changes: 159 additions & 32 deletions src/dash-panels/tile.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
<template lang="pug">
.content
.tiles-container(v-if="imagesAreLoaded")
.tile(v-for="(value, index) in this.dataSet.data" v-bind:style="{ 'background-color': colors[index % colors.length]}" @click="")
.tile(
v-for="(value, index) in this.dataSet.data"
:style="getTileStyle(index)"
@click=""
)
a(:href="value[urlIndex]" target="_blank" :class="{ 'is-not-clickable': !value[urlIndex] }")
p.tile-title {{ value[tileNameIndex] }}
p.tile-value {{ value[tileValueIndex] }}
p.tile-title(:style="{ color: tileTextColor }") {{ value[tileNameIndex] }}
p.tile-value(:style="{ color: tileTextColor }") {{ value[tileValueIndex] }}
.tile-image(v-if="value[tileImageIndex] != undefined && checkIfItIsACustomIcon(value[tileImageIndex])" :style="{'background': base64Images[index], 'background-size': 'contain'}")
img.tile-image(v-else-if="value[tileImageIndex] != undefined && checkIfIconIsInAssetsFolder(value[tileImageIndex])" v-bind:src="getLocalImage(value[tileImageIndex].trim())" :style="{'background': ''}")
font-awesome-icon.tile-image(v-else-if="value[tileImageIndex] != undefined" :icon="value[tileImageIndex].trim()" size="2xl" :style="{'background': '', 'color': 'black'}")
Expand All @@ -22,9 +26,53 @@ import HTTPFileSystem from '@/js/HTTPFileSystem'
import globalStore from '@/store'
import { arrayBufferToBase64 } from '@/js/util'
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
import { openDb } from '@/plugins/sqlite-map/db'
import { initSql } from '@/plugins/sqlite-map/loader'
import { loadDbWithCache } from '@/plugins/sqlite-map/helpers'

const BASE_URL = import.meta.env.BASE_URL

// color palette options
const PALETTE_PASTEL = [
'#F08080', // Light coral pink
'#FFB6C1', // Pale pink
'#FFDAB9', // peach
'#FFECB3', // cream yellow
'#B0E0E6', // light blue
'#98FB98', // light green
'#FFD700', // golden yellow
'#FFA07A', // salmon pink
'#E0FFFF', // light turquoise
'#FFDAB9', // pink
'#FFC0CB', // pink
'#FFA500', // orange
'#FF8C00', // dark orange
'#FF7F50', // coral red
'#FFE4B5', // papaya
'#ADD8E6', // light blue
'#90EE90', // light green
'#FFD700', // golden yellow
'#FFC0CB', // pink
'#FFA500', // Orange
]

const PALETTE_VIVID = [
'#FF006E', // Vivid Pink
'#FB5607', // Vivid Orange
'#FFBE0B', // Vivid Yellow
'#8338EC', // Vivid Purple
'#3A86FF', // Vivid Blue
'#06FFA5', // Vivid Green
'#FF4365', // Vivid Red
'#00D9FF', // Vivid Cyan
'#FF1493', // Vivid Deep Pink
'#FF8C00', // Vivid Deep Orange
]

const PALETTE_MONOCHROME = [
'#f7f7fe', // Light gray
]

export default defineComponent({
name: 'Tile',
components: { FontAwesomeIcon },
Expand All @@ -44,29 +92,9 @@ export default defineComponent({
// dataSet is either x,y or allRows[]
dataSet: {} as { data?: any; x?: any[]; y?: any[]; allRows?: any },
YAMLrequirementsOverview: { dataset: '' },
colors: [
'#F08080', // Light coral pink
'#FFB6C1', // Pale pink
'#FFDAB9', // peach
'#FFECB3', // cream yellow
'#B0E0E6', // light blue
'#98FB98', // light green
'#FFD700', // golden yellow
'#FFA07A', // salmon pink
'#E0FFFF', // light turquoise
'#FFDAB9', // pink
'#FFC0CB', // pink
'#FFA500', // orange
'#FF8C00', // dark orange
'#FF7F50', // coral red
'#FFE4B5', // papaya
'#ADD8E6', // light blue
'#90EE90', // light green
'#FFD700', // golden yellow
'#FFC0CB', // pink
'#FFA500', // Orange
],
colors: PALETTE_PASTEL,
colorsD3: [
// TODO: remove? Is this being used?
'#1F77B4',
'#FF7F0E',
'#2CA02C',
Expand Down Expand Up @@ -117,10 +145,29 @@ export default defineComponent({
fileApi(): HTTPFileSystem {
return new HTTPFileSystem(this.fileSystemConfig, globalStore)
},
tileBorderColor(): string {
return this.globalState.isDarkMode ? '#fff' : '#000'
},
tileTextColor(): string {
return this.globalState.isDarkMode ? '#fff' : '#363636'
},
},
async mounted() {
this.dataSet = await this.loadFile()
this.validateDataSet()
// Set color palette from config if specified, otherwise default to pastel
if (this.config.colors) {
const paletteKey = this.config.colors.toLowerCase()
if (paletteKey === 'vivid') {
this.colors = PALETTE_VIVID
} else if (paletteKey === 'monochrome') {
this.colors = PALETTE_MONOCHROME
} else {
// Default to pastel for any other value or unrecognized palette
this.colors = PALETTE_PASTEL
}
}

this.dataSet = await this.buildDataset()
// this.validateDataSet()
await this.loadImages()
this.$emit('isLoaded')
console.log(this.dataSet)
Expand Down Expand Up @@ -191,6 +238,79 @@ export default defineComponent({
return []
},

async getDataFromSQLQuery(
database: string,
query: string,
singleValue = true,
titleColumn = 'metric',
valueColumn = 'value'
) {
try {
const trimmedQuery = query.trim()
// open a sqlite connection
const spl = await initSql()
// connect to database
const db = await loadDbWithCache(spl, this.fileApi, openDb, database)
// run query and return result
if (singleValue) {
const queryResult = await db.exec(trimmedQuery).get.first
return queryResult
} else {
const queryResult = await db.exec(trimmedQuery).get.objs
const results = []
for (const obj of queryResult) {
results.push([obj[titleColumn], obj[valueColumn]]) // table columns default to 'metric' and 'value'
}
return results
}
} catch (e) {
console.error('' + e)
this.$emit('error', 'Error querying database: ' + database)
}
return { data: [] }
},

async buildDataset() {
// Datasets can be defined in a handful of ways.
// If `dataset` value is a string, it's a .csv to load.
if (typeof this.config.dataset === 'string') {
return await this.loadFile()
}
// It can be database & sql query
if (this.config.dataset.database && this.config.dataset.query) {
return {
data: await this.getDataFromSQLQuery(
this.config.dataset.database,
this.config.dataset.query,
false,
this.config.dataset.titleCol || 'metric',
this.config.dataset.valueCol || 'value'
),
}
}
// Otherwise it's a list of key-value pairs.
// Values can either be static or be a database & sql query returning a single value.
if (Array.isArray(this.config.dataset)) {
const data: any[] = await Promise.all(
this.config.dataset.map(async (item: any) => {
const key = item.key
const row: any[] = []
row.push(key)
// if the database/query are defined
if (item.value?.database && item.value?.query) {
const result = await this.getDataFromSQLQuery(item.value.database, item.value.query)
row.push(result)
} else {
// otherwise it's a static value
row.push(item.value)
}
return row
})
)
return { data: data }
}
},

validateYAML() {
for (const key in this.YAMLrequirementsOverview) {
if (key in this.config === false) {
Expand Down Expand Up @@ -227,6 +347,14 @@ export default defineComponent({
}
return false
},

getTileStyle(index: number) {
return {
'background-color': this.colors[index % this.colors.length],
border: '1px solid ' + this.tileBorderColor,
color: this.tileTextColor,
}
},
},
})
</script>
Expand Down Expand Up @@ -277,13 +405,13 @@ export default defineComponent({
padding: 20px;
min-width: 250px;
font-family: $fancyFont;
border-color: v-bind(tileBorderColor);
}

.tile .tile-value {
font-size: 2rem;
font-size: 3rem;
font-weight: bold;
width: 100%;
color: #363636; // var(--text) but always the color from the light mode.
grid-column-start: 2;
grid-column-end: 4;
text-align: center;
Expand All @@ -292,10 +420,9 @@ export default defineComponent({

.tile .tile-title {
width: 100%;
font-size: 1.4rem;
height: 5rem;
font-size: 2.5rem;
// height: 3.5rem;
Copy link

Copilot AI Jan 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The commented-out height property on line 318 (// height: 3.5rem;) should either be removed or uncommented if it's needed. Leaving commented code creates maintenance confusion.

Suggested change
// height: 3.5rem;

Copilot uses AI. Check for mistakes.
margin-bottom: 0;
color: #363636; // var(--text) but always the color from the light mode.
text-align: center;
grid-column-start: 1;
grid-column-end: 5;
Expand Down
2 changes: 1 addition & 1 deletion src/fileSystemConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,4 +250,4 @@ try {
console.error('ERROR MERGING URL SHORTCUTS:', '' + e)
}

export default fileSystems
export default fileSystems
Loading
Loading