Add trip display to departures

This commit is contained in:
Kacper Donat 2020-01-23 19:27:08 +01:00
parent 1bdea1926d
commit c00e038fba
13 changed files with 207 additions and 7 deletions

View File

@ -1,6 +1,6 @@
<div class="departures" v-responsive>
<ul class="departures__list list-underlined">
<departure :departure="departure" :key="departure.id" v-for="departure in departures"/>
<departure :departure="departure" :key="departure.key" v-for="departure in departures"/>
</ul>
<div class="alert alert-info" v-if="stops.length === 0">
<fa :icon="['fal', 'info-circle']"/>

View File

@ -34,5 +34,18 @@
</div>
</div>
<fold :visible="showTrip">
<div v-if="trip != null" class="trip" :class="[ `trip--${departure.line.type}` ]">
<ol class="trip__stops">
<li v-for="stop in trip.schedule" class="trip-stop">
<div class="trip-stop__marker"/>
<div class="trip-stop__description">
<stop :stop="stop.stop"/>
</div>
</li>
</ol>
</div>
<div v-else class="text-center">
<fa icon="spinner-third" pulse></fa>
</div>
</fold>
</li>

View File

@ -6,7 +6,7 @@
.stop__name {
flex: 1 0;
line-height: 1.2;
line-height: 1.1;
}
.stop__variant {

View File

@ -0,0 +1,66 @@
///////////////////////////////////////////////////////////
// Plain SASS Trigonometry Algorithm in Taylor Expansion //
// //
// Based on //
// http://japborst.net/posts/sass-sines-and-cosines //
///////////////////////////////////////////////////////////
$pi: 3.14159265359;
$_precision: 5;
@function pow($base, $exp) {
$value: $base;
@if $exp > 1 {
@for $i from 2 through $exp {
$value: $value * $base;
}
}
@if $exp < 1{
@for $i from 0 through -$exp {
$value: $value / $base;
}
}
@return $value;
}
@function fact($num) {
$fact: 1;
@if $num > 0{
@for $i from 1 through $num {
$fact: $fact * $i;
}
}
@return $fact;
}
@function _to_unitless_rad($angle) {
@if unit($angle) == "deg" {
$angle: $angle / 180deg * $pi;
}
@if unit($angle) == "rad" {
$angle: $angle / 1rad;
}
@return $angle;
}
@function sin($angle){
$a: _to_unitless_rad($angle);
$sin: $a;
@for $n from 1 through $_precision {
$sin: $sin + (pow(-1, $n) / fact(2 * $n + 1) ) * pow($a, (2 * $n + 1));
}
@return $sin;
}
@function cos($angle){
$a: _to_unitless_rad($angle);
$cos: 1;
@for $n from 1 through $_precision {
$cos: $cos + ( pow(-1,$n) / fact(2*$n) ) * pow($a,2*$n);
}
@return $cos;
}
@function tan($angle){
@return sin($angle) / cos($angle);
}

View File

@ -0,0 +1,97 @@
@import "trigonometry";
$description-rotation: 60deg;
$description-width: 250px;
$trip-stop-marker-size: .9rem;
$trip-stop-line-width: .2rem;
.trip {
display: flex;
justify-content: center;
}
.trip__stops {
padding-top: sin($description-rotation) * $description-width;
padding-right: cos($description-rotation) * $description-width;
padding-left: 0;
display: flex;
list-style: none;
overflow-x: auto;
}
.trip-stop {
width: 2.5rem;
position: relative;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
}
.trip-stop:first-child {
.trip-stop__marker::before {
content: none;
}
}
.trip-stop:last-child {
.trip-stop__marker::after {
content: none;
}
}
.trip-stop__marker {
width: $trip-stop-marker-size;
height: $trip-stop-marker-size;
border: $dark $trip-stop-line-width solid;
border-radius: 100%;
background: white;
margin: .75rem 0;
&::before, &::after {
content: "";
display: block;
height: $trip-stop-line-width;
background: $dark;
width: 50%;
position: absolute;
top: 50%;
transform: translateY(-50%);
z-index: -1;
}
&::after {
right: 0;
}
&::before {
left: 0;
}
}
@each $type, $color in $line-types {
.trip--#{$type} {
.trip-stop__marker {
border-color: $color;
&::before, &::after {
background: $color;
}
}
}
}
.trip-stop__description {
display: flex;
transform: rotate(-$description-rotation) translateX(.75rem);
transform-origin: 0 50%;
max-width: $description-width;
position: absolute;
left: 50%;
top: 0;
.stop {
width: max-content;
}
}

View File

@ -51,6 +51,7 @@ $grid-gutter-width: $spacer * 2;
@import "animations";
@import "form";
@import "fabourites";
@import "trip";
body {
min-height: 100vh;

View File

@ -3,6 +3,8 @@ import { Departure, Stop } from "../model";
import { Component, Prop, Watch } from "vue-property-decorator";
import { namespace } from 'vuex-class';
import store from '../store'
import { Trip } from "../model/trip";
import urls from "../urls";
const { State } = namespace('departures');
@ -19,6 +21,7 @@ export class DepartureComponent extends Vue {
@Prop(Object) departure: Departure;
showTrip: boolean = false;
trip: Trip = null;
get timeDiffers() {
const departure = this.departure;
@ -29,6 +32,19 @@ export class DepartureComponent extends Vue {
get time() {
return this.departure.estimated || this.departure.scheduled;
}
@Watch('showTrip')
async downloadTrips() {
if (this.showTrip != true || this.trip != null) {
return;
}
const response = await fetch(urls.prepare(urls.trip, { id: this.departure.trip.id }));
if (response.ok) {
this.trip = await response.json();
}
}
}
Vue.component('Departures', DeparturesComponent);

View File

@ -1,9 +1,10 @@
import { Stop } from "./stop";
import { Line } from "./line";
import { Moment } from "moment";
import { Identity } from "./identity";
export interface Departure {
id: string;
key: string;
display: string;
estimated: Moment;
scheduled?: Moment;
@ -12,6 +13,7 @@ export interface Departure {
delay: number;
vehicle?: Vehicle;
trip?: Identity;
}
export interface Vehicle {

View File

@ -0,0 +1,3 @@
export type Identity = {
id: string;
}

View File

@ -1,4 +1,5 @@
export * from './stop'
export * from './departure'
export * from './line'
export * from './error'
export * from './error'
export * from './identity'

View File

@ -56,5 +56,6 @@ export default {
get: `${base}/stops/{id}`,
tracks: `${base}/stops/{id}/tracks`
},
trip: `${base}/trips/{id}`,
prepare: (url: string, params: UrlParams = { }) => prepare(url, Object.assign({}, { provider: window['data'].provider }, params))
}
}

View File

@ -60,7 +60,7 @@ class GenericScheduleRepository extends DatabaseRepository implements ScheduleRe
$last = $entity->getTrip()->getTrack()->getStopsInTrack()->last()->getStop();
return Departure::createFromArray([
'id' => sprintf('%s::%s', $entity->getTrip()->getId(), $entity->getDeparture()->format('H:i')),
'key' => sprintf('%s::%s', $this->id->of($entity->getTrip()), $entity->getDeparture()->format('H:i')),
'scheduled' => $entity->getDeparture(),
'stop' => $stop,
'display' => $last->getName(),

View File

@ -70,7 +70,7 @@ class ZtmGdanskDepartureRepository implements DepartureRepository
$estimated = (clone $scheduled)->addSeconds($delay['delayInSeconds']);
return Departure::createFromArray([
'id' => sprintf('%s::%s', $delay['routeId'], $scheduled->format('H:i')),
'key' => sprintf('%s::%s', $delay['routeId'], $scheduled->format('H:i')),
'scheduled' => $scheduled,
'estimated' => $estimated,
'stop' => $stop,