简体   繁体   中英

Can I improve the rendering of thousands of elements using JavaScript jQuery?

I am developing an application based on the Google Maps APIs: basically I have the postal codes of my country and I need to show them.

Here is a video which shows my current implementation -> https://vid.me/S6PL

Postal codes on the map are created thanks to the google.maps.OverlayView class which I extend and create a custom PostalCodeOverlay (which is represented by the circles). Its draw method is the following:

PostalCodeOverlay.prototype.draw = function() {

        var overlayProjection = this.getProjection();
        // Handle some positioning stuff here with some properties created before during construction
        var center = overlayProjection.fromLatLngToDivPixel(new google.maps.LatLng(this.centerLat, this.centerLng));
        var div = this.postalCodeOverlayDiv;
        div.style.position = 'absolute';
        div.style.left = (center.x - (width/2)) + 'px';
        div.style.top = (center.y - (height/2)) + 'px';
        div.style["-moz-border-radius"] = "50%";
        div.style["-webkit-border-radius"] = "50%";
        div.style["border-radius"] = "50%";
        // As I show it the first time with an animation and
        // the APIs call this method several times (e.g. when
        // the zoom level of the map changes), I have a custom
        // boolean property that tells me whether it's the first
        // time or not
        if (!this.justCreated) {        
            div.style.width = width + "px";
            div.style.height = height + "px";
        }
        else {
            this.justCreated = false;
            var $postalCodeOverlayDiv = $(div); // here I get a jQuery reference to the div which represents the overlay (the circle).
            $postalCodeOverlayDiv.css({
                "width": "0",
                "height": "0",
                "opacity": "0"
            });
            // Animate it a bit so that it looks nicer when it
            // is drawn the first time.
            $postalCodeOverlayDiv.animate({
                "opacity": "1",
                "width": width + "px",
                "height": height + "px"
            }, 500);

        }
};

Now, as you can see from the video, the circles are created smoothly when the zoom level is higher, cause the density of postal codes per viewport bounds is lower.

But, when I start to zoom out, you can see that these nice effects are lost, as there are more postal codes per viewport bounds now (the area became wider).

I fetch the postal codes from a database through AJAX (I cache them thanks to the Google Geocoding API locally on my DB). The query which fetches them when the bounds are changed (I use map.addListener('bounds_changed', function() {...}) for that) is fast and returns as soon as a request is made. The returned JSON contains all the postal codes within the certain bounds searched, computed as the user moves within the map (as you can see from the video). I then iterate over this JSON and for each entry (which represents the postal code), I create a new PostalCodeOverlay(...params...) with the relative information.

The problem as you already understand is the rendering: when it comes to render thousands of elements the JavaScript engine lacks a bit and the map hangs.

I can post the code but I don't think it's needed here, I think it's enough to show you the video and the overlay I use (anyway, if something wasn't clear, please, tell me, I will update).

Which is the best way to address such problems? Is there a way to tell JavaScript/jQuery to handle the animations more smoothly when the underlying dataset is bigger? Or maybe there are some Google Maps features I am unaware of and I can leverage them in the overlay I have created?

Anyway, some advice will be appreciated.

Thanks for the attention.

Google offers this document on Too Many Markers for rendering suggestions. There are a number of options to consider there.

You want also want to get rid of the jQuery animation if there are hundreds of elements being drawn in the view. jQuery animations involve thousands of drawing cycles on timers. Multiply that by hundreds or thousands of elements and it's more than a CPU can effectively keep up with. You could also experiment with using CSS animations instead of jQuery animations which have a possibility of being more efficient.

So, perhaps if the zoom level if past some threshold (thus making it likely that lost of postal codes are in the view), then skip the animation and just set the CSS property directly.

Beyond that you could look into a more efficient way to draw your postal codes by perhaps removing the border-radius or simplifying some other CSS styles (you don't show everything involved in displaying that div so we can't make more specific recommendations). Again, you could do this only when zoomed out beyond some threshold.

And, for situations where you're zoomed out a lot, you may want to skip rendering of heavily overlapped codes since they are all so small and so close together that they don't offer a whole lot of value anyway. The challenge here is to figure out how to do that while still saving overall CPU. You could only show one postal code in a given screen segment or show no postal codes when the zoom out is beyond some threshold.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM