Google 地图 API - 如何获取渐变中使用的最大强度值?

GoogleMaps API - How to get the maxIntensity value used in the gradient?

我想达到的目标

我正在尝试为我的热图的梯度建立图例 - 我使用 GoogleMaps API 成功创建 - 我唯一缺少的是梯度(即在热图上显示最高强度的值)。

我在这个主题上找到了一个很好的主题,它总结并完美地说明了我想要实现的目标,但遗憾的是我感兴趣的部分不起作用:HowTo create legend for google Heatmap?

我试过的

我尝试了几件事(几乎所有我能做的事),包括:

问题

所以现在我几乎没有解决方案:也许这里有人知道计算 maxIntensity 的神圣公式,或者比我更了解原始 API 来提取 maxIntensity 值?

什么我"found"

在使用控制台深入研究时,我 认为 我设法隔离了 Google 的 API 参与该过程的部分。它们有点重,但我不能做得更好。

这个显然有一个 属性 标识为 "maxIntensity":

google.maps.__gjsload__('visualization_impl', function (_) {
'use strict';
var i6 = function (a) {
        for (var b = Array(a), c = 0; c < a; ++c) b[c] = 0;
        for (var c = Array(a), d = 0; d < a; ++d) c[d] = b.concat();
        return c
    },
    j6 = function (a) {
        if (!a || !a.getLength()) return 1;
        var b = new _.Xd;
        a.forEach(function (a) {
            a && b.extend(a.location || a)
        });
        var c = b.f.f,
            d = b.b.b,
            e = Math.max(b.f.b - c, b.b.f - d);
        if (1E-9 > e) {
            var f = 0;
            a.forEach(function (a) {
                a instanceof _.E ? ++f : f += a.weight
            });
            return Math.max(1, f)
        }
        var g = 800 / e,
            h = i6(800),
            l = 1;
        a.forEach(function (a) {
            if (a) {
                var b = a.location || a;
                a = a.weight || 1;
                b = new _.I(Math.max(0, Math.min(799,
                    Math.floor((b.lat() - c) * g))), Math.max(0, Math.min(799, Math.floor((b.lng() - d) * g))));
                h[b.x][b.y] += a;
                l = Math.max(l, h[b.x][b.y])
            }
        });
        return l
    },
    l6 = function (a, b) {
        var c = [],
            d = [],
            e = 1E3 / (a.length - 1);
        _.v(a, function (a, b) {
            c.push(b * e);
            d.push(_.gJ(a))
        });
        a = Array(1001);
        for (var f = 0, g = 0; 1001 > g; ++g) g > c[f + 1] && ++f, a[g] = f < c.length - 1 ? k6(e * f, g, e * (f + 1), d[f], d[f + 1]) : d[d.length - 1], a[g].alpha *= b, a[g].alpha = _.Za(Math.floor(255 * a[g].alpha), 0, 255);
        return a
    },
    k6 = function (a, b, c, d, e) {
        if (a == c) return d;
        a = (b - a) / (c - a);
        return new _.dJ(Math.floor((e.j -
            d.j) * a + d.j), Math.floor((e.f - d.f) * a + d.f), Math.floor((e.b - d.b) * a + d.b), (e.alpha - d.alpha) * a + d.alpha)
    },
    n6 = function (a, b, c) {
        if (!m6) {
            for (var d = Array(256), e = 0; 256 > e; ++e) {
                for (var f = e, g = 0; 8 > g; ++g) f = f & 1 ? (3988292384 ^ f >>> 1) >>> 0 : f >>> 1;
                d[e] = f
            }
            m6 = d
        }
        d = 4294967295;
        e = b;
        for (b += c; e < b; ++e) d = (m6[(d ^ a[e]) & 255] ^ d >>> 8) >>> 0;
        return (d ^ 4294967295) >>> 0
    },
    p6 = function (a) {
        this.f = a.createElement("div");
        this.b = new o6(this)
    },
    o6 = _.oa("b"),
    q6 = function (a, b) {
        this.m = a;
        this.b = 1;
        this.f = [];
        this.j = b
    },
    r6 = function (a, b, c) {
        _.Rl(b.V, "");
        var d = b.ownerDocument,
            e, f, g, h;
        if (_.Gz()) e = g = d.createElement("canvas"), _.$l(e), f = e.getContext("2d"), h = 1 < a.b;
        else if (1 == _.W.type && _.Vk(_.W.version, 8)) e = new p6(d), f = e.b, g = e.getDiv(), h = !1;
        else return;
        e.width = e.height = 256;
        b.V.appendChild(g);
        e = a.get("projection");
        g = a.get("radius");
        g = Math.round(g / a.b) * a.b;
        var l = 1 << b.zoom,
            n = b.ac,
            q = (256 + 2 * g) / a.b;
        b = i6(q);
        for (var r in n)
            for (var u = n[r], x = e.fromLatLngToPoint(new _.E(u.K, u.L, !0)), A = e.fromLatLngToPoint(new _.E(u.O, u.P, !0)), x = new _.I(Math.min(x.x, A.x), Math.min(x.y, A.y)), x = new _.I(x.x +
                    g / l, x.y + g / l), u = a.m.search(u), A = 0, C = u.length; A < C; ++A) {
                var D = u[A],
                    H = e.fromLatLngToPoint(new _.E(D.ea.x, D.ea.y)),
                    K = Math.floor((Math.floor((H.y - x.y) * l) + g) / a.b),
                    H = Math.floor((Math.floor((H.x - x.x) * l) + g) / a.b);
                0 <= K && K < q && 0 <= H && H < q && (b[K][H] += D.weight)
            }
        r = a.f;
        e = Math.floor(r.length / 2);
        g = b.length;
        l = g - e;
        n = i6(g);
        for (q = 0; q < g; ++q)
            for (x = b[q], C = n[q], u = 0; u < g; ++u)
                if (A = x[u])
                    for (D = u - e, K = Math.min(l, u + e + 1), H = Math.max(e, D); H < K; ++H) C[H] += A * r[H - D];
        b = i6(g - 2 * e);
        for (q = 0; q < g; ++q)
            for (x = n[q], C = Math.max(e, q - e), D = Math.min(l, q + e + 1),
                K = q - e, u = e, H = 0; u < l; ++u, ++H)
                if (A = x[u])
                    for (var G = C; G < D; ++G) b[G - e][H] += A * r[G - K];
        r = Math.ceil(256 / a.b);
        r = f.createImageData(r, r);
        e = a.get("gradient");
        g = a.j;
        l = e[e.length - 1];
        c = e.length / c;
        n = r.data;
        x = q = 0;
        for (u = b.length; x < u; ++x)
            for (A = b[x], C = 0, D = A.length; C < D; ++C)(K = A[C]) || e[0].alpha ? (K = e[Math.floor(K * c)] || l, H = g ? K.alpha / 255 : 1, n[q++] = K.j * H, n[q++] = K.f * H, n[q++] = K.b * H, n[q++] = K.alpha) : q += 4;
        h ? (d = d.createElement("canvas"), d.width = d.height = 256 / a.b, d.getContext("2d").putImageData(r, 0, 0), f.scale(a.b, a.b), f.drawImage(d, 0,
            0)) : f.putImageData(r, 0, 0)
    },
    s6 = function (a, b) {
        _.yf.call(this);
        this.tileSize = new _.J(256, 256);
        this.j = {};
        var c = _.vf(-100, -300, 100, 300);
        this.A = new _.dG(c, void 0);
        c = _.vf(-90, -180, 90, 180);
        this.f = _.jJ(c, function (a, b) {
            return a.ea.b(b.ea) && a.weight == b.weight
        });
        this.S = [];
        this.D = new _.zc;
        this.b = 0;
        this.m = new q6(this.f, a);
        this.m.bindTo("projection", this, "projection", !0);
        this.m.bindTo("gradient", this, "gradient", !0);
        this.m.bindTo("radius", this, "radius", !0);
        var d = this;
        b(this.D, function (a) {
            r6(d.m, a, d.b)
        })
    },
    t6 = function (a,
        b) {
        var c = b.Z,
            d = 1 << b.zoom,
            e = a.get("radius"),
            f = new _.I(256 * c.x / d, 256 * c.y / d),
            c = _.vf((256 * c.x - e) / d, (256 * c.y - e) / d, (256 * (c.x + 1) + e) / d, (256 * (c.y + 1) + e) / d),
            d = a.get("projection");
        _.kJ(c, d, f, function (c) {
            c.wm = b;
            b.ac[_.yb(c)] = c;
            _.eG(a.A, c)
        })
    },
    u6 = function (a, b) {
        _.Wa(b.ac, function (b, d) {
            a.A.remove(d)
        });
        b.ac = {}
    },
    v6 = function (a) {
        var b = a.get("maxIntensity");
        return 1 <= b ? b : j6(a.get("data"))
    },
    w6 = function (a, b) {
        b = _.gG(a.A, b);
        a.get("projection");
        for (var c = 0, d = b.length; c < d; ++c) _.Ac(a.D, b[c].wm)
    },
    x6 = function (a) {
        _.Wa(a.j, function (b,
            c) {
            _.Ac(a.D, c)
        })
    },
    y6 = function (a) {
        var b = a.location || a;
        a = a.weight || 1;
        return {
            ea: new _.I(b.lat(), b.lng()),
            weight: a
        }
    },
    z6 = function (a, b, c) {
        this.b = a;
        a.b = (0, _.p)(this.j, this);
        this.A = b;
        this.f = c
    },
    A6 = _.na();
var B6 = "rgba(102, 255, 0, 0);rgba(102, 255, 0, 1);rgba(147, 255, 0, 1);rgba(193, 255, 0, 1);rgba(238, 255, 0, 1);rgba(244, 227, 0, 1);rgba(249, 198, 0, 1);rgba(255, 170, 0, 1);rgba(255, 113, 0, 1);rgba(255, 57, 0, 1);rgba(255, 0, 0, 1)".split(";");
var m6;
var C6, D6 = [137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13],
    E6 = [0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130];
p6.prototype.getDiv = _.pa("f");
o6.prototype.createImageData = function (a, b) {
    for (var c = Array(a * b * 4), d = 0; d < a * b * 4; ++d) c[d] = 0;
    return {
        data: c,
        width: a,
        height: b
    }
};
o6.prototype.putImageData = function (a) {
    var b = this.b,
        c = _.Y("img", b.getDiv()),
        d = a.width,
        e = a.height,
        f = a.data,
        g = 11 + (4 * d + 1) * e;
    a = Array(g + 24);
    a[0] = g >>> 24;
    a[1] = (g & 16711680) >> 16;
    a[2] = (g & 65280) >> 8;
    a[3] = g & 255;
    a[4] = 73;
    a[5] = 68;
    a[6] = 65;
    a[7] = 84;
    a[8] = 8;
    a[9] = 29;
    a[10] = 1;
    g -= 11;
    a[11] = g & 255;
    a[12] = (g & 65280) >> 8;
    a[13] = 255 - a[11];
    a[14] = 255 - a[12];
    for (var h = 1, l = 0, n = 15, q = 0, r = 0; r < e; ++r) {
        a[n++] = 0;
        for (var l = l + h, u = 0; u < 4 * d; ++u) a[n++] = f[q], l += h += f[q++]
    }
    h %= 65521;
    l %= 65521;
    a[n++] = (l & 65280) >> 8;
    a[n++] = l & 255;
    a[n++] = (h & 65280) >> 8;
    a[n++] = h &
        255;
    f = n6(a, 4, g + 15);
    a[n++] = f >>> 24;
    a[n++] = (f & 16711680) >> 16;
    a[n++] = (f & 65280) >> 8;
    a[n++] = f & 255;
    f = 0;
    for (g = E6.length; f < g; ++f) a[n++] = E6[f];
    if (-1 != d || -1 != e) d = [73, 72, 68, 82, d >>> 24, (d & 16711680) >> 16, (d & 65280) >> 8, d & 255, e >>> 24, (e & 16711680) >> 16, (e & 65280) >> 8, e & 255, 8, 6, 0, 0, 0], e = n6(d, 0, d.length), C6 = "data:image/png;base64," + _.qk(D6.concat(d, [e >>> 24, (e & 16711680) >> 16, (e & 65280) >> 8, e & 255]));
    a = C6 + _.qk(a);
    c.src = a;
    c.width = b.width;
    c.height = b.height
};
_.t(q6, _.B);
q6.prototype.radius_changed = function () {
    var a = this.get("radius");
    _.Gz() ? this.b = 20 > a ? 1 : 2 : this.b = 4;
    for (var a = Math.round(a / this.b), b = a / 3, c = [], d = -a; d <= a; d++) c.push(Math.exp(-d * d / (2 * b * b)));
    this.f = c
};
_.t(s6, _.yf);
_.k = s6.prototype;
_.k.projection = null;
_.k.getTile = function (a, b, c) {
    var d = c.createElement("div");
    _.zf(d, this.tileSize);
    var e = this.get("opacity");
    _.m(e) && _.am(d, e);
    a = {
        V: d,
        zoom: b,
        Z: a,
        ac: {},
        ownerDocument: c
    };
    d.ma = a;
    this.j[_.yb(a)] = a;
    t6(this, a);
    this.b || (this.b = v6(this));
    r6(this.m, a, this.b);
    return d
};
_.k.data_changed = function () {
    this.f.clear();
    var a = this.get("data"),
        b = this;
    a && (a.forEach(function (a) {
        a && _.iJ(b.f, y6(a))
    }), this.M());
    x6(this);
    _.v(this.S, _.z.removeListener);
    this.S = [];
    a && (this.S = [_.z.bind(a, "insert_at", this, this.si), _.z.bind(a, "remove_at", this, this.ti), _.z.bind(a, "set_at", this, this.eo)])
};
_.k.si = function (a) {
    if (a = this.get("data").getAt(a)) a = y6(a), _.iJ(this.f, a), this.M(), w6(this, a.ea)
};
_.k.ti = function (a, b) {
    b && (a = y6(b), this.f.remove(a), this.M(), w6(this, a.ea))
};
_.k.eo = function (a, b) {
    this.ti(0, b);
    this.si(a)
};
_.k.$ = function () {
    var a = this.b;
    this.b = v6(this);
    _.ab(a, this.b) || x6(this)
};
_.k.maxIntensity_changed = function () {
    this.b = v6(this);
    x6(this)
};
_.k.gradient_changed = function () {
    x6(this)
};
_.k.opacity_changed = function () {
    var a = this.get("opacity");
    _.Wa(this.j, function (b, c) {
        _.am(c.V, a)
    })
};
_.k.radius_changed = function () {
    var a = this;
    _.Wa(this.j, function (b, c) {
        u6(a, c);
        t6(a, c)
    });
    x6(this)
};
_.k.releaseTile = function (a) {
    if (a) {
        var b = a.ma;
        a.ma = null;
        delete this.j[_.yb(b)];
        var c = this.A;
        _.Wa(b.ac, function (a, b) {
            c.remove(b)
        });
        _.Rl(b.V, "")
    }
};
z6.prototype.j = function () {
    _.lz(this.f, (0, _.p)(this.m, this))
};
z6.prototype.m = function () {
    var a;
    a: {
        a = this.b.f;
        for (var b in a) {
            a = a[b];
            this.b.remove(a);
            break a
        }
        a = null
    }
    a && this.A(a)
};
A6.prototype.b = function (a) {
    var b = a.j,
        c = a.j = a.get("map");
    b && (a.b && a.b.unbindAll(), a.f && a.f.release(), _.Wm("Lh", "-p", a));
    if (c) {
        a.b = new _.Bu({
            dissipating: !0,
            gradient: B6,
            opacity: .6,
            radius: 10
        });
        a.b.bindTo("dissipating", a);
        a.b.bindTo("gradient", a);
        a.b.bindTo("opacity", a);
        a.b.bindTo("radius", a);
        b = new _.du(["stringGradient", "opacity"], "colorGradient", function (a, b) {
            return l6(a, b)
        });
        b.bindTo("stringGradient", a.b, "gradient", !0);
        var d = new _.du(["radius", "dissipating", "zoom"], "renderingRadius", function (a, b, c) {
            return b ?
                a : Math.min(Math.round(a * Math.pow(2, c)), 256)
        });
        d.bindTo("radius", a.b);
        d.bindTo("zoom", c);
        d.bindTo("dissipating", a.b);
        var e = new s6(_.fl.Hm(), function (a, b) {
            new z6(a, b, new _.oz(_.nz(250), 0))
        });
        e.bindTo("projection", c);
        e.bindTo("data", a);
        e.bindTo("maxIntensity", a);
        e.bindTo("gradient", b, "colorGradient");
        e.bindTo("radius", d, "renderingRadius");
        _.Gz() ? (e.bindTo("opacity", a.b), b.set("opacity", 1)) : b.bindTo("opacity", a.b);
        _.QF(c, e, "overlayLayer", 15, function (b) {
            a.f = b
        });
        _.Tm(c, "Lh");
        _.Vm("Lh", "-p", a, !!c.b)
    }
};
_.mc("visualization_impl", new A6);
});

