תוכנית השירות של מפות Google למפת חום ב-Android

הפלטפורמה: Android iOS

מפות חום שימושיות להצגת ההתפלגות והצפיפות של נקודות נתונים במפה.

מבוא

ספריית כלי העזר של Maps SDK ל-Androidכוללת כלי ליצירת מפת חום, שבעזרתו אפשר להוסיף מפת חום אחת או יותר למפת Google באפליקציה.

בסרטון הזה מוסבר איך להשתמש במפות חום כחלופה לסמנים, כשצריך להציג במפה מספר גדול של נקודות נתונים.

מפות צפיפות מאפשרות לצופים להבין בקלות את הפיזור והעוצמה היחסית של נקודות הנתונים במפה. במקום להציב סמן בכל מיקום, במפות חום משתמשים בצבע כדי לייצג את התפלגות הנתונים.

בדוגמה שלמטה, האזורים האדומים מייצגים ריכוז גבוה של תחנות משטרה בוויקטוריה, אוסטרליה.

מפה עם מפת חום שמציגה את המיקום של תחנות משטרה
מפת חום במפה

אם עדיין לא הגדרתם את ספריית כלי העזר של Maps SDK ל-Android, מומלץ לעיין במדריך ההגדרה לפני שתמשיכו לקרוא את שאר המאמר הזה.

הוספת מפת חום פשוטה

כדי להוסיף מפת חום למפה, צריך להשתמש במערך נתונים שכולל את הקואורדינטות של כל מיקום שמעניין אתכם. קודם יוצרים HeatmapTileProvider ומעבירים לו את האוסף של אובייקטים מסוג LatLng. לאחר מכן יוצרים TileOverlay חדש, מעבירים אליו את ספק המשבצות של מפת החום ומוסיפים את שכבת המשבצות למפה.

כלי השירות מספק את המחלקה HeatmapTileProvider, שמטמיעה את הממשק TileProvider כדי לספק את תמונות המשבצות למפת החום. ‫HeatmapTileProvider מקבל אוסף של אובייקטים מסוג LatLng (או אובייקטים מסוג WeightedLatLng, כפי שמתואר בהמשך). הכלי יוצר את תמונות המשבצות לרמות שונות של הגדלה, על סמך האפשרויות של הרדיוס, הגרדיאנט והאטימות שצוינו. אפשר לשנות את ערכי ברירת המחדל של האפשרויות האלה.

הסבר מפורט יותר על השלבים:

  1. משתמשים ב-HeatmapTileProvider.Builder() ומעבירים לו אוסף של אובייקטים מסוג LatLng כדי להוסיף HeatmapTileProvider חדש.
  2. יוצרים אובייקט חדש של TileOverlayOptions עם האפשרויות הרלוונטיות, כולל HeatmapTileProvider.
  3. מתקשרים אל GoogleMap.addTileOverlay() כדי להוסיף את שכבת העל למפה.

Kotlin

private fun addHeatMap() {
    var latLngs: List<LatLng?>? = null

    // Get the data: latitude/longitude positions of police stations.
    try {
        latLngs = readItems(R.raw.police_stations)
    } catch (e: JSONException) {
        Toast.makeText(context, "Problem reading list of locations.", Toast.LENGTH_LONG)
            .show()
    }

    // Create a heat map tile provider, passing it the latlngs of the police stations.
    val provider = HeatmapTileProvider.Builder()
        .data(latLngs)
        .build()

    // Add a tile overlay to the map, using the heat map tile provider.
    val overlay = map.addTileOverlay(TileOverlayOptions().tileProvider(provider))
}

@Throws(JSONException::class)
private fun readItems(@RawRes resource: Int): List<LatLng?> {
    val result: MutableList<LatLng?> = ArrayList()
    val inputStream = context.resources.openRawResource(resource)
    val json = Scanner(inputStream).useDelimiter("\\A").next()
    val array = JSONArray(json)
    for (i in 0 until array.length()) {
        val `object` = array.getJSONObject(i)
        val lat = `object`.getDouble("lat")
        val lng = `object`.getDouble("lng")
        result.add(LatLng(lat, lng))
    }
    return result
}

      

