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; | ||||
| } | ||||
| @ -1,4 +1,5 @@ | ||||
| export * from './stop' | ||||
| export * from './departure' | ||||
| export * from './line' | ||||
| export * from './error' | ||||
| 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