

(function (w) {
    // the heatmapFactory creates heatmap instances     
    var heatmapFactory = (function(){

    // store object constructor
    // a heatmap contains a store
    // the store has to know about the heatmap in order to trigger heatmap updates when datapoints get added
    var store = function store(hmap) {

        var _ = {
            // data is a two dimensional array
            // a datapoint gets saved as data[point-x-value][point-y-value]
            // the value at [point-x-value][point-y-value] is the occurrence of the datapoint
            data: [],
            // tight coupling of the heatmap object
            heatmap: hmap
        };
        // the max occurrence - the heatmaps radial gradient alpha transition is based on it
        this.max = 1;

        this.get = function (key) {
            return _[key];
        };
        this.set = function (key, value) {
            _[key] = value;
        };
    }

    store.prototype = {
        // function for adding datapoints to the store
        // datapoints are usually defined by x and y but could also contain a third parameter which represents the occurrence
        addDataPoint: function (x, y) {
            if (x < 0 || y < 0)
                return;

            var me = this,
                heatmap = me.get("heatmap"),
                data = me.get("data");

            if (!data[x])
                data[x] = [];

            if (!data[x][y])
                data[x][y] = 0;

            // if count parameter is set increment by count otherwise by 1
            data[x][y] += (arguments.length < 3) ? 1 : arguments[2];

            me.set("data", data);
            // do we have a new maximum?
            if (me.max < data[x][y]) {
                // max changed, we need to redraw all existing(lower) datapoints
                heatmap.get("actx").clearRect(0, 0, heatmap.get("width"), heatmap.get("height"));
                me.setDataSet({ max: data[x][y], data: data }, true);
                return;
            }
            heatmap.drawAlpha(x, y, data[x][y], true);
        },
        setDataSet: function (obj, internal) {
            var me = this,
                heatmap = me.get("heatmap"),
                data = [],
                d = obj.data,
                dlen = d.length;
            // clear the heatmap before the data set gets drawn
            heatmap.clear();
            this.max = obj.max;
            // if a legend is set, update it
            heatmap.get("legend") && heatmap.get("legend").update(obj.max);

            if (internal != null && internal) {
                for (var one in d) {
                    // jump over undefined indexes
                    if (one === undefined)
                        continue;
                    for (var two in d[one]) {
                        if (two === undefined)
                            continue;
                        // if both indexes are defined, push the values into the array
                        heatmap.drawAlpha(one, two, d[one][two], false);
                    }
                }
            } else {
                while (dlen--) {
                    var point = d[dlen];
                    heatmap.drawAlpha(point.x, point.y, point.count, false);
                    if (!data[point.x])
                        data[point.x] = [];

                    if (!data[point.x][point.y])
                        data[point.x][point.y] = 0;

                    data[point.x][point.y] = point.count;
                }
            }
            heatmap.colorize();
            this.set("data", d);
        },
        exportDataSet: function () {
            var me = this,
                data = me.get("data"),
                exportData = [];

            for (var one in data) {
                // jump over undefined indexes
                if (one === undefined)
                    continue;
                for (var two in data[one]) {
                    if (two === undefined)
                        continue;
                    // if both indexes are defined, push the values into the array
                    exportData.push({ x: parseInt(one, 10), y: parseInt(two, 10), count: data[one][two] });
                }
            }

            return { max: me.max, data: exportData };
        },
        generateRandomDataSet: function (points) {
            var heatmap = this.get("heatmap"),
                w = heatmap.get("width"),
                h = heatmap.get("height");
            var randomset = {},
                max = Math.floor(Math.random() * 1000 + 1);
            randomset.max = max;
            var data = [];
            while (points--) {
                data.push({ x: Math.floor(Math.random() * w + 1), y: Math.floor(Math.random() * h + 1), count: Math.floor(Math.random() * max + 1) });
            }
            randomset.data = data;
            this.setDataSet(randomset);
        }
    };

    var legend = function legend(config) {
        this.config = config;

        var _ = {
            element: null,
            labelsEl: null,
            gradientCfg: null,
            ctx: null
        };
        this.get = function (key) {
            return _[key];
        };
        this.set = function (key, value) {
            _[key] = value;
        };
        this.init();
    };
    legend.prototype = {
        init: function () {
            var me = this,
                config = me.config,
                title = config.title || "Legend",
                position = config.position,
                offset = config.offset || 10,
                gconfig = config.gradient,
                labelsEl = document.createElement("ul"),
                labelsHtml = "",
                grad, element, gradient, positionCss = "";

            me.processGradientObject();

            // Positioning

            // top or bottom
            if (position.indexOf('t') > -1) {
                positionCss += 'top:' + offset + 'px;';
            } else {
                positionCss += 'bottom:' + offset + 'px;';
            }

            // left or right
            if (position.indexOf('l') > -1) {
                positionCss += 'left:' + offset + 'px;';
            } else {
                positionCss += 'right:' + offset + 'px;';
            }

            element = document.createElement("div");
            element.style.cssText = "border-radius:5px;position:absolute;" + positionCss + "font-family:Helvetica; width:256px;z-index:10000000000; background:rgba(255,255,255,1);padding:10px;border:1px solid black;margin:0;";
            element.innerHTML = "<h3 style='padding:0;margin:0;text-align:center;font-size:16px;'>" + title + "</h3>";
            // create gradient in canvas
            labelsEl.style.cssText = "position:relative;font-size:12px;display:block;list-style:none;list-style-type:none;margin:0;height:15px;";


            // create gradient element
            gradient = document.createElement("div");
            gradient.style.cssText = ["position:relative;display:block;width:256px;height:15px;border-bottom:1px solid black; background-image:url(", me.createGradientImage(), ");"].join("");

            element.appendChild(labelsEl);
            element.appendChild(gradient);

            me.set("element", element);
            me.set("labelsEl", labelsEl);

            me.update(1);
        },
        processGradientObject: function () {
            // create array and sort it
            var me = this,
                gradientConfig = this.config.gradient,
                gradientArr = [];

            for (var key in gradientConfig) {
                if (gradientConfig.hasOwnProperty(key)) {
                    gradientArr.push({ stop: key, value: gradientConfig[key] });
                }
            }
            gradientArr.sort(function (a, b) {
                return (a.stop - b.stop);
            });
            gradientArr.unshift({ stop: 0, value: 'rgba(0,0,0,0)' });

            me.set("gradientArr", gradientArr);
        },
        createGradientImage: function () {
            var me = this,
                gradArr = me.get("gradientArr"),
                length = gradArr.length,
                canvas = document.createElement("canvas"),
                ctx = canvas.getContext("2d"),
                grad;
            // the gradient in the legend including the ticks will be 256x15px
            canvas.width = "256";
            canvas.height = "15";

            grad = ctx.createLinearGradient(0, 5, 256, 10);

            for (var i = 0; i < length; i++) {
                grad.addColorStop(1 / (length - 1) * i, gradArr[i].value);
            }

            ctx.fillStyle = grad;
            ctx.fillRect(0, 5, 256, 10);
            ctx.strokeStyle = "black";
            ctx.beginPath();

            for (var i = 0; i < length; i++) {
                ctx.moveTo(((1 / (length - 1) * i * 256) >> 0) + .5, 0);
                ctx.lineTo(((1 / (length - 1) * i * 256) >> 0) + .5, (i == 0) ? 15 : 5);
            }
            ctx.moveTo(255.5, 0);
            ctx.lineTo(255.5, 15);
            ctx.moveTo(255.5, 4.5);
            ctx.lineTo(0, 4.5);

            ctx.stroke();

            // we re-use the context for measuring the legends label widths
            me.set("ctx", ctx);

            return canvas.toDataURL();
        },
        getElement: function () {
            return this.get("element");
        },
        update: function (max) {
            var me = this,
                gradient = me.get("gradientArr"),
                ctx = me.get("ctx"),
                labels = me.get("labelsEl"),
                labelText, labelsHtml = "", offset;

            for (var i = 0; i < gradient.length; i++) {

                labelText = max * gradient[i].stop >> 0;
                offset = (ctx.measureText(labelText).width / 2) >> 0;

                if (i == 0) {
                    offset = 0;
                }
                if (i == gradient.length - 1) {
                    offset *= 2;
                }
                labelsHtml += '<li style="position:absolute;left:' + (((((1 / (gradient.length - 1) * i * 256) || 0)) >> 0) - offset + .5) + 'px">' + labelText + '</li>';
            }
            labels.innerHTML = labelsHtml;
        }
    };

    // heatmap object constructor
    var heatmap = function heatmap(config) {
        // private variables
        var _ = {
            radius: 40,
            element: {},
            canvas: {},
            acanvas: {},
            ctx: {},
            actx: {},
            legend: null,
            visible: true,
            width: 0,
            height: 0,
            max: false,
            gradient: false,
            opacity: 180,
            premultiplyAlpha: false,
            bounds: {
                l: 1000,
                r: 0,
                t: 1000,
                b: 0
            },
            debug: false
        };
        // heatmap store containing the datapoints and information about the maximum
        // accessible via instance.store
        this.store = new store(this);

        this.get = function (key) {
            return _[key];
        };
        this.set = function (key, value) {
            _[key] = value;
        };
        // configure the heatmap when an instance gets created
        this.configure(config);
        // and initialize it
        this.init();
    };

    // public functions
    heatmap.prototype = {
        configure: function (config) {
            var me = this,
                rout, rin;

            me.set("radius", config["radius"] || 40);
            me.set("element", (config.element instanceof Object) ? config.element : document.getElementById(config.element));
            me.set("visible", (config.visible != null) ? config.visible : true);
            me.set("max", config.max || false);
            me.set("gradient", config.gradient || { 0.45: "rgb(0,0,255)", 0.55: "rgb(0,255,255)", 0.65: "rgb(0,255,0)", 0.95: "yellow", 1.0: "rgb(255,0,0)" });    // default is the common blue to red gradient
            me.set("opacity", parseInt(255 / (100 / config.opacity), 10) || 180);
            me.set("width", config.width || 0);
            me.set("height", config.height || 0);
            me.set("debug", config.debug);

            if (config.legend) {
                var legendCfg = config.legend;
                legendCfg.gradient = me.get("gradient");
                me.set("legend", new legend(legendCfg));
            }

        },
        resize: function () {
            var me = this,
                element = me.get("element"),
                canvas = me.get("canvas"),
                acanvas = me.get("acanvas");
            canvas.width = acanvas.width = me.get("width") || element.style.width.replace(/px/, "") || me.getWidth(element);
            this.set("width", canvas.width);
            canvas.height = acanvas.height = me.get("height") || element.style.height.replace(/px/, "") || me.getHeight(element);
            this.set("height", canvas.height);
        },

        init: function () {
            var me = this,
                canvas = document.createElement("canvas"),
                acanvas = document.createElement("canvas"),
                ctx = canvas.getContext("2d"),
                actx = acanvas.getContext("2d"),
                element = me.get("element");


            me.initColorPalette();

            me.set("canvas", canvas);
            me.set("ctx", ctx);
            me.set("acanvas", acanvas);
            me.set("actx", actx);

            me.resize();
            canvas.style.cssText = acanvas.style.cssText = "position:absolute;top:0;left:0;z-index:1;";

            if (!me.get("visible"))
                canvas.style.display = "none";

            element.appendChild(canvas);
            if (me.get("legend")) {
                element.appendChild(me.get("legend").getElement());
            }

            // debugging purposes only
            if (me.get("debug"))
                document.body.appendChild(acanvas);

            actx.shadowOffsetX = 15000;
            actx.shadowOffsetY = 15000;
            actx.shadowBlur = 15;
        },
        initColorPalette: function () {

            var me = this,
                canvas = document.createElement("canvas"),
                gradient = me.get("gradient"),
                ctx, grad, testData;

            canvas.width = "1";
            canvas.height = "256";
            ctx = canvas.getContext("2d");
            grad = ctx.createLinearGradient(0, 0, 1, 256);

            // Test how the browser renders alpha by setting a partially transparent pixel
            // and reading the result.  A good browser will return a value reasonably close
            // to what was set.  Some browsers (e.g. on Android) will return a ridiculously wrong value.
            testData = ctx.getImageData(0, 0, 1, 1);
            testData.data[0] = testData.data[3] = 64; // 25% red & alpha
            testData.data[1] = testData.data[2] = 0; // 0% blue & green
            ctx.putImageData(testData, 0, 0);
            testData = ctx.getImageData(0, 0, 1, 1);
            me.set("premultiplyAlpha", (testData.data[0] < 60 || testData.data[0] > 70));

            for (var x in gradient) {
                grad.addColorStop(x, gradient[x]);
            }

            ctx.fillStyle = grad;
            ctx.fillRect(0, 0, 1, 256);

            me.set("gradient", ctx.getImageData(0, 0, 1, 256).data);
        },
        getWidth: function (element) {
            var width = element.offsetWidth;
            if (element.style.paddingLeft) {
                width += element.style.paddingLeft;
            }
            if (element.style.paddingRight) {
                width += element.style.paddingRight;
            }

            return width;
        },
        getHeight: function (element) {
            var height = element.offsetHeight;
            if (element.style.paddingTop) {
                height += element.style.paddingTop;
            }
            if (element.style.paddingBottom) {
                height += element.style.paddingBottom;
            }

            return height;
        },
        colorize: function (x, y) {
            // get the private variables
            var me = this,
                width = me.get("width"),
                radius = me.get("radius"),
                height = me.get("height"),
                actx = me.get("actx"),
                ctx = me.get("ctx"),
                x2 = radius * 3,
                premultiplyAlpha = me.get("premultiplyAlpha"),
                palette = me.get("gradient"),
                opacity = me.get("opacity"),
                bounds = me.get("bounds"),
                left, top, bottom, right,
                image, imageData, length, alpha, offset, finalAlpha;

            if (x != null && y != null) {
                if (x + x2 > width) {
                    x = width - x2;
                }
                if (x < 0) {
                    x = 0;
                }
                if (y < 0) {
                    y = 0;
                }
                if (y + x2 > height) {
                    y = height - x2;
                }
                left = x;
                top = y;
                right = x + x2;
                bottom = y + x2;

            } else {
                if (bounds['l'] < 0) {
                    left = 0;
                } else {
                    left = bounds['l'];
                }
                if (bounds['r'] > width) {
                    right = width;
                } else {
                    right = bounds['r'];
                }
                if (bounds['t'] < 0) {
                    top = 0;
                } else {
                    top = bounds['t'];
                }
                if (bounds['b'] > height) {
                    bottom = height;
                } else {
                    bottom = bounds['b'];
                }
            }

            image = actx.getImageData(left, top, right - left, bottom - top);
            imageData = image.data;
            length = imageData.length;
            // loop thru the area
            for (var i = 3; i < length; i += 4) {

                // [0] -> r, [1] -> g, [2] -> b, [3] -> alpha
                alpha = imageData[i],
                    offset = alpha * 4;

                if (!offset)
                    continue;

                // we ve started with i=3
                // set the new r, g and b values
                finalAlpha = (alpha < opacity) ? alpha : opacity;
                imageData[i - 3] = palette[offset];
                imageData[i - 2] = palette[offset + 1];
                imageData[i - 1] = palette[offset + 2];

                if (premultiplyAlpha) {
                    // To fix browsers that premultiply incorrectly, we'll pass in a value scaled
                    // appropriately so when the multiplication happens the correct value will result.
                    imageData[i - 3] /= 255 / finalAlpha;
                    imageData[i - 2] /= 255 / finalAlpha;
                    imageData[i - 1] /= 255 / finalAlpha;
                }

                // we want the heatmap to have a gradient from transparent to the colors
                // as long as alpha is lower than the defined opacity (maximum), we'll use the alpha value
                imageData[i] = finalAlpha;
            }
            // the rgb data manipulation didn't affect the ImageData object(defined on the top)
            // after the manipulation process we have to set the manipulated data to the ImageData object
            image.data = imageData;
            ctx.putImageData(image, left, top);
        },
        drawAlpha: function (x, y, count, colorize) {
            // storing the variables because they will be often used
            var me = this,
                radius = me.get("radius"),
                ctx = me.get("actx"),
                max = me.get("max"),
                bounds = me.get("bounds"),
                xb = x - (1.5 * radius) >> 0, yb = y - (1.5 * radius) >> 0,
                xc = x + (1.5 * radius) >> 0, yc = y + (1.5 * radius) >> 0;

            ctx.shadowColor = ('rgba(0,0,0,' + ((count) ? (count / me.store.max) : '0.1') + ')');

            ctx.shadowOffsetX = 15000;
            ctx.shadowOffsetY = 15000;
            ctx.shadowBlur = 15;

            ctx.beginPath();
            ctx.arc(x - 15000, y - 15000, radius, 0, Math.PI * 2, true);
            ctx.closePath();
            ctx.fill();
            if (colorize) {
                // finally colorize the area
                me.colorize(xb, yb);
            } else {
                // or update the boundaries for the area that then should be colorized
                if (xb < bounds["l"]) {
                    bounds["l"] = xb;
                }
                if (yb < bounds["t"]) {
                    bounds["t"] = yb;
                }
                if (xc > bounds['r']) {
                    bounds['r'] = xc;
                }
                if (yc > bounds['b']) {
                    bounds['b'] = yc;
                }
            }
        },
        toggleDisplay: function () {
            var me = this,
                visible = me.get("visible"),
                canvas = me.get("canvas");

            if (!visible)
                canvas.style.display = "block";
            else
                canvas.style.display = "none";

            me.set("visible", !visible);
        },
        // dataURL export
        getImageData: function () {
            return this.get("canvas").toDataURL();
        },
        clear: function () {
            var me = this,
                w = me.get("width"),
                h = me.get("height");

            me.store.set("data", []);
            // @TODO: reset stores max to 1
            //me.store.max = 1;
            me.get("ctx").clearRect(0, 0, w, h);
            me.get("actx").clearRect(0, 0, w, h);
        },
        cleanup: function () {
            var me = this;
            me.get("element").removeChild(me.get("canvas"));
        }
    };

    return {
        create: function (config) {
            return new heatmap(config);
        },
        util: {
            mousePosition: function (ev) {
                // this doesn't work right
                // rather use
                /*
                    // this = element to observe
                    var x = ev.pageX - this.offsetLeft;
                    var y = ev.pageY - this.offsetTop;

                */
                var x, y;

                if (ev.layerX) { // Firefox
                    x = ev.layerX;
                    y = ev.layerY;
                } else if (ev.offsetX) { // Opera
                    x = ev.offsetX;
                    y = ev.offsetY;
                }
                if (typeof (x) == 'undefined')
                    return;

                return [x, y];
            }
        }
    };
})();
w.h337 = w.heatmapFactory = heatmapFactory;
}) (window);