Java

private void addHeatMap() {
    List<LatLng> latLngs = null;

    // Get the data: latitude/longitude positions of police stations.
    try {
        latLngs = readItems(R.raw.police_stations);
    } catch (JSONException e) {
        Toast.makeText(context, "Problem reading list of locations.", Toast.LENGTH_LONG).show();
    }

    // Create a heat map tile provider, passing it the latlngs of the police stations.
    HeatmapTileProvider provider = new HeatmapTileProvider.Builder()
        .data(latLngs)
        .build();

    // Add a tile overlay to the map, using the heat map tile provider.
    TileOverlay overlay = map.addTileOverlay(new TileOverlayOptions().tileProvider(provider));
}

private List<LatLng> readItems(@RawRes int resource) throws JSONException {
    List<LatLng> result = new ArrayList<>();
    InputStream inputStream = context.getResources().openRawResource(resource);
    String json = new Scanner(inputStream).useDelimiter("\\A").next();
    JSONArray array = new JSONArray(json);
    for (int i = 0; i < array.length(); i++) {
        JSONObject object = array.getJSONObject(i);
        double lat = object.getDouble("lat");
        double lng = object.getDouble("lng");
        result.add(new LatLng(lat, lng));
    }
    return result;
}

      

בדוגמה הזו, הנתונים מאוחסנים בקובץ JSON,‏ police_stations.json. הנה קטע מהקובץ:

[
{"lat" : -37.1886, "lng" : 145.708 } ,
{"lat" : -37.8361, "lng" : 144.845 } ,
{"lat" : -38.4034, "lng" : 144.192 } ,
{"lat" : -38.7597, "lng" : 143.67 } ,
{"lat" : -36.9672, "lng" : 141.083 }
]

שימוש בנקודות משוקללות של קווי אורך ורוחב

כשיוצרים HeatmapTileProvider, אפשר להעביר לו אוסף של קואורדינטות משוקללות של קו רוחב/אורך. האפשרות הזו שימושית אם רוצים להמחיש את החשיבות של קבוצה מסוימת של מיקומים.

כדי להחיל משקל על מיקומים ספציפיים:

  1. יוצרים WeightedLatLng חדש לכל מיקום שנדרש לו משקל. מעבירים את LatLng ואת double שמייצג את עוצמת ההשפעה הנדרשת. העוצמה מציינת את החשיבות היחסית או הערך של המיקום הזה. ערך גבוה יותר יגרום לצבע בעוצמה גבוהה יותר בהדרגת הצבעים של מפת החום. כברירת מחדל, הצבע בעל העוצמה הגבוהה ביותר הוא אדום.
  2. ‫Call HeatmapTileProvider.Builder().weightedData(), במקום HeatmapTileProvider.Builder().data(), כדי ליצור את מפת החום.

התאמה אישית של מפת החום

אפשר להתאים אישית מספר מאפיינים של מפת החום. אפשר להגדיר את האפשרויות האלה בזמן היצירה באמצעות פונקציות Builder. לחלופין, אפשר לשנות אפשרות בכל שלב על ידי קריאה לפונקציית ה-setter הרלוונטית ב-HeatmapTileProvider, ואז לנקות את מטמון המשבצות של שכבת העל כדי שכל המשבצות יצוירו מחדש עם האפשרויות החדשות.

