stash some shit
Signed-off-by: Frank Villaro-Dixon <frank@villaro-dixon.eu>
This commit is contained in:
parent
3a3d997d49
commit
311ce09e15
23 changed files with 3454 additions and 0 deletions
3
ui/.gitignore
vendored
Normal file
3
ui/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
db.sqlite
|
||||
node_modules/
|
||||
public/rivers.json
|
8
ui/Dockerfile
Normal file
8
ui/Dockerfile
Normal file
|
@ -0,0 +1,8 @@
|
|||
FROM node:20
|
||||
WORKDIR /app
|
||||
|
||||
COPY package*.json ./
|
||||
RUN npm install
|
||||
|
||||
COPY . .
|
||||
RUN npm run build
|
5
ui/README.md
Normal file
5
ui/README.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
# vue3-openlayers Starter Template
|
||||
|
||||
See [vue3-openlayers](https://github.com/MelihAltintas/vue3-openlayers)
|
||||
|
||||
You can use this starter template as a playground or for providing reproduction steps, when opening new [issues](https://github.com/MelihAltintas/vue3-openlayers/issues).
|
24
ui/_gitignore
Normal file
24
ui/_gitignore
Normal file
|
@ -0,0 +1,24 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
37
ui/generate-db.py
Normal file
37
ui/generate-db.py
Normal file
|
@ -0,0 +1,37 @@
|
|||
import json
|
||||
import sqlite3
|
||||
|
||||
def db_to_js(db_name: str):
|
||||
conn = sqlite3.connect(db_name)
|
||||
c = conn.cursor()
|
||||
c.execute("SELECT wayid, name, length, start_ele, end_ele, slope_correct, slope_confidence, centroid_lat, centroid_lon FROM rivers")
|
||||
|
||||
rows = c.fetchall()
|
||||
ret = []
|
||||
for river in rows:
|
||||
sc = river[5]
|
||||
if sc == 1:
|
||||
#print(f"OK: {river}")
|
||||
continue
|
||||
r = {
|
||||
'wayid': river[0],
|
||||
'name': river[1],
|
||||
'length': river[2],
|
||||
'start_ele': river[3],
|
||||
'end_ele': river[4],
|
||||
'slope_correct': river[5],
|
||||
'slope_confidence': river[6],
|
||||
'centroid_lat': river[7],
|
||||
'centroid_lon': river[8]
|
||||
}
|
||||
if r['slope_confidence'] > 0.4:
|
||||
print(f"KO: {r}")
|
||||
if r['start_ele'] + 20 < r['end_ele']:
|
||||
print(f"KO: {r}")
|
||||
ret.append(r)
|
||||
return ret
|
||||
|
||||
if __name__ == '__main__':
|
||||
rivers = db_to_js('db.sqlite')
|
||||
with open('public/rivers.json', 'w') as f:
|
||||
f.write(json.dumps(rivers, indent=1))
|
13
ui/index.html
Normal file
13
ui/index.html
Normal file
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>OSM QA: uphill rivers</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
2650
ui/package-lock.json
generated
Normal file
2650
ui/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
26
ui/package.json
Normal file
26
ui/package.json
Normal file
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"name": "vue3-openlayers-starter",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite --mode development",
|
||||
"build": "vue-tsc && vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.5.1",
|
||||
"bootstrap": "^5.3.2",
|
||||
"chart.js": "^4.4.0",
|
||||
"vue": "^3.2.47",
|
||||
"vue-chartjs": "^5.2.0",
|
||||
"vue-router": "^4.2.5",
|
||||
"vue3-openlayers": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^4.1.0",
|
||||
"typescript": "^4.9.3",
|
||||
"vite": "^4.2.1",
|
||||
"vue-tsc": "^1.2.0"
|
||||
}
|
||||
}
|
1
ui/public/.gitignore
vendored
Normal file
1
ui/public/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
rivers.json
|
0
ui/public/.gitkeep
Normal file
0
ui/public/.gitkeep
Normal file
23
ui/src/App.vue
Normal file
23
ui/src/App.vue
Normal file
|
@ -0,0 +1,23 @@
|
|||
<template>
|
||||
<router-link :to="{ path: `/` }">
|
||||
<h2 class="text-center">Openstreetmap QA: uphill rivers</h2>
|
||||
</router-link>
|
||||
<router-view />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "App",
|
||||
components: {},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
#app {
|
||||
font-family: Avenir, Helvetica, Arial, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
color: #2c3e50;
|
||||
margin-top: 60px;
|
||||
}
|
||||
</style>
|
7
ui/src/App2.vue
Normal file
7
ui/src/App2.vue
Normal file
|
@ -0,0 +1,7 @@
|
|||
<script setup lang="ts">
|
||||
import TheMap from './components/TheMap.vue';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<TheMap />
|
||||
</template>
|
0
ui/src/assets/.gitkeep
Normal file
0
ui/src/assets/.gitkeep
Normal file
246
ui/src/components/Home copy.vue
Normal file
246
ui/src/components/Home copy.vue
Normal file
|
@ -0,0 +1,246 @@
|
|||
<template>
|
||||
<notifications
|
||||
class="mt-3 ms-3"
|
||||
:duration="2000"
|
||||
:width="250"
|
||||
animation-name="v-fade-left"
|
||||
position="top left"
|
||||
/>
|
||||
<div class="container my-5">
|
||||
<h3 class="text-center">Liste des clusters</h3>
|
||||
<!--
|
||||
<div class="row d-flex justify-content-center">
|
||||
<div class="col-xs-12 col-lg-6 my-3">
|
||||
<div class="form-group mb-3">
|
||||
<label for="todo" class="form-label">Add ToDo</label>
|
||||
<div class="row">
|
||||
<div class="col-10">
|
||||
<input
|
||||
v-model="todo"
|
||||
type="text"
|
||||
class="form-control"
|
||||
name="todo"
|
||||
id="todo"
|
||||
placeholder="Enter New Todo"
|
||||
v-bind:class="{ 'is-invalid': input_errors.length > 0, 'is-valid': input_errors.length == 0 && todo != '' }"
|
||||
/>
|
||||
<div class="invalid-feedback">
|
||||
<span :key="key" v-for="(error,key) in input_errors">{{ error }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-2 d-grid gap-2">
|
||||
<button class="btn btn-primary btn-s float-end" @click="save">Add</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group"></div>
|
||||
</div>
|
||||
</div>
|
||||
-->
|
||||
|
||||
<div class="row d-flex justify-content-center mt-3" v-if="Clusters.length">
|
||||
<div class="col-md-6">
|
||||
<h5 class="mb-3">Liste des paravalanches:</h5>
|
||||
Trier par:
|
||||
<select v-model="sortby">
|
||||
<option value="altitude">Altitude</option>
|
||||
<option value="length">Long. de paravalanche</option>
|
||||
<option value="energy_yr">Energie annuelle</option>
|
||||
<option value="efficiency">Rendement</option>
|
||||
</select>
|
||||
|
||||
<div style="list-style-type: none;">
|
||||
<li
|
||||
v-for="cluster in sortedClusters"
|
||||
:key="cluster.id"
|
||||
class="row"
|
||||
style="
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 10px 24px;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 12px;
|
||||
border: 2px solid hsla(0, 0%, 0%, 0.35);
|
||||
"
|
||||
>
|
||||
<div class="col-8">
|
||||
<span
|
||||
v-bind:style="cluster.done ? 'text-decoration:line-through;' : ''"
|
||||
>📏 {{ parseInt(cluster.length) }} m - ⛰️ {{ cluster.alt }} m<br>
|
||||
{{ parseInt(cluster.yield) }} kWh/kWp - {{ parseInt(cluster.energy_total/1000) }} MWh/yr
|
||||
</span>
|
||||
</div>
|
||||
<div class="col-2 d-flex justify-content-center">
|
||||
<span
|
||||
class="form-check form-switch"
|
||||
@click="done_todo(cluster)"
|
||||
style="margin-left:20px;"
|
||||
> Installer
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="checkbox"
|
||||
:id="cluster.id"
|
||||
:value="cluster.id"
|
||||
:key="cluster.id"
|
||||
v-model="choosen_installs"
|
||||
data-onstyle="#1f2023"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div class="col-2 d-flex justify-content-center">
|
||||
<!--
|
||||
<button class="btn btn-primary btn-sm" @click="delete_todo(cluster.id)">+ details</button>
|
||||
-->
|
||||
<router-link :to="{ path: `/clusters/${cluster.id}`}">
|
||||
<button class="btn btn-primary btn-sm">+ details</button>
|
||||
</router-link>
|
||||
</div>
|
||||
</li>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<h4>Statistiques</h4>
|
||||
(cocher sur "installer" pour ajouter aux statistiques)
|
||||
<ul>
|
||||
<li>Longueur totale: {{ Math.round(stats['length']/1000 * 10)/10 }} km</li>
|
||||
<li>Energie totale: {{ Math.round(stats['energy']/1000) }} MWh/yr</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
sortby: 'length',
|
||||
stats_length: 0,
|
||||
choosen_installs: [],
|
||||
todo: "",
|
||||
Clusters: [],
|
||||
errors: [],
|
||||
newTodo: {
|
||||
todo: "",
|
||||
done: false
|
||||
},
|
||||
responseData: null,
|
||||
input_errors: []
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
sortedClusters() {
|
||||
var clusters = this.Clusters.slice();
|
||||
|
||||
if(this.sortby == "length"){
|
||||
return clusters.sort(function(a,b){
|
||||
return b.length - a.length;
|
||||
})
|
||||
}
|
||||
else if(this.sortby == "altitude") {
|
||||
return clusters.sort(function(a,b){
|
||||
return b.alt - a.alt;
|
||||
})
|
||||
}
|
||||
else if(this.sortby == "energy_yr") {
|
||||
return clusters.sort(function(a,b){
|
||||
return b.energy_total - a.energy_total;
|
||||
})
|
||||
}
|
||||
else if(this.sortby == "efficiency") {
|
||||
return clusters.sort(function(a,b){
|
||||
return b.yield - a.yield;
|
||||
})
|
||||
}
|
||||
else {
|
||||
return clusters;
|
||||
}
|
||||
},
|
||||
stats() {
|
||||
let installed = this.Clusters.filter((item) => this.choosen_installs.includes(item.id))
|
||||
|
||||
let energy_sum = 0;
|
||||
let length_sum = 0;
|
||||
installed.forEach(function (value) {
|
||||
energy_sum += value.energy_total;
|
||||
length_sum += value.length;
|
||||
});
|
||||
|
||||
return {
|
||||
energy: energy_sum,
|
||||
length: length_sum,
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.getClusters();
|
||||
},
|
||||
methods: {
|
||||
async getClusters() {
|
||||
try {
|
||||
const response = await this.$axios.get("/paralist.js");
|
||||
console.log('YEAH !')
|
||||
this.Clusters = response.data;
|
||||
} catch (error) {
|
||||
this.errors.push(error);
|
||||
}
|
||||
},
|
||||
/*
|
||||
async save() {
|
||||
if (this.input_errors.length > 0 || this.todo == '') {
|
||||
if (this.todo == '' && this.input_errors.length == 0)
|
||||
this.input_errors.push('ToDo field cannot be left blank')
|
||||
this.input_errors.forEach((value) => {
|
||||
this.$notify(value);
|
||||
});
|
||||
} else {
|
||||
try {
|
||||
this.newTodo.todo = this.todo;
|
||||
const response = await this.$axios.post("/todos", this.newTodo);
|
||||
this.responseData = response.data;
|
||||
} catch (error) {
|
||||
this.errors.push(error);
|
||||
}
|
||||
this.getTodos();
|
||||
this.$notify("Added Succesfully");
|
||||
this.todo = "";
|
||||
}
|
||||
},
|
||||
async delete_todo(index) {
|
||||
try {
|
||||
const response = await this.$axios.delete("/todos/" + index);
|
||||
this.responseData = response.data;
|
||||
} catch (error) {
|
||||
this.errors.push(error);
|
||||
}
|
||||
this.getTodos();
|
||||
this.$notify("Deleted Succesfully");
|
||||
},
|
||||
async done_todo(todo) {
|
||||
try {
|
||||
const response = await this.$axios.put("/todos/" + todo.id, { "todo": todo.todo, "done": !todo.done });
|
||||
this.responseData = response.data;
|
||||
} catch (error) {
|
||||
this.errors.push(error);
|
||||
}
|
||||
this.getTodos();
|
||||
this.$notify("Updated Succesfully");
|
||||
},
|
||||
*/
|
||||
},
|
||||
watch: {
|
||||
todo(val) {
|
||||
this.input_errors = [];
|
||||
if (val == '') {
|
||||
this.input_errors.push('ToDo field cannot be left blank')
|
||||
return;
|
||||
}
|
||||
if (val.length < 3 || val.length > 40) {
|
||||
this.input_errors.push('ToDo field be Minimum 6, Maximum 25 characters')
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
153
ui/src/components/Home.vue
Normal file
153
ui/src/components/Home.vue
Normal file
|
@ -0,0 +1,153 @@
|
|||
<template>
|
||||
<div class="container my-5">
|
||||
<span v-if="!Rivers.length">
|
||||
Loading... If nothing happens in a while, please reload the page
|
||||
</span>
|
||||
<div class="row d-flex justify-content-center mt-3" v-if="Rivers.length">
|
||||
<div class="col-md-6">
|
||||
<h5 class="mb-3">Uphill rivers:</h5>
|
||||
Sort by:
|
||||
<select v-model="sortby">
|
||||
<option value="wayid">Way id</option>
|
||||
<option value="alt-diff">altitude difference</option>
|
||||
<option value="confidence">confidence</option>
|
||||
<option value="length">length</option>
|
||||
</select>
|
||||
|
||||
<div style="list-style-type: none;">
|
||||
<li v-for="river in sortedRivers" :key="river.id" class="row" style="
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 10px 24px;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 12px;
|
||||
border: 2px solid hsla(0, 0%, 0%, 0.35);
|
||||
">
|
||||
<div class="col-7">
|
||||
<span v-if="river.name">
|
||||
{{ river.name }}
|
||||
</span>
|
||||
<b>{{ parseInt(river.length) }} m</b>
|
||||
( {{ river.slope_confidence }})<br>
|
||||
Start ele.: {{ river.start_ele | round }} m - End ele.: {{ river.end_ele | round }}m<br>
|
||||
{{ river.wayid }}
|
||||
</div>
|
||||
<!--
|
||||
<div class="col-2 d-flex justify-content-center">
|
||||
<span class="form-check form-switch" style="margin-left:20px;"> Choisir
|
||||
<input class="form-check-input" type="checkbox" :id="cluster.id" :value="cluster.id"
|
||||
:key="cluster.id" v-model="choosen_installs" data-onstyle="#1f2023" />
|
||||
</span>
|
||||
</div>
|
||||
-->
|
||||
<br>
|
||||
<hr>
|
||||
<div class="col-2 d-flex justify-content-center">
|
||||
<router-link :to="{ path: `/river/${river.wayid}` }">
|
||||
<button class="btn btn-primary btn-sm">+ details</button>
|
||||
</router-link>
|
||||
</div>
|
||||
<div class="col-2 d-flex justify-content-center">
|
||||
<button class="btn btn-primary btn-sm" @click="openOnJOSM(river.wayid)">+ JOSM</button>
|
||||
</div>
|
||||
<div class="col-2 d-flex justify-content-center">
|
||||
<a :href="`https://https://www.openstreetmap.org/way/${ river.wayid }`">
|
||||
<button class="btn btn-primary btn-sm">OSM</button>
|
||||
</a>
|
||||
</div>
|
||||
</li>
|
||||
</div>
|
||||
</div>
|
||||
<!--
|
||||
<div class="col-md-3">
|
||||
<h4>Somme des installations choisies</h4>
|
||||
(cocher sur "installer" pour ajouter aux statistiques)
|
||||
<ul>
|
||||
<li>Longueur totale: {{ Math.round(stats['length'] / 1000 * 10) / 10 }} km</li>
|
||||
<li>Energie totale: {{ Math.round(stats['energy'] / 1000) }} MWh/yr</li>
|
||||
</ul>
|
||||
</div>
|
||||
-->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
Contact: f@vi-di.fr
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
sortby: 'length',
|
||||
stats_length: 0,
|
||||
sortedRivers: [],
|
||||
Rivers: [],
|
||||
errors: [],
|
||||
responseData: null,
|
||||
input_errors: []
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
sortedRivers() {
|
||||
var rivers = this.Rivers.slice();
|
||||
|
||||
if (this.sortby == "length") {
|
||||
return rivers.sort(function (a, b) {
|
||||
return b.length - a.length;
|
||||
})
|
||||
}
|
||||
else if (this.sortby == "confidence") {
|
||||
return rivers.sort(function (a, b) {
|
||||
return b.slope_confidence - a.slope_confidence;
|
||||
})
|
||||
}
|
||||
else if (this.sortby == "alt-diff") {
|
||||
return rivers.sort(function (a, b) {
|
||||
return Math.abs(b.start_ele - b.end_ele) > Math.abs(a.start_ele - a.end_ele);
|
||||
})
|
||||
}
|
||||
else {
|
||||
console.log("Unknown sortby value: " + this.sortby)
|
||||
return rivers;
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.getRivers();
|
||||
},
|
||||
methods: {
|
||||
async getRivers() {
|
||||
try {
|
||||
const response = await this.$axios.get("/rivers.json");
|
||||
console.log('YEAH !')
|
||||
this.Rivers = response.data;
|
||||
} catch (error) {
|
||||
this.errors.push(error);
|
||||
}
|
||||
},
|
||||
async openOnJOSM(wayid) {
|
||||
console.log('Will open on josm!')
|
||||
try {
|
||||
await this.$axios.get("http://localhost:8111/load_object?new_layer=true&objects=w"+wayid);
|
||||
console.log('YEAH !')
|
||||
} catch (error) {
|
||||
this.errors.push(error);
|
||||
}
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
todo(val) {
|
||||
this.input_errors = [];
|
||||
if (val == '') {
|
||||
this.input_errors.push('ToDo field cannot be left blank')
|
||||
return;
|
||||
}
|
||||
if (val.length < 3 || val.length > 40) {
|
||||
this.input_errors.push('ToDo field be Minimum 6, Maximum 25 characters')
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
124
ui/src/components/River.vue
Normal file
124
ui/src/components/River.vue
Normal file
|
@ -0,0 +1,124 @@
|
|||
<template>
|
||||
<div class="container my-5">
|
||||
<h2 class="text-center">River details</h2>
|
||||
<div class="row d-flex justify-content-center mt-3">
|
||||
<div class="col-md-6">
|
||||
<h3>Characteristics
|
||||
</h3>
|
||||
<ul>
|
||||
<li>Est. length: {{ Math.round(river.length) }}m</li>
|
||||
<li>Altitude moyenne: {{ cluster.alt }} m</li>
|
||||
<li>Commune: {{cluster.city}}
|
||||
<span v-if="cluster.city == 'Bellwald'">☀️</span>
|
||||
</li>
|
||||
<li>Puissance installable: {{ Math.round(cluster.num_panels * .4) }} kWp</li>
|
||||
<li>Azimuth: {{Math.round(cluster.azimuth)}}°</li>
|
||||
<li>Energie annuelle: {{ Math.round(cluster.energy_total) }} MWh</li>
|
||||
<li>Efficience: {{ Math.round(cluster.yield) }} kWh/kWp</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<Bar id="my-chart-id" :options="chartOptions" :data="chartData" />
|
||||
(ceci est une estimation, sans prise en compte de ombrage)
|
||||
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<ol-map :loadTilesWhileAnimating="true" :loadTilesWhileInteracting="true" style="height: 400px">
|
||||
<ol-view ref="view" :center="center" zoom="13" :projection="projection" />
|
||||
|
||||
<ol-tile-layer>
|
||||
<ol-source-osm />
|
||||
</ol-tile-layer>
|
||||
<ol-vector-layer>
|
||||
<ol-source-vector>
|
||||
<ol-feature v-for="c in cluster_geom['features']">
|
||||
<ol-geom-line-string :coordinates="c['geometry']['coordinates']"></ol-geom-line-string>
|
||||
<ol-style>
|
||||
<ol-style-stroke color="blue" width="2"></ol-style-stroke>
|
||||
</ol-style>
|
||||
</ol-feature>
|
||||
</ol-source-vector>
|
||||
</ol-vector-layer>
|
||||
|
||||
</ol-map>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, inject } from 'vue';
|
||||
import { Bar } from 'vue-chartjs'
|
||||
import { Chart as ChartJS, Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale } from 'chart.js'
|
||||
|
||||
ChartJS.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale)
|
||||
|
||||
export default {
|
||||
name: 'BarChart',
|
||||
components: { Bar },
|
||||
data() {
|
||||
const projection = ref('EPSG:3857');
|
||||
|
||||
const format = inject('ol-format');
|
||||
const geoJson = new format.GeoJSON();
|
||||
|
||||
return {
|
||||
projection,
|
||||
geoJson,
|
||||
cluster: {},
|
||||
cluster_geom: [],
|
||||
data_loaded: false,
|
||||
chartOptions: {
|
||||
responsive: true
|
||||
}
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
center() {
|
||||
if (this.data_loaded) {
|
||||
console.log(this.cluster.centroid);
|
||||
return this.cluster.centroid
|
||||
}
|
||||
return ref([40, 40]);
|
||||
},
|
||||
chartData() {
|
||||
if(this.data_loaded) {
|
||||
let dats = this.cluster['pv_norm']['outputs']['monthly']['fixed'];
|
||||
let graphVals = dats.map((d) => d.E_m)
|
||||
return {
|
||||
labels: ['Jan', 'Fev', 'Mar', 'Avr', 'Mai', 'Jun', 'Jul', 'Aou', 'Sep', 'Oct', 'Nov', 'Dec'],
|
||||
datasets: [{
|
||||
data: graphVals,
|
||||
label: 'Energie annuelle/kWp',
|
||||
}],
|
||||
}
|
||||
}
|
||||
return {
|
||||
labels: [],
|
||||
datasets: [],
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getCluster();
|
||||
},
|
||||
methods: {
|
||||
async getCluster() {
|
||||
try {
|
||||
let id = this.$route.params.clusterid;
|
||||
|
||||
const rgeom = await this.$axios.get(`/cluster-geom-${id}.json`);
|
||||
this.cluster_geom = rgeom.data;
|
||||
|
||||
const r = await this.$axios.get(`/cluster-meta-${id}.json`);
|
||||
this.cluster = r.data;
|
||||
this.data_loaded = true;
|
||||
console.log(rgeom.data)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
this.errors.push(error);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
43
ui/src/components/TheMap.vue
Normal file
43
ui/src/components/TheMap.vue
Normal file
|
@ -0,0 +1,43 @@
|
|||
<template>
|
||||
<ol-map
|
||||
:loadTilesWhileAnimating="true"
|
||||
:loadTilesWhileInteracting="true"
|
||||
style="height: 400px"
|
||||
>
|
||||
<ol-view
|
||||
ref="view"
|
||||
:center="center"
|
||||
:rotation="rotation"
|
||||
:zoom="zoom"
|
||||
:projection="projection"
|
||||
/>
|
||||
|
||||
<ol-tile-layer>
|
||||
<ol-source-osm />
|
||||
</ol-tile-layer>
|
||||
</ol-map>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, inject } from 'vue';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const center = ref([40, 40]);
|
||||
const projection = ref('EPSG:4326');
|
||||
const zoom = ref(3);
|
||||
const rotation = ref(0);
|
||||
|
||||
const format = inject('ol-format');
|
||||
const geoJson = new format.GeoJSON();
|
||||
|
||||
return {
|
||||
center,
|
||||
projection,
|
||||
zoom,
|
||||
rotation,
|
||||
geoJson,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
32
ui/src/main.ts
Normal file
32
ui/src/main.ts
Normal file
|
@ -0,0 +1,32 @@
|
|||
import { createApp } from 'vue';
|
||||
|
||||
import VueRouter from './router';
|
||||
import App from './App.vue';
|
||||
|
||||
import OpenLayersMap from 'vue3-openlayers';
|
||||
import 'vue3-openlayers/dist/vue3-openlayers.css';
|
||||
|
||||
import { Bar } from 'vue-chartjs';
|
||||
|
||||
import axios from "axios";
|
||||
import "bootstrap/dist/css/bootstrap.min.css"
|
||||
import "bootstrap"
|
||||
|
||||
let baseUrl;
|
||||
if (window.location.hostname === "localhost") {
|
||||
baseUrl = "./public/"
|
||||
}
|
||||
|
||||
const axiosInstance = axios.create({
|
||||
baseURL: baseUrl,
|
||||
//baseURL: "https://parapower.k3s.fr/data/"
|
||||
});
|
||||
|
||||
|
||||
|
||||
const app = createApp(App)
|
||||
app.config.globalProperties.$axios = axiosInstance;
|
||||
app.use(OpenLayersMap)
|
||||
app.use(VueRouter)
|
||||
|
||||
app.mount('#app');
|
21
ui/src/router/index.ts
Normal file
21
ui/src/router/index.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import { createRouter, createWebHistory } from "vue-router";
|
||||
import Home from "../components/Home.vue";
|
||||
import River from "../components/River.vue";
|
||||
|
||||
const routerHistory = createWebHistory();
|
||||
const router = createRouter({
|
||||
history: routerHistory,
|
||||
routes: [
|
||||
{
|
||||
path: "/",
|
||||
name: "Home",
|
||||
component: Home,
|
||||
},
|
||||
{
|
||||
path: "/river/:riverid",
|
||||
name: "River",
|
||||
component: River,
|
||||
}
|
||||
],
|
||||
});
|
||||
export default router;
|
1
ui/src/vite-env.d.ts
vendored
Normal file
1
ui/src/vite-env.d.ts
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/// <reference types="vite/client" />
|
19
ui/tsconfig.json
Normal file
19
ui/tsconfig.json
Normal file
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"strict": true,
|
||||
"jsx": "preserve",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"esModuleInterop": true,
|
||||
"lib": ["ESNext", "DOM"],
|
||||
"skipLibCheck": true,
|
||||
"noEmit": true,
|
||||
"allowJs": true
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
9
ui/tsconfig.node.json
Normal file
9
ui/tsconfig.node.json
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
9
ui/vite.config.ts
Normal file
9
ui/vite.config.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
resolve: {
|
||||
}
|
||||
})
|
Loading…
Reference in a new issue