Skip to content
Snippets Groups Projects
Commit 30f923b7 authored by Clemens Berteld's avatar Clemens Berteld
Browse files

Merge remote-tracking branch 'origin/master'

parents 7d90010a 7f258b03
No related branches found
No related tags found
No related merge requests found
<template>
<div class="main">
<WeatherMap />
</div>
<!-- -->
<v-app>
<div class="main">
<WeatherMap id="weathermap"></WeatherMap>
<Legend id="legend"></Legend>
</div>
</v-app>
</template>
......@@ -10,15 +14,28 @@
width: 100%;
height: 100%;
}
#legend{
width:20%;
height:inherit;
position:relative;
float:left;
}
#weathermap{
width:80%;
height:inherit;
position:relative;
float:left;
}
</style>
<script lang="ts">
import { Component, Vue} from 'vue-property-decorator';
import 'ol/ol.css';
import WeatherMap from './src/WeatherMap.vue'
import WeatherMap from './src/WeatherMap.vue';
import Legend from './src/Legend.vue';
@Component({
components: {WeatherMap}
components: {WeatherMap, Legend}
})
export default class App extends Vue{
name: 'App'
......
import Vue from 'vue';
import vuetify from './src/plugins/vuetify';
import App from './App.vue';
import vuetify from './src/plugins/vuetify'
//new Vue({ render: createElement => createElement(App) }).$mount('#app');
new Vue({vuetify, render: createElement => createElement(App)}).$mount('#app')
\ No newline at end of file
This diff is collapsed.
......@@ -7,6 +7,8 @@
"build": "parcel build --public-url . index.html"
},
"dependencies": {
"core-js": "^3.18.0",
"d3": "^7.0.3",
"ol": "^6.6.1",
"vue": "^2.6.14",
"vue-class-component": "^7.2.6",
......@@ -16,11 +18,15 @@
"vuetify": "^2.5.8"
},
"devDependencies": {
"@types/d3": "^7.0.0",
"@vue/component-compiler-utils": "^3.2.2",
"parcel": "^2.0.0-rc.0",
"parcel-bundler": "^1.12.5",
"regenerator-runtime": "^0.13.9",
"typescript": "^4.4.3",
"vue-template-compiler": "^2.6.14"
},
"browserslist": "defaults"
"browserslist": [
"last 2 Chrome versions"
]
}
<template>
<div>
<p class="font-weight-black">
Legend
</p>
<v-card>
<v-card-text>
<p class="font-weight-medium">
Durchschnittstemperatur Layer 1:
</p>
<v-range-slider
v-model="range0"
step="1"
:min="daterange[0]"
:max="daterange[1]"
thumb-label="always"
style="margin-top:3em"
>
</v-range-slider>
</v-card-text>
</v-card>
<v-card style="margin-top:10px;">
<v-card-text>
<p class="font-weight-medium">
Durchschnittstemperatur Layer 1:
</p>
<v-checkbox
v-model="checkbox"
:label="`Checkbox 1: ${checkbox.toString()}`"
></v-checkbox>
<v-range-slider
v-model="range1"
step="1"
:min="daterange[0]"
:max="daterange[1]"
thumb-label="always"
style="margin-top:3em"
>
</v-range-slider>
</v-card-text>
</v-card>
</div>
</template>
<script lang="ts">
import {Vue, Ref, Component } from 'vue-property-decorator';
@Component({})
export default class Legend extends Vue{
private checkbox: boolean = true;
private daterange: number[] = [1900, 2020];
private range0: number[] = [1960, 1990];
private range1: number[] = [1991, 2020];
mounted(){
console.log("Legend mounted");
}
}
</script>
<template>
<div ref="station-chart" id="stationChartSVG" width="200px" height="200px"></div>
</template>
<script lang="ts">
import * as d3 from 'd3';
import {Vue, Ref } from 'vue-property-decorator';
import {TemperatureSeries} from './StationLayer';
export default class StationChartPopup extends Vue{
name = 'StationChartPopup';
private d3svg: any;
private path: any;
private xScale: any;
private yScale: any;
private yAxis: any;
private yAxisContainer: any;
private xAxisContainer: any;
private xAxis: any;
private margin = {top: 10, right: 30, bottom: 30, left: 60}
private width = 500 - this.margin.left - this.margin.right;
private height = 200 - this.margin.top - this.margin.bottom;
mounted(){
}
public renderGraph(tSeries: TemperatureSeries[]): void{
if (!this.path){
console.log("new path 2")
this.d3svg = d3.select("#stationChartSVG")
.append("svg")
.attr("width", this.width + this.margin.left + this.margin.right)
.attr("height", this.height + this.margin.top + this.margin.bottom)
.append("g")
.attr("transform", "translate("+this.margin.left+","+this.margin.top+")");
this.xScale = d3.scaleLinear()
.domain(d3.extent(tSeries, function(d){return d.date}))
.range([0, this.width]);
this.xAxis = d3.axisBottom(this.xScale).tickFormat(d3.format("d"));
this.xAxisContainer = this.d3svg.append("g")
.attr("transform", "translate(0,"+this.height+")")
.call(this.xAxis);
this.yScale = d3.scaleLinear()
.domain([d3.min(tSeries, function(d){return d.value}), d3.max(tSeries, function(d){return d.value})])
.range([this.height, 0]);
this.yAxis = d3.axisLeft(this.yScale);
this.yAxisContainer = this.d3svg.append("g")
.call(this.yAxis);
}
this.xScale.domain(d3.extent(tSeries, function(d){return d.date})).range([0, this.width]);
this.xAxis = d3.axisBottom(this.xScale).tickFormat(d3.format("d"));
this.xAxisContainer.call(this.xAxis).transition().duration(1000);
this.yScale.domain([d3.min(tSeries, function(d){return d.value}), d3.max(tSeries, function(d){return d.value})])
.range([this.height, 0]).nice();
this.yAxisContainer.call(this.yAxis).transition()
.duration(1000);
this.path = this.d3svg.selectAll(".t-line")
.data([tSeries], function(d){ return d.value });
this.path.enter().append("path")
.attr("class", "t-line")
.merge(this.path)
.transition()
.duration(1000)
.attr("d", d3.line()
.x((d)=>{return this.xScale(d.date)})
.y((d)=>{return this.yScale(d.value)}))
.attr("fill", "none")
.attr("stroke", "blue")
.attr("stroke-width", 2);
}
}
</script>
......@@ -4,8 +4,13 @@ import GeoJSON from 'ol/format/GeoJSON';
import {Circle as CircleStyle, Fill, Stroke, Style, Text} from 'ol/style';
import MapProperties from './MapProperties';
export default class StationLayer{
export interface TemperatureSeries{
date: number;
value: number;
}
export default class StationLayer{
public static readonly layerName: string = "StationLayer";
private layer: any;
private mapProperties: MapProperties;
......@@ -13,6 +18,7 @@ export default class StationLayer{
this.mapProperties = mapProperties;
this.layer = new VectorLayer({
className: StationLayer.layerName,
source: new VectorSource({
url: "http://localhost/germanStation.geojson",
format: new GeoJSON(),
......@@ -27,7 +33,6 @@ export default class StationLayer{
protected stationStyle(feature){
console.log(feature.getProperties());
let fontSize = 15
let label = '\u272A';
if(this.mapProperties.getZoomLevel()>=8){
......@@ -47,4 +52,22 @@ export default class StationLayer{
});
}
public getTemperatureSeriesFromFeature(feature: any): TemperatureSeries[]{
let series: TemperatureSeries[] = new Array<TemperatureSeries>();
console.log(feature);
/* series.push({date: 2010, value: feature.get(2010)});
series.push({date: 2011, value: feature.get(2011)});
series.push({date: 2012, value: feature.get(2012)});
series.push({date: 2013, value: feature.get(2013)});
series.push({date: 2014, value: feature.get(2014)});
*/
feature.getKeys().forEach(element => {
if(!isNaN(element) && Number.parseInt(element)>=1800 && feature.get(element)!=null){
series.push({date: Number.parseInt(element), value: feature.get(element)});
}
});
return series;
}
}
\ No newline at end of file
......@@ -2,29 +2,83 @@
<template>
<div class="weatherContainer">
<div ref="weathermap" class="weathermap" />
<div ref="popup" class="ol-popup">
<a href="#" ref="popup-closer" class="ol-popup-closer"></a>
<div ref="popup-content">
</div>
<StationChartPopup ref="StationChartPopup"/>
</div>
</div>
</template>
<style scoped>
.weathermap {
width: inherit;
height: inherit;
width: 100%;
height: 100%;
position:absolute;
}
.ol-popup {
position: absolute;
background-color: white;
box-shadow: 0 1px 4px rgba(0,0,0,0.2);
padding: 15px;
border-radius: 10px;
border: 1px solid #cccccc;
bottom: 12px;
left: -50px;
min-width: 280px;
}
.ol-popup:after, .ol-popup:before {
top: 100%;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
}
.ol-popup:after {
border-top-color: white;
border-width: 10px;
left: 48px;
margin-left: -10px;
}
.ol-popup:before {
border-top-color: #cccccc;
border-width: 11px;
left: 48px;
margin-left: -11px;
}
.ol-popup-closer {
text-decoration: none;
position: absolute;
top: 2px;
right: 8px;
}
.ol-popup-closer:after {
content: "✖";
}
</style>
<script lang="ts">
import {Vue, Ref, Component } from 'vue-property-decorator';
import View from 'ol/View';
import Map from 'ol/Map';
import OSM from 'ol/source/OSM';
import Overlay from 'ol/Overlay';
import TileLayer from 'ol/layer/Tile';
import { fromLonLat} from 'ol/proj';
import 'ol/ol.css';
import StationLayer from './StationLayer';
import MapProperties from './MapProperties';
import StationChartPopup from './StationChartPopup.vue';
@Component({name : 'WeatherMap'})
@Component({components:{StationChartPopup}})
export default class WeatherMap extends Vue{
@Ref('weathermap') readonly targetElement!: HTMLElement;
......@@ -32,7 +86,23 @@ export default class WeatherMap extends Vue{
private projection: string = 'EPSG:3857'; //4236
private mapProperties: MapProperties;
private stationLayer: StationLayer;
@Ref('StationChartPopup') stationChartPopup: StationChartPopup;
@Ref('popup') container: HTMLElement;
@Ref('popup-content') content: HTMLElement;
@Ref('popup-closer') closer: HTMLElement;
private overlay:Overlay;
public mounted(): void{
this.overlay = new Overlay({
element: this.container,
autoPan: true,
autoPanAnimation: {
duration: 250,
},
});
this.map = new Map({
target: this.targetElement,
layers: [
......@@ -45,13 +115,53 @@ export default class WeatherMap extends Vue{
center: fromLonLat([11, 51.3]),
constrainResolution: true,
projection: this.projection
})
}),
overlays: [this.overlay],
});
this.mapProperties = new MapProperties(this.map, this.projection);
this.appendStationLayer();
this.map.on('click', (evt) => {
const coordinate = evt.coordinate;
console.log(coordinate);
var openPopup: boolean = false;
this.map.forEachFeatureAtPixel(evt.pixel, (feature, layer)=> {
if(layer.getClassName()===StationLayer.layerName){
this.stationChartPopup.renderGraph(this.stationLayer.getTemperatureSeriesFromFeature(feature));
openPopup = true;
this.content.innerHTML = '<p>Station: ' + feature.get("id") + '</p>';
}else{
}
/* if(markerList.indexOf(feature)>=0){
console.log(feature);
} */
});
if(openPopup){
this.overlay.setPosition(coordinate);
}else{
this.closePopUp();
}
});
this.closer.onclick = () => {
this.closePopUp();
};
}
private closePopUp():void{
this.overlay.setPosition(undefined);
this.closer.blur();
}
private appendStationLayer(){
......
{
"compilerOptions": {
"target":"esnext",
"target":"es5",
"module":"esnext",
"moduleResolution": "node",
"strict": true,
"esModuleInterop": true,
"jsx": "preserve",
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"allowSyntheticDefaultImports": true,
"allowJs": true,
"noEmit": true,
"baseUrl": ".",
......@@ -17,5 +20,6 @@
"./*"
]
}
}
},
"exclude": ["node_modules"]
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment