Add trip display to departures
This commit is contained in:
parent
1bdea1926d
commit
c00e038fba
@ -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']"/>
|
||||
|
@ -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>
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
.stop__name {
|
||||
flex: 1 0;
|
||||
line-height: 1.2;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.stop__variant {
|
||||
|
66
resources/styles/_trigonometry.scss
Normal file
66
resources/styles/_trigonometry.scss
Normal 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);
|
||||
}
|
97
resources/styles/_trip.scss
Normal file
97
resources/styles/_trip.scss
Normal 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;
|
||||
}
|
||||
}
|
@ -51,6 +51,7 @@ $grid-gutter-width: $spacer * 2;
|
||||
@import "animations";
|
||||
@import "form";
|
||||
@import "fabourites";
|
||||
@import "trip";
|
||||
|
||||
body {
|
||||
min-height: 100vh;
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
3
resources/ts/model/identity.ts
Normal file
3
resources/ts/model/identity.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export type Identity = {
|
||||
id: string;
|
||||
}
|
@ -2,3 +2,4 @@ export * from './stop'
|
||||
export * from './departure'
|
||||
export * from './line'
|
||||
export * from './error'
|
||||
export * from './identity'
|
||||
|
@ -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))
|
||||
}
|
@ -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(),
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user