אלה האפשרויות הזמינות:

  1. רדיוס: הגודל של הטשטוש הגאוסיאני שמוחל על מפת החום, בפיקסלים. ברירת המחדל היא 20. הערך חייב להיות בין 10 ל-50. אפשר להשתמש ב-radius() של הכלי ליצירת מפות חום כדי להגדיר את הערך כשיוצרים את מפת החום, או לשנות את הערך מאוחר יותר באמצעות setRadius().
  2. מעבר צבעים: טווח של צבעים שמשמשים במפת החום ליצירת מפת הצבעים, מדרגת העוצמה הנמוכה ביותר ועד הגבוהה ביותר. הגרדיאנט נוצר באמצעות שני מערכים: מערך של מספרים שלמים שמכיל את הצבעים, ומערך של מספרים עשרוניים שמציין את נקודת ההתחלה של כל צבע. הנקודה מצוינת כאחוז מהעוצמה המקסימלית, ומבוטאת כשבר בין 0 ל-1. צריך לציין רק צבע אחד למעבר צבעים חד-צבעי, או לפחות שני צבעים למעבר צבעים רב-צבעי. מפת הצבעים נוצרת באמצעות אינטרפולציה בין הצבעים האלה. למעבר הצבעים שמוגדר כברירת מחדל יש שני צבעים. משתמשים ב-gradient() של הכלי ליצירת מפות חום כדי להגדיר את הערך כשיוצרים את מפת החום, או משנים את הערך מאוחר יותר באמצעות setGradient().
  3. אטימות: האטימות של שכבת מפת החום כולה, והיא נעה בין 0 ל-1. ערך ברירת המחדל הוא 0.7. אפשר להשתמש בכלי ליצירת מפות חום, opacity(), כדי להגדיר את הערך כשיוצרים את מפת החום, או לשנות את הערך מאוחר יותר באמצעות setOpacity().

לדוגמה, יוצרים Gradient כדי להגדיר את המעבר לפני שמוסיפים את מפת החום:

Kotlin

// Create the gradient.
val colors = intArrayOf(
    Color.rgb(102, 225, 0),  // green
    Color.rgb(255, 0, 0) // red
)
val startPoints = floatArrayOf(0.2f, 1f)
val gradient = Gradient(colors, startPoints)

// Create the tile provider.
val provider = HeatmapTileProvider.Builder()
    .data(latLngs)
    .gradient(gradient)
    .build()

// Add the tile overlay to the map.
val tileOverlay = map.addTileOverlay(
    TileOverlayOptions()
        .tileProvider(provider)
)

      

Java

// Create the gradient.
int[] colors = {
    Color.rgb(102, 225, 0), // green
    Color.rgb(255, 0, 0)    // red
};

float[] startPoints = {
    0.2f, 1f
};

Gradient gradient = new Gradient(colors, startPoints);

// Create the tile provider.
HeatmapTileProvider provider = new HeatmapTileProvider.Builder()
    .data(latLngs)
    .gradient(gradient)
    .build();

// Add the tile overlay to the map.
TileOverlay tileOverlay = map.addTileOverlay(new TileOverlayOptions().tileProvider(provider));

      

כדי לשנות את רמת השקיפות של מפת חום קיימת:

Kotlin

provider.setOpacity(0.7)
tileOverlay?.clearTileCache()

      

Java

provider.setOpacity(0.7);
tileOverlay.clearTileCache();

      

שינוי מערך הנתונים

כדי לשנות את מערך הנתונים שעליו מבוססת מפת החום, משתמשים ב-HeatmapTileProvider.setData(), ב-HeatmapTileProvider.setWeightedData() או ב-WeightedLatLng נקודות. הערה: אם רוצים להוסיף נקודות למפת החום או להסיר נקודות ממפת החום, צריך לעדכן את איסוף הנתונים ואז להשתמש ב-setData() או ב-setWeightedData().

Kotlin

val data: List<WeightedLatLng> = ArrayList()
provider.setWeightedData(data)
tileOverlay?.clearTileCache()

      

Java

List<WeightedLatLng> data = new ArrayList<>();
provider.setWeightedData(data);
tileOverlay.clearTileCache();

      

הסרת מפת חום

כדי להסיר את מפת החום, צריך להסיר את שכבת העל של המשבצת:

Kotlin

tileOverlay?.remove()

      

Java

tileOverlay.remove();

      

לצפייה באפליקציית ההדגמה

דוגמה נוספת להטמעה של מפת חום מופיעה ב-HeatmapsDemoActivity באפליקציית ההדגמה שמגיעה עם ספריית כלי העזר. במדריך ההגדרה מוסבר איך להפעיל את אפליקציית ההדגמה.