Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft UI version of location and google map interactive #14

Merged
merged 1 commit into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
<div class="w-full max-w-5xl mx-auto bg-white rounded-xl p-4 sm:flex sm:items-center sm:space-x-6 shadow-md hover:shadow-sm transition-shadow duration-300 mb-4 cursor-pointer">
<div class="w-full max-w-5xl mx-auto rounded-xl p-4 sm:flex sm:items-center sm:space-x-6 shadow-md hover:shadow-sm transition-shadow duration-300 mb-4 cursor-pointer" (click)="onSelectLocation()" [ngClass]="{'shadow-none bg-blue-500 text-white' : isSelected, 'bg-white': !isSelected}">
<img class="block mx-auto h-16 w-16 object-cover rounded-full sm:mx-0 sm:flex-shrink-0" [src]="location.image" alt="">
<div class="text-center space-y-2 sm:text-left">
<div class="space-y-0.5">
<p class="text-lg text-black font-semibold">
<p class="text-lg text-black font-semibold" [ngClass]="{'text-white' : isSelected, 'text-black': !isSelected}">
{{ location.name }}
</p>
<p class="text-gray-500 font-medium">
<p class="text-gray-500 text-sm text-slate-500 truncate" [ngClass]="{'text-white' : isSelected, 'text-gray-500': !isSelected}">
{{ location.address }}
</p>
<p class="text-gray-600 font-small">
<p class="text-gray-600 text-sm text-slate-500 truncate" [ngClass]="{'text-white' : isSelected, 'text-gray-600': !isSelected}">
Kategorija: {{ location.type }}
</p>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,29 @@
import { Component, Input } from '@angular/core';
import { NgClass } from '@angular/common';
import { Component, EventEmitter, Input, Output } from '@angular/core';

export interface Location {
id: number;
name: string;
address: string;
type: string;
image?: string;
coordinates: google.maps.LatLngLiteral
}

@Component({
selector: 'app-location-card',
standalone: true,
imports: [],
imports: [NgClass],
templateUrl: './location-card.component.html',
styleUrls: ['./location-card.component.scss'],
})
export class LocationCardComponent {
@Input() location: Location = {} as Location;
@Input() index: number | undefined;
@Input() isSelected: boolean = false; // Receives the selected state from the parent
@Output() locationSelected = new EventEmitter<number>(); // Emit event when card is clicked

onSelectLocation() {
this.locationSelected.emit(this.index); // Emit the event when the card is clicked
}
}
8 changes: 4 additions & 4 deletions frontend/src/app/pages/home/home.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,31 @@ <h2 class="text-4xl mb-8 font-semibold text-center uppercase">Lokacije</h2>
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-8 mt-7">
<!-- Location 1 -->
<div class="bg-white-100">
<img class="w-64 h-64 object-cover rounded-full mx-auto drop-shadow-xl" src="/assets/images/smet.jpg">
<img class="w-48 h-48 object-cover rounded-full mx-auto drop-shadow-xl" src="/assets/images/smet.jpg">
<div class="p-6">
<h3 class="text-lg font-medium mb-2 text-center uppercase">Konjički klub "Smet"</h3>
</div>
</div>

<!-- Location 2 -->
<div class="bg-white-100">
<img class="w-64 h-64 object-cover rounded-full mx-auto drop-shadow-xl" src="/assets/images/spomenik.jpg">
<img class="w-48 h-48 object-cover rounded-full mx-auto drop-shadow-xl" src="/assets/images/spomenik.jpg">
<div class="p-6">
<h3 class="text-lg font-medium mb-2 text-center uppercase">Spomen obilježje</h3>
</div>
</div>

<!-- Location 3 -->
<div class="bg-white-100">
<img class="w-64 h-64 object-cover rounded-full mx-auto drop-shadow-xl" src="/assets/images/restoran_960.jpg">
<img class="w-48 h-48 object-cover rounded-full mx-auto drop-shadow-xl" src="/assets/images/restoran_960.jpg">
<div class="p-6">
<h3 class="text-lg font-medium mb-2 text-center uppercase">Restoran 360</h3>
</div>
</div>

<!-- Location 4 -->
<div class="bg-white-100">
<img class="w-64 h-64 object-cover rounded-full mx-auto drop-shadow-xl" src="/assets/images/dom_saveza_izvidaca_i_radioamatera.jpg">
<img class="w-48 h-48 object-cover rounded-full mx-auto drop-shadow-xl" src="/assets/images/dom_saveza_izvidaca_i_radioamatera.jpg">
<div class="p-6">
<h3 class="text-lg font-medium mb-2 text-center uppercase">Dom Saveza Izviđača i Radioamatera</h3>
</div>
Expand Down
37 changes: 26 additions & 11 deletions frontend/src/app/pages/location/location.component.html
Original file line number Diff line number Diff line change
@@ -1,18 +1,33 @@
<main class="flex items-center justify-center bg-gray-100">
<div class="w-full lg:flex container">
<div class="lg:w-1/2 py-6 px-4">
<ng-container *ngFor="let locationItem of locations">
<app-location-card [location]="locationItem"></app-location-card>
<div class="lg:w-1/3 py-6 px-4">
<ng-container *ngFor="let locationItem of locations; let i = index">
<app-location-card
[location]="locationItem"
[index]="i"
[isSelected]="isLocationSelected(i)"
(locationSelected)="openInfoWindowFromCard(i)">
</app-location-card>
</ng-container>
</div>
<div class="lg:w-1/2 w-full">
<google-map
height="100vh"
width="100%"
[zoom]="zoom"
[center]="center"
[options]="options"
></google-map>
<div class="w-full py-6">
<google-map height="100vh" width="100%" [zoom]="zoom" [center]="center" [options]="options">
<map-marker
*ngFor="let marker of markers; let i = index"
[position]="marker.position"
[options]="getMarkerOptions(i)"
#markerRef="mapMarker"
(mapClick)="openInfoWindow(marker, markerRef, i)">
</map-marker>
<map-info-window #infoWindow>
<div class="marker-info shadow-md">
<img [src]="infoWindowContent.image" />
<div class="marker-details">
<h3 class="text-lg font-semibold text-center">{{ infoWindowContent.name }}</h3>
</div>
</div>
</map-info-window>
</google-map>
</div>
</div>
</main>
12 changes: 12 additions & 0 deletions frontend/src/app/pages/location/location.component.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.marker-info {
img {
max-width: 300px;
max-height: 200px;
min-height: 200px;
object-fit: cover;
width: 300px;
}
.marker-details {
padding: 10px;
}
}
109 changes: 89 additions & 20 deletions frontend/src/app/pages/location/location.component.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, QueryList, ViewChild, ViewChildren } from '@angular/core';
import { CommonModule } from '@angular/common';
import { LocationCardComponent } from 'src/app/components/location-card/location-card.component';
import { Location } from 'src/app/components/location-card/location-card.component';
import { GoogleMapsModule } from '@angular/google-maps';
import { GoogleMapsModule, MapMarker, MapInfoWindow } from '@angular/google-maps';

