webtimo-de/ngx-apple-mapkit

Source code not pushed

Closed this issue · 25 comments

It seems you just committed the dist folder, is that by intention?

Actually, yes. So far, the source code is still in my private Repo.

Previously, this was a project of ihor-zinchenko/ngx-apple-maps. I only modified and brought it to Angular 16. He actually didn't publish his source code either. And well, I wrote it again from Compiled Angular Code in TypeScript Angular Code. And before I uploaded it to NPM, I simply installed my GitHub repo as an NPM package. It was just stupid because I didn't have any versions.
And I didn't think it was necessary to change that so far.

But why do you ask, do you need the code?

Alright, got it, thanks. No I don't need it, but was about to change a few thinks and thought about making a PR but without the source that wont be possible. Just replaced our Google Maps impl with yours, works very well. Just added two features to mine:

Zoomlevel

map.map._impl.zoomLevel = this.zoom

Custom HTML annotations

    this.map.map.addAnnotation(
      new window.mapkit.Annotation(
        new window.mapkit.Coordinate(annotation.latitude, annotation.longitude),
        function () {
          const div = document.createElement('div')
          div.innerHTML =
            annotation.contents ?? '<img src="/assets/pins/pin.svg" alt="" />'
          if (annotation.onClick) {
            div.addEventListener('click', annotation.onClick)
          }
          return div
        },
        annotation.options,
      ),
    )

Yes, okay, I would say that you would have to look directly at Apple. But I'll take a look at the whole thing because I know that I've done something like this before with the 'Custom HTML annotations'. I'll then write a code example for you here.

Regarding the Zoomlevel, there is a region in the settings parameter. There you can specify a center and a span. (I think that's not what you're looking for)

        this.settings = {
            isZoomEnabled: true,
            showsZoomControl: true,
            showsUserLocationControl: false,
            showsMapTypeControl: true,
            showsUserLocation: false,
            tracksUserLocation: false,
            isScrollEnabled: true,
            mapType: "standard",
            center: home, // Coordinate
            isRotationEnabled: true,
            region: {
                center: home, // Coordinate
                span: {
                    from: 0.025, // Here
                    to: 0.025 // Here
                }
            }
        };

The lower the span number, the closer it is.

I'll look at both cases again when the time comes. I think today or tomorrow.

So about the zoom, there's nothing like that at Apple, the only thing that works is what I showed you. You can also jump to Marker and then adjust the zoom there. Or areas, but there is no direct parameter for zoom.

I found something about the markers at Apple.
https://developer.apple.com/documentation/mapkitjs/annotation

But here is the code for it:

    onLoaded(e: MapKitLoaded) {
        const map = e.map;
        const people = [
            {
                title: "Juan Chavez",
                // @ts-ignore
                coordinate: new mapkit.Coordinate(37.3349, -122.0090201),
                role: "developer",
                building: "HQ"
            },
            {
                title: "Anne Johnson",
                // @ts-ignore
                coordinate: new mapkit.Coordinate(37.722319, -122.434979),
                role: "manager",
                building: "HQ"
            }
        ];


        const factory = (coordinate, options) => {
            const div = document.createElement("div"),
                name = options.title,           // "Juan Chavez"
                parts = name.split(' ');        // ["Chavez", "Juan"]
            div.textContent = parts[0].charAt(0) + parts[1].charAt(0);    // "JA"
            div.className = "circle-annotation";
            return div;
        };


        people.forEach((person) => {
            const options = {
                title: person.title,
                data: {role: person.role, building: person.building}
            };
            // @ts-ignore
            const annotation = new mapkit.Annotation(person.coordinate, factory, options);
            map.addAnnotation(annotation);
        });
    }
            <ngx-apple-mapkit id="map-apple"
                              (onLoaded)="onLoaded($event)"
                              *ngIf="!!options && !!settings"
                              [options]="options" [settings]="settings">
                <ngx-apple-mapkit-annotation
                        [options]="{subtitle: 'Timo Köhler', title: 'web-timo.de', glyphText: '🧑‍💻', selected: true}"
                        [latitude]="51.6815333"
                        [longitude]="7.8637212"
                ></ngx-apple-mapkit-annotation>
            </ngx-apple-mapkit>

I have also released an update with this in mind.

npm install ngx-apple-mapkit@latest

Please download this

