Skip to content
Snippets Groups Projects
Commit fd31d134 authored by Peter Morstein's avatar Peter Morstein
Browse files

add temperature popup chart

parent b5df86ac
No related branches found
No related tags found
No related merge requests found
import Vue from 'vue';
import App from './App.vue';
import vuetify from './src/plugins/vuetify'
import 'regenerator-runtime';
//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 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,84 @@
<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';
import { component } from 'vue/types/umd';
@Component({name : 'WeatherMap'})
@Component({components:{StationChartPopup})
export default class WeatherMap extends Vue{
@Ref('weathermap') readonly targetElement!: HTMLElement;
......@@ -32,7 +87,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 +116,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