/*==============================以上部分为heatmap.js的核心代码,只负责热力图的展现====================================*/


/*==============================以下部分为专为百度地图打造的覆盖物===================================================*/
/**
 * @fileoverview 百度地图的热力图功能,对外开放。
 * 主要基于http://www.patrick-wied.at/static/heatmapjs/index.html 修改而得
 
 * 主入口类是<a href="symbols/BMapLib.Heatmap.html">Heatmap</a>，
 * 基于Baidu Map API 2.0。
 *
 * @author Baidu Map Api Group
 * @version 1.0
 */

/**
 * @namespace 
 * BMap的所有library类均放在BMapLib命名空间下
 */
var BMapLib = window.BMapLib = BMapLib || {};


(function () {
    /** 
     * @exports HeatmapOverlay as BMapLib.HeatmapOverlay 
     */
    var HeatmapOverlay =
        /**
         * 热力图的覆盖物
         * @class 热力图的覆盖物
         * 实例化该类后，使用map.addOverlay即可以添加热力图
         * 
         * @constructor
         * @param {Json Object} opts 可选的输入参数，非必填项。可输入选项包括：<br />
         * {"<b>radius</b>" : {String} 热力图的半径,
         * <br />"<b>visible</b>" : {Number} 热力图是否显示,
         * <br />"<b>gradient</b>" : {JSON} 热力图的渐变区间,
         * <br />"<b>opacity</b>" : {Number} 热力的透明度,
         *
         * @example <b>参考示例：</b><br />
         * var map = new BMapGL.Map("container");<br />map.centerAndZoom(new BMapGL.Point(116.404, 39.915), 15);<br />var heatmapOverlay = new BMapLib.HeatmapOverlay({"radius":10, "visible":true, "opacity":70});<br />heatmapOverlay.setDataSet(data);//data是热力图的详细数据
         */

        BMapLib.HeatmapOverlay = function (opts) {
            this.conf = opts;
            this.heatmap = null;
            this.latlngs = [];
            this.bounds = null;
        }

    HeatmapOverlay.prototype = new BMapGL.Overlay();

    HeatmapOverlay.prototype.initialize = function (map) {
        this._map = map;
        var el = document.createElement("div");
        el.style.position = "absolute";
        el.style.top = 0;
        el.style.left = 0;
        el.style.border = 0;
        el.style.width = this._map.getSize().width + "px";
        el.style.height = this._map.getSize().height + "px";
        this.conf.element = el;

        if (!isSupportCanvas()) {//判断是否支持Canvas.
            return el;
        }
        map.getContainer().appendChild(el);
        this.heatmap = h337.create(this.conf);
        this._div = el;
        return el;
    }

    HeatmapOverlay.prototype.draw = function () {
        if (!isSupportCanvas()) {//判断是否支持Canvas.
            return;
        }
        var currentBounds = this._map.getBounds();

        if (currentBounds.equals(this.bounds)) {
            return;
        }
        this.bounds = currentBounds;

        var ne = this._map.pointToOverlayPixel(currentBounds.getNorthEast()),
            sw = this._map.pointToOverlayPixel(currentBounds.getSouthWest()),
            topY = ne.y,
            leftX = sw.x,
            h = sw.y - ne.y,
            w = ne.x - sw.x;

        this.conf.element.style.left = leftX + 'px';
        this.conf.element.style.top = topY + 'px';
        this.conf.element.style.width = w + 'px';
        this.conf.element.style.height = h + 'px';
        this.heatmap.store.get("heatmap").resize();

        if (this.latlngs.length > 0) {
            this.heatmap.clear();

            var len = this.latlngs.length;
            d = {
                max: this.heatmap.store.max,
                data: []
            };

            while (len--) {
                var latlng = this.latlngs[len].latlng;

                if (!currentBounds.containsPoint(latlng)) {
                    continue;
                }

                var divPixel = this._map.pointToOverlayPixel(latlng),
                    screenPixel = new BMapGL.Pixel(divPixel.x - leftX, divPixel.y - topY);
                var roundedPoint = this.pixelTransform(screenPixel);
                d.data.push({
                    x: roundedPoint.x,
                    y: roundedPoint.y,
                    count: this.latlngs[len].c
                });
            }
            this.heatmap.store.setDataSet(d);
        }
    }


    //内部使用的坐标转化
    HeatmapOverlay.prototype.pixelTransform = function (p) {
        var w = this.heatmap.get("width"),
            h = this.heatmap.get("height");

        while (p.x < 0) {
            p.x += w;
        }

        while (p.x > w) {
            p.x -= w;
        }

        while (p.y < 0) {
            p.y += h;
        }

        while (p.y > h) {
            p.y -= h;
        }

        p.x = (p.x >> 0);
        p.y = (p.y >> 0);

        return p;
    }

    /**
     * 设置热力图展现的详细数据, 实现之后,即可以立刻展现 
     * @param {Json Object } data
     * {"<b>max</b>" : {Number} 权重的最大值,
     * <br />"<b>data</b>" : {Array} 坐标详细数据,格式如下 <br/>
     * {"lng":116.421969,"lat":39.913527,"count":3}, 其中<br/>
     * lng lat分别为经纬度, count权重值
     */
    HeatmapOverlay.prototype.setDataSet = function (data) {
        this.data = data;
        if (!isSupportCanvas()) {//判断是否支持Canvas.
            return;
        }
        var currentBounds = this._map.getBounds();
        var mapdata = {
            max: data.max,
            data: []
        };
        var d = data.data,
            dlen = d.length;


        this.latlngs = [];

        while (dlen--) {
            var latlng = new BMapGL.Point(d[dlen].lng, d[dlen].lat);
            if (!currentBounds.containsPoint(latlng)) {
                continue;
            }
            this.latlngs.push({
                latlng: latlng,
                c: d[dlen].count
            });

            var divPixel = this._map.pointToOverlayPixel(latlng),
                leftX = this._map.pointToOverlayPixel(currentBounds.getSouthWest()).x,
                topY = this._map.pointToOverlayPixel(currentBounds.getNorthEast()).y,
                screenPixel = new BMapGL.Pixel(divPixel.x - leftX, divPixel.y - topY);
            var point = this.pixelTransform(screenPixel);

            mapdata.data.push({
                x: point.x,
                y: point.y,
                count: d[dlen].count
            });
        }
        this.heatmap.clear();
        this.heatmap.store.setDataSet(mapdata);
    }

    /**
     * 添加热力图的详细坐标点
     * @param {Number} lng 经度坐标
     * @param {Number} lat 经度坐标
     * @param {Number} count 经度坐标
     */
    HeatmapOverlay.prototype.addDataPoint = function (lng, lat, count) {

        if (!isSupportCanvas()) {
            return;
        }
        if (this.data && this.data.data) {
            this.data.data.push({
                lng: lng,
                lat: lat,
                count: count
            });
        }

        var latlng = new BMapGL.Point(lng, lat),
            point = this.pixelTransform(this._map.pointToOverlayPixel(latlng));

        this.heatmap.store.addDataPoint(point.x, point.y, count);
        this.latlngs.push({
            latlng: latlng,
            c: count
        });
    }

    /**
     * 更改热力图的展现或者关闭
     */

    HeatmapOverlay.prototype.toggle = function () {
        if (!isSupportCanvas()) {//判断是否支持Canvas.
            return;
        }
        this.heatmap.toggleDisplay();
    }
    /**
     * 设置热力图展现的配置
     * @param {Json Object} options 可选的输入参数，非必填项。可输入选项包括：<br />
     * {"<b>radius</b>" : {String} 热力图的半径,
     * <br />"<b>visible</b>" : {Number} 热力图是否显示,
     * <br />"<b>gradient</b>" : {JSON} 热力图的渐变区间,
     * <br />"<b>opacity</b>" : {Number} 热力的透明度,}
     */
    HeatmapOverlay.prototype.setOptions = function (options) {
        if (!isSupportCanvas()) {//判断是否支持Canvas.
            return;
        }

        if (options) {
            for (var key in options) {
                this.heatmap.set(key, options[key]);

                if (key == "gradient") {
                    this.heatmap.initColorPalette();
                    continue;
                }

                if (key == 'opacity') {
                    this.heatmap.set(key, parseInt(255 / (100 / options[key]), 10));

                }
            }

            if (this.data) {
                this.setDataSet(this.data);//重新渲染
            }
        }
    }

    function isSupportCanvas() {
        var elem = document.createElement('canvas');
        return !!(elem.getContext && elem.getContext('2d'));
    }
})()