I also have better typing with the update. To make it easier to find (:


At the same time, I have a question for you @muuvmuuv
During the update I also created the mapkit as a declare namespace. And then when I want to import that into my project, it gives me this message.

1. Variant

import {AppleMapsService, mapkit} from "ngx-apple-mapkit";

Error:

./src/app/pages/ngx-apple-mapkit/ngx-apple-mapkit/ngx-apple-mapkit.component.ts:169:22-39 - Error: export 'mapkit' (imported as 'mapkit') was not found in 'ngx-apple-mapkit' (possible exports: AppleMapkitAnnotationComponent, AppleMapkitComponent, AppleMapsGeocoderService, AppleMapsModule, AppleMapsSearchService, AppleMapsService)

./src/app/pages/ngx-apple-mapkit/ngx-apple-mapkit/ngx-apple-mapkit.component.ts:175:22-39 - Error: export 'mapkit' (imported as 'mapkit') was not found in 'ngx-apple-mapkit' (possible exports: AppleMapkitAnnotationComponent, AppleMapkitComponent, AppleMapsGeocoderService, AppleMapsModule, AppleMapsSearchService, AppleMapsService)

./src/app/pages/ngx-apple-mapkit/ngx-apple-mapkit/ngx-apple-mapkit.component.ts:197:29-46 - Error: export 'mapkit' (imported as 'mapkit') was not found in 'ngx-apple-mapkit' (possible exports: AppleMapkitAnnotationComponent, AppleMapkitComponent, AppleMapsGeocoderService, AppleMapsModule, AppleMapsSearchService, AppleMapsService)

2. Variant

import {AppleMapsService} from "ngx-apple-mapkit";
import {mapkit} from "ngx-apple-mapkit/lib/mapkit";

Error:

./src/app/pages/ngx-apple-mapkit/ngx-apple-mapkit/ngx-apple-mapkit.component.ts:5:0-53 - Error: Module not found: Error: Package path ./lib/mapkit is not exported from package C:\xampp\htdocs\Webseiten\projects.web-timo.de\node_modules\ngx-apple-mapkit (see exports field in C:\xampp\htdocs\Webseiten\projects.web-timo.de\node_modules\ngx-apple-mapkit\package.json)

Export

public-api.ts

/*
 * Public API Surface of ngx-apple-mapkit
 */

// <reference path="./lib/declarations.ts" />
// <reference path="./lib/mapkit.ts" />
export * from './lib/apple-maps.service';
export * from './lib/services/geocoder/apple-maps-geocoder.service';
export * from './lib/services/search/apple-maps-search.service';
export * from './lib/apple-mapkit.component';
export * from './lib/components/apple-mapkit-annotation/apple-mapkit-annotation.component';
export * from './lib/apple-maps.module';
export * from './lib/mapkit';

mapkit.ts

grafik

Do you perhaps know a solution or how to fix this?

I tested the zoom with what I shared with you and it works ^^ so its a hack on my side but good to know this isn't official. Will mark it on my side.

Yes, I am aware of glyphText but you have no API for event listeners on markers so I created my own.

Will have a look at that typing issue the next days, maybe because you export a namespace which isnt importable like and interface or its the reference which imports it twice.

I tested the zoom with what I shared with you and it works ^^ so its a hack on my side but good to know this isn't official. Will mark it on my side.

Oh okay, I tried it too, it actually works. I also just added this to the README.

Yes, I am aware of glyphText but you have no API for event listeners on markers so I created my

But I wrote it in there.

    onLoaded(e: MapKitLoaded) {
        const map = e.map;
        const people = [
            {
                title: "Juan Chavez",
                // @ts-ignore
                coordinate: new mapkit.Coordinate(37.3349, -122.0090201),
                role: "developer",
                building: "HQ"
            },
            {
                title: "Anne Johnson",
                // @ts-ignore
                coordinate: new mapkit.Coordinate(37.722319, -122.434979),
                role: "manager",
                building: "HQ"
            }
        ];


        const factory = (coordinate, options) => {
            const div = document.createElement("div"),
                name = options.title,           // "Juan Chavez"
                parts = name.split(' ');        // ["Chavez", "Juan"]
            div.textContent = parts[0].charAt(0) + parts[1].charAt(0);    // "JA"
            div.className = "circle-annotation";
            return div;
        };


        people.forEach((person) => {
            const options = {
                title: person.title,
                data: {role: person.role, building: person.building}
            };
            // @ts-ignore
            const annotation = new mapkit.Annotation(person.coordinate, factory, options);
            map.addAnnotation(annotation);
        });
    }
            <ngx-apple-mapkit id="map-apple"
                              (onLoaded)="onLoaded($event)"
                              *ngIf="!!options && !!settings"
                              [options]="options" [settings]="settings">
            </ngx-apple-mapkit>

You find the Doc here:
https://developer.apple.com/documentation/mapkitjs/annotation

And I have an event listener.

Please take a look at the Apple documentation. I use you too. Because I can't maping everything, either.

https://developer.apple.com/documentation/mapkitjs

Will have a look at that typing issue the next days, maybe because you export a namespace which isnt importable like and interface or its the reference which imports it twice.

That would be nice, because I don't know what to do, and StackOverflow and Google etc don't help somehow.

Oh yes, sorry, I forgot that my GitHub Chrome extension gives code-blocks a max-height... forgot to scroll down :D

Can you test with tripple slash because double is the wrong syntax:

/// <reference path="./lib/mapkit.ts" />

I also think it is wrongly imported and not export in the final fesm bundle.

Do you think it would be possible to add (click) listener to "ngx-apple-mapkit-annotation" or maybe that I can add a factory function. At the moment I have the issue that when I want to add an annotation the map is not ready yet. I cannot wait for mapLoaded because I do API requests on every page visit.

Okay, i try it

Can you test with tripple slash because double is the wrong syntax:

/// <reference path="./lib/mapkit.ts" />

I also think it is wrongly imported and not export in the final fesm bundle.

About the import, I did it. I was just now in my concentration mode. That's why I write now. I just turned the whole thing around.

Before:

272944961-0d7cb53a-d188-4b87-bea2-1b38a32fdb47

After:

grafik

This actually worked (:

Do you think it would be possible to add (click) listener to "ngx-apple-mapkit-annotation" or maybe that I can add a factory function. At the moment I have the issue that when I want to add an annotation the map is not ready yet. I cannot wait for mapLoaded because I do API requests on every page visit.

So you want a click event? So when he clicks on the marker you get that via the event emitter?

Great!

Something like that, but ideally would be an option parameter with a callback function. So when multiple annotations are created, I can directly set the callback function in a loop. For example like that (my own version).

private async renderActivities(activities: FeedActivity[]) {
  this.annotations = activities
    .filter((a) => a.place)
    .map((activity) => ({
      id: activity.id,
      latitude: activity.place!.latitude,
      longitude: activity.place!.longitude,
      contents: `<img src="/assets/pins/${activity.category.alias}.svg" alt="" />`,
      onClick: () => this.displayActivity(activity.id),
      options: {
        accessibilityLabel: activity.title,
        draggable: false,
      },
    }))
}

Great!

Something like that, but ideally would be an option parameter with a callback function. So when multiple annotations are created, I can directly set the callback function in a loop. For example like that (my own version).

private async renderActivities(activities: FeedActivity[]) {
  this.annotations = activities
    .filter((a) => a.place)
    .map((activity) => ({
      id: activity.id,
      latitude: activity.place!.latitude,
      longitude: activity.place!.longitude,
      contents: `<img src="/assets/pins/${activity.category.alias}.svg" alt="" />`,
      onClick: () => this.displayActivity(activity.id),
      options: {
        accessibilityLabel: activity.title,
        draggable: false,
      },
    }))
}

I'll try to do it that way.

So do you want to pass the annotations as a variable in the <ngx-apple-mapkit...>?

No I think something like a basic click event emitter is enough, I guess I can pass it as a parameter but whatever you prefer.

<ngx-apple-mapkit-annotation
                        [options]="{subtitle: 'Timo Köhler', title: 'web-timo.de', glyphText: '🧑‍💻', selected: true}"
(click)="annotation.onClick($event)"
                        [latitude]="51.6815333"
                        [longitude]="7.8637212"
                ></ngx-apple-mapkit-annotation>

No I think something like a basic click event emitter is enough, I guess I can pass it as a parameter but whatever you prefer.

<ngx-apple-mapkit-annotation
                        [options]="{subtitle: 'Timo Köhler', title: 'web-timo.de', glyphText: '🧑‍💻', selected: true}"
(click)="annotation.onClick($event)"
                        [latitude]="51.6815333"
                        [longitude]="7.8637212"
                ></ngx-apple-mapkit-annotation>

I've finished it, but I won't upload it until tomorrow. I want to rewrite the README.md.

I just uploaded it. (:

npm install ngx-apple-mapkit@latest

You can find out more here in the new README: Annotations (Markers)

Oh, great! I love that; onSelect/Deselect is exactly what I need! Unfortunately, the select custom marker is a bit weird. Would be better to have both, marker and select marker (maybe as slots) or just the marker. But anyway, thank you!

Oh, great! I love that; onSelect/Deselect is exactly what I need! Unfortunately, the select custom marker is a bit weird. Would be better to have both, marker and select marker (maybe as slots) or just the marker. But anyway, thank you!

Supi

I will also be working on improving the custom markers these days. Just as I want to typed other services.

Do you need anything else?

Right now, no. Just something I noticed. We have a very large map with around 20 markers rendered. I noticed that the service workers or some other process it freezing/killing the webpage after some time so chrome will kill the process and show an eval error. Any idea why that happens?

Right now, no. Just something I noticed. We have a very large map with around 20 markers rendered. I noticed that the service workers or some other process it freezing/killing the webpage after some time so chrome will kill the process and show an eval error. Any idea why that happens?

I think it's because he's constantly trying to render again. Please use this function: trackby
https://stackoverflow.com/questions/42108217/how-to-use-trackby-with-ngfor

Because I have Maps, more than 200 markers are displayed, and he does that without any problems.

Already using it.. no change

Can I maybe see what you're doing? I find it difficult to help you further.

Maybe try going directly instead of the ngx-apple-mapkit-annotation. So you get the mapkit object back with the ngx-apple-mapkit onLoaded(). There you can e.g.

onLoaded(e: MapKitLoaded) {
    const map: MapKit.Map = e.map;
    this.map = e;
}

Get the Mapkit object and then create the markers directly via it.
Take a look at the Apple documentation here: https://developer.apple.com/documentation/mapkitjs/markerannotation
You then get the select and deselect from the MarkerAnnotation to the addEventListener. Like here for example

annotation.addEventListener("select", (event) => {
    this.onSelect.emit(event.target);
});
annotation.addEventListener("deselect", (event) => {
    this.onDeselect.emit(event.target);
});

This is a bit older code, but it works. That's kind of how I did it.

private searchMap(data: MapKitSearchResponse.RootObject) {
    if (!data) {
        return;
    }
    if (data.places.length > 1 || (data.places.length > 0 && !this.selected.getValue()?.value)) {
        this.map.setRegionAnimated(data.boundingRegion.center, {
            from: data.boundingRegion.span.latitudeDelta,
            to: data.boundingRegion.span.longitudeDelta
        }, true);
    }
    // @ts-ignore
    const markerList: mapkit.MarkerAnnotation[] = [];
    data.places.forEach(value => {
        // @ts-ignore
        const marker = new mapkit.MarkerAnnotation(new mapkit.Coordinate(value.coordinate.latitude, value.coordinate.longitude),
            {
                title: value.name,
                subtitle: value.formattedAddress,
                selected: false
            }
        );
        const name = value.name;
        const address = value.formattedAddress;
        const coordinate = {
            latitude: value.coordinate.latitude,
            longitude: value.coordinate.longitude
        };
        this.results = this.results.filter(x => x.id !== value.muid);
        this.results.push({
            name: name,
            address: address,
            coordinate: coordinate,
            pointOfInterestCategory: <any>value.pointOfInterestCategory,
            appleMapsUrl: value._wpURL,
            telephone: value.telephone,
            urls: value.urls,
            id: value.muid
        });
        markerList.push(marker);
    });
    if (markerList.length > 0) {
        this.map.showItems(markerList); // <-- this.map.map.addAnnotations(markerList);
    }
}

This one still uses the old ngx-apple-maps

I have used the services here to search for addresses or If you look for a doctor, you will then see the results on a list and on the MapKit map.

Ok, so it seems to be just an issue while in dev mode when Angular refreshes the page before the worker has anything todo so it hangs. I will open a new issues if this is going to be an issue on production.

Okay, now I know. I will then close the Issue.

Just create a new Issue if the error continues to appear 😊