const DUMMY_LOCATIONS = [
{
Expand All @@ -11,51 +11,120 @@ const DUMMY_LOCATIONS = [
address: 'Smetovi bb',
type: 'Zooloski vrt',
image: '/assets/images/smet.jpg',
coordinates: { lat: 44.241592, lng: 17.969323 },
},
{
id: 2,
name: 'Restoran "960"',
address: 'Smetovi bb',
type: 'Restoran',
image:
'/assets/images/restoran_960.jpg',
image: '/assets/images/restoran_960.jpg',
coordinates: { lat: 44.242418, lng: 17.97361 },
},
];

interface Marker {
position: google.maps.LatLngLiteral;
title: string;
}

interface InfoWindowContent {
name: string;
image?: string;
}

interface Marker extends google.maps.MarkerOptions {
image?: string; // Add custom field for image URL
}

@Component({
selector: 'app-location',
standalone: true,
imports: [LocationCardComponent, CommonModule, GoogleMapsModule],
templateUrl: './location.component.html',
styleUrls: ['./location.component.scss']
styleUrls: ['./location.component.scss'],
})



export class LocationComponent implements OnInit {
zoom = 12;
@ViewChild(MapInfoWindow) infoWindow: MapInfoWindow | undefined;
@ViewChildren('markerRef') markerElements!: QueryList<MapMarker>;

center: google.maps.LatLngLiteral = {
lat: 44.241962,
lng: 17.969424
lng: 17.969424,
};
zoom = 12;
markers: Marker[] = [];
options: google.maps.MapOptions = {
mapTypeId: 'hybrid',
zoomControl: false,
scrollwheel: false,
zoomControl: true,
scrollwheel: true,
draggable: false,
fullscreenControl: false,
disableDoubleClickZoom: true,
maxZoom: 20,
minZoom: 16,
}
styles: [
{
featureType: 'poi', // Hides points of interest
stylers: [{ visibility: 'off' }],
},
{
featureType: 'transit', // Hides transit stations
stylers: [{ visibility: 'off' }],
},
{
featureType: 'business', // Hides businesses
stylers: [{ visibility: 'off' }],
},
],
};
locations: Location[] = DUMMY_LOCATIONS;
selectedLocationIndex!: number; // Tracks the selected location index
infoWindowContent: InfoWindowContent = {
name: '',
image: ''
};

ngOnInit() {
this.locations.forEach(location => {
this.markers.push(
{
position: location.coordinates,
title: location.name,
image: location.image
},
)
});
}

// Handle card click and open corresponding marker infoWindow
openInfoWindowFromCard(index: number) {
const markerRef = this.markerElements.get(index); // Get the marker reference by index
if (markerRef) {
this.center = this.markers[index].position; // Center map on the marker's position
this.selectedLocationIndex = index; // Set the selected location index
this.openInfoWindow(this.markers[index], markerRef, index);
}
}

ngOnInit() {}

zoomIn() {
if (this.zoom < 15) this.zoom++;
openInfoWindow(marker: Marker, markerRef: MapMarker, index: number) {
this.infoWindowContent = { name: marker.title, image: marker.image };
this.center = marker.position; // Center map on the marker's position
this.selectedLocationIndex = index; // Set the selected location index
this.infoWindow?.open(markerRef);
}

zoomOut() {
if (this.zoom > 8) this.zoom--;

isLocationSelected(index: number): boolean {
return this.selectedLocationIndex === index; // Check if current index is selected
}

getMarkerOptions(index: number): google.maps.MarkerOptions {
return {
position: this.markers[index].position,
icon: (index === this.selectedLocationIndex)
? 'http://maps.google.com/mapfiles/ms/icons/blue-dot.png'
: 'http://maps.google.com/mapfiles/ms/icons/red-dot.png',
title: this.markers[index].title,
};
}
}
13 changes: 13 additions & 0 deletions frontend/src/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,17 @@ button, .button {
.primary {
background-color: #fff;
color: #222;
}

/* Google maps styling */
.gm-style-iw-chr {
display: none;
}

.gm-style-iw-d {
overflow: hidden !important;
}

.gm-style-iw.gm-style-iw-c {
padding: 0px!important;
}
Loading