而这第二个好像和第一个关系密切,在操作数据时调用(字符太多放不下,所以我把它存储在这个fiddle):

https://jsfiddle.net/u59wrb2o/

提前致谢!

这不是确切答案,而是我使用的解决方法,可能对其他人有用

由于找不到这个问题的答案,所以我用了一个技巧,仍然可以访问图例。

简而言之,我让用户使用 HTML 中的滑块定义热图的 maxIntensity 参数(在最左侧时,显示由 Google 定义的默认 maxIntensity 值):

<!-- For the UPPER_BOUND in the max, I chose to use the sum of all my data, it works pretty well -->
<input type="range" id="intensitySlider" onchange="changeMaxIntensity(intensitySlider.value)" min="0" max="UPPER_BOUND" step="1" value="0">

从这里我可以得到现在用这个 JS 函数明确定义的 maxIntensity:

function changeMaxIntensity(maxIntensity) {

    // If maxIntensity = 0, it will be set to the default value => heatmap.get('maxIntensity') will return "undefined"
    // The "* 1" here is to convert "maxIntensity" from string to number if ever needed
    heatmap.set('maxIntensity', maxIntensity * 1);
    var maxInt = heatmap.get('maxIntensity'),
        valueLegend = document.getElementById("value"),
        percentLegend = document.getElementById("percent");

    if (maxInt) { 
        // Not default value (user set != 0)
        for (var i = 2; i < 6; i++) {
            // The numbers are rounded and formatted in the french way: "1 234 567 Tons" for instance
            valueLegend.childNodes[i].textContent = Math.round(maxInt * (i - 1) / 4).toString().replace(/\B(?=(\d{3})+(?!\d))/g, " ") + ' Tons';
            percentLegend.childNodes[i].textContent = Math.round(maxInt / globalSalesTons * 100 * (i - 1) / 4).toString().replace(/\B(?=(\d{3})+(?!\d))/g, " ") + ' %';
    } else { 
        // Default value (user set = 0), can't get maxIntensity with .get in this case
        valueLegend.childNodes[2].textContent = '...';
        valueLegend.childNodes[3].textContent = '...';
        valueLegend.childNodes[4].textContent = '...';
        valueLegend.childNodes[5].textContent = 'Undefined';

        percentLegend.childNodes[2].textContent = '...';
        percentLegend.childNodes[3].textContent = '...';
        percentLegend.childNodes[4].textContent = '...';
        percentLegend.childNodes[5].textContent = 'Undefined';
    }
}

有关信息,这是我的 HTML 图例代码:

<div id="legend">
        <div class="legend-labels" id ="value">
            <div>0 Tons</div><div>...</div><div>...</div><div>...</div><div>Undefined</div>
        </div>
        <div class="ticks">
            <div></div><div></div><div></div><div></div><div></div>
        </div>
        <div id="legend-gradient" class="grad1"></div>
        <div class="ticks">
            <div></div><div></div><div></div><div></div><div></div>
        </div>
        <div class="legend-labels" id ="percent">
            <div>0 % of overall sales</div><div>...</div><div>...</div><div>...</div><div>Undefined</div>
        </div>
    </div>

和 CSS:

.ticks {
    display: -ms-flexbox;
    display: flex;
    -ms-flex-pack: distribute;
    justify-content: space-around;
    height: 10px;
    width: 100%;
    background: inherit;
}

.ticks * {
    width: 1px;
    background: #eeeeee;
}

#legend {
    width: 100%;
    height: 100px;
    background: #333333;
    display: -ms-flexbox;
    display: flex;
    -ms-flex-direction: column;
    flex-direction: column;
    -ms-flex-align: center;
    align-items: center;
    color: #eeeeee;
}

.legend-labels {
    width: 100%;
    height: 25px;
    display: -ms-flexbox;
    display: flex;
    -ms-flex-pack: distribute;
    justify-content: space-around;
}

.legend-labels *{
    -ms-flex: 1;
    flex: 1;
    height: 25px;
    line-height: 25px;
    overflow: hidden;
    text-align: center;
}

#legend-gradient {
    width: 80%;
    height: 30px;
    background: YOUR_GRADIENT_HERE;
}

这里有两个截图来说明最终结果:

When the user has not yet defined the maxIntensity

When the user has defined the maxIntensity