Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

eggplantSword's avatar

Loading thousands of markers on map

How would you handle loading aprox. 12k markers on a vue3-leaflet map? I have my map component and everything works great but it's slow. I'm testing right now with only 1k and it's kinda slow I wouldn't want to use this with a lot less than 12k. The map images load after the markers do, but the more markers I create the longer the map images take to load.

This is my MapComponentDashboard.vue, just to show how I'm creating the markers. It's set with a prop and a v-for over said prop.

<l-map v-model:zoom="zoom" :zoom="zoom" :minZoom="4" :maxZoom="19" :zoomAnimation="true"
               :center="center" class="cursor-auto" :marker-zoom-animation="true">
    <l-tile-layer :url="url" :attribution="attribution"/>

    <l-layer-group layer-type="overlay" name="Markers">
        <l-marker :key="location.uuid" :lat-lng="[location.latitude, location.longitude]"
                          v-for="location in modelValue" :icon="dummyIcon">
            <l-popup>
                <ul class="w-48 grid grid-cols-1 gap-1 bg-white rounded-md -p-2">
                    <li class="font-semibold text-xs text-gray-600">Código: {{ location.code }}</li>
                    <li class="font-semibold text-base text-teal">{{ location.name }}</li>
                    <li v-if="location.business_name" class="text-sm text-gray-600">{{ location.business_name }}</li>

                    <div class="flex justify-center pt-2" v-if="$page.props.can_read">
                        <Link :href="route('sale-points.index', {id: location.id})">
                            <my-button>View</my-button>
                        </Link>
                    </div>
                </ul>
            </l-popup>

            <l-icon :icon-size="[8, 8]" :icon-anchor="[4, 4]">
                <div class="bg-red rounded-full w-full h-full"></div>
            </l-icon>

            <l-tooltip>{{location.name}}</l-tooltip>
        </l-marker>
    </l-layer-group>
</l-map>

I use it like this

<main class="w-full h-full flex-grow z-0">
    <map-component-dashboard v-model="$page.props.sale_points"></map-component-dashboard>
</main>

In my Controller

public function index(Request $request)
    {
        return Inertia::render('Dashboard', [
            'sale_points' => Inertia::lazy(fn() => SalePoint::select(['id', 'code', 'name', 'business_name', 'latitude', 'longitude'])
                ->filterDistribution($request)
                ->filterSquema($request)
                ->disableCache()
                ->get(),
        ]);
    }

What can I try to make this faster? Should I try to load these a couple hundred at a time? Any suggestions are greatly appreciated.

0 likes
5 replies
Tray2's avatar

I would probably chunk it, but getting 12000 records from the database, is pretty quick. I have a table with 100000 records and fetching 12000 of them took 0.016 seconds.

So make sure that you run all the filtering and sorting inside the database, and not on the php side.

eggplantSword's avatar

@Tray2 The filtering is being done in the above Controller code ->filterDistribution($request)->filterSquema($request) those scopes.

public function scopeFilterDistribution($query, $request) {
        $query->when($request->input('district_id'), function ($q, $district) {
            $q->where('district_id', $district);
        }, function ($query) use ($request) {
            $query->when($request->input('canton_id'), function ($query, $canton) {
                $query->whereHas('district', function ($query) use ($canton) {
                    return $query->where('canton_id', $canton);
                });
            }, function ($query) use ($request) {
                $query->when($request->input('province_id'), function ($query, $province) {
                    $query->whereHas('district.canton', function ($query) use ($province) {
                        return $query->where('province_id', $province);
                    });
                }, function ($query) use ($request) {
                    $query->when($request->input('country_id'), function ($query, $country) {
                        $query->whereHas('district.canton.province', function ($query) use ($country) {
                            return $query->where('country_id', $country);
                        });
                    });
                });
            });
        });
    }

    public function scopeFilterSquema($query, $request) {
        $query->when($request->input('format_id'), function ($query, $format) {
            $query->where('format_id', $format);
        }, function ($query) use ($request) {
            $query->when($request->input('chain_id'), function ($query, $chain) {
                $query->whereHas('format', function ($query) use ($chain) {
                    return $query->where('chain_id', $chain);
                });
            }, function ($query) use ($request) {
                $query->when($request->input('channel_id'), function ($query, $channel) {
                    $query->whereHas('format.chain', function ($query) use ($channel) {
                        return $query->where('channel_id', $channel);
                    });
                });
            });
        });
    }

I'm more worried about the Vue aspect of it, because you're right that getting 12k records is fast but the page takes like 5-8 seconds to fully load when I set all the markers on the map at once and it might even take longer, getting the 12k records and loading just the map without the markers is fast.

martinbean's avatar

@msslgomez Well the question would be, why are you trying to fetch and display so many markers in the first place? 12,000 is nuts. If you make a search on Google Maps, it doesn’t show you every possible result—the map would be far too busy to look at and make sense of.

Tray2's avatar

@msslgomez @martinbean is right that it is a bit bonkers to load that many at once, and that the map would be very busy.

I take it that you can use zoom in and out one the map, and if so, you can in zoom 100%, show a few well known markers, and then as the zoom in fetch the markers for the visible area.

eggplantSword's avatar

@tray2 @martinbean I agree that 12k markers is pretty insane, let me explain what I'm trying to do so you can see where I'm coming from. This system is a management hub for Sale Points nationwide (small country), these Sale Points (SP) are like supermarkets, chains like Walmart, licor stores, mini marts and more. There are around 12k total in the database currently but there could be more later on. The dashboard is supposed to be a big map of the country with the SP shown on the map, however these SP can be filtered in the map so even if I don't show the full 12k at first if they add all the filters, I would have to display them all.

@tray2

I take it that you can use zoom in and out one the map, and if so, you can in zoom 100%, show a few well known markers, and then as the zoom in fetch the markers for the visible area.

I think I'll attempt this approach, however what if in this case I don't know which are the most well-known. How many do you think is a good number of random SP to display on load?

Please or to participate in this conversation.