/* COPYRIGHT 2012 SUPERMAP
 * 本程序只能在有效的授权许可下使用
 * 未经许可,不得以任何手段擅自使用或传播。*/

/**
 * @requires SuperMap/Layer/Vector.js
 */

/**
 * Class: SuperMap.Layer.ClusterLayer
 * 该图层用于将要素以聚散的形式渲染出来。
 *
 * Inherits from:
 *  - <SuperMap.Layer.Vector>
 */
SuperMap.Layer.ClusterLayer = SuperMap.Class(SuperMap.Layer.Vector, {

    /**
     * APIProperty: maxLevel
     * {Number} 聚散显示的最大比例尺级数,超过该级后,不再进行聚散,而是直接绘制feature。
     */
    maxLevel: null,

    /**
     * APIProperty: isDiffused
     * {Boolean} 当点击聚散点时,是否允许聚散点可以散开,默认为true,允许聚散点散开。
     */
    isDiffused: true,

    /**
     * APIProperty: tolerance
     * {Number} 聚散的范围,该像素范围内的小点会被聚散成一个大点,默认为60像素。
     */
    tolerance: 60,

    /**
     * APIProperty: maxDiffuseAmount
     * {Number} 聚散点最多能散开小点的数目,当点击聚散点的时候,聚散数目小于等于该值的聚散点可以散开,大于该值的聚散点不会散开,默认值为50。
     */
    maxDiffuseAmount: 50,

    /**
     * APIProperty: renderers
     * {Array(String)} 可支持渲染器的列表,支持的渲染方式有'SVG', 'VML' ,默认值['SVG', 'VML']。
     * 如果在可选属性中未设置 'renderer' 选项,则使用当前浏览器支持的此列表中的第一个渲染方式,默认列表为['SVG', 'VML']。
     */
    renderers: ['SVG', 'VML'],

    /**
     * APIProperty: clusterStyles
     * Array{<Object>} 各级聚散点的样式,可通过修改该属性,修改cluster的分级以及各级的样式。
     * (注:示例代码中的clusterStyles值是clusterStyles的默认值)
     * (start code)
     * //创建一个名为“Cluster”的聚散点图层,并修改其clusterStyles属性。
     * var clusterLayer = new SuperMap.Layer.ClusterLayer("Cluster",{
     *     clusterStyles:[
     *         {
     *             "count":15,//子节点小于等于15的聚散点
     *             "style":{
     *                 fontColor:"#404040",
     *                 graphic:true,
     *                 externalGraphic:SuperMap.Util.getImagesLocation()+"cluster3.png",
     *                 graphicWidth:37,
     *                 graphicHeight:38,
     *                 labelXOffset:-4,
     *                 labelYOffset:5
     *             }
     *         },
     *         {
     *             "count":50,//子节点小于等于50大于15的聚散点
     *             "style":{
     *                 fontColor:"#404040",
     *                 graphic:true,
     *                 externalGraphic:SuperMap.Util.getImagesLocation()+"cluster2.png",
     *                 graphicWidth:41,
     *                 graphicHeight:46,
     *                 labelXOffset:-3,
     *                 labelYOffset:6
     *             }
     *         },
     *         {
     *             "count":"moreThanMax",// 子节点大于50的聚散点
     *             "style":{
     *                 fontColor:"#404040",
     *                 graphic:true,
     *                 externalGraphic:SuperMap.Util.getImagesLocation()+"cluster1.png",
     *                 graphicWidth:48,
     *                 graphicHeight:53,
     *                 labelXOffset:-5,
     *                 labelYOffset:8
     *             }
     *         }
     * ]});
     * (end)
     */
    clusterStyles: [
        {
            "count": 15,
            "style": {
                fontColor: "#404040",
                graphic: true,
                externalGraphic: SuperMap.Util.getImagesLocation() + "cluster3.png",
                graphicWidth: 37,
                graphicHeight: 38,
                labelXOffset: -4,
                labelYOffset: 5
            }
        },
        {
            "count": 50,
            "style": {
                fontColor: "#404040",
                graphic: true,
                externalGraphic: SuperMap.Util.getImagesLocation() + "cluster2.png",
                graphicWidth: 41,
                graphicHeight: 46,
                labelXOffset: -3,
                labelYOffset: 6
            }
        },
        {
            "count": "moreThanMax",
            "style": {
                fontColor: "#404040",
                graphic: true,
                externalGraphic: SuperMap.Util.getImagesLocation() + "cluster1.png",
                graphicWidth: 48,
                graphicHeight: 53,
                labelXOffset: -5,
                labelYOffset: 8
            }
        }
    ],

    /**
     * Property: noDrawClusters
     * {Boolean} 是否绘制聚散点,当设置为true时,仍然进行相关计算,但是不绘制,默认为false。
     */
    noDrawClusters: false,

    /**
     * Property: isFeatureChangeed
     * {Boolean} 添加的点是否有变化
     */
    isFeatureChanged: true,

    /**
     * Property: clusterPoints
     * {Array(<SuperMap.Feature.Vector>)}  所有需要渲染的feature数组
     */
    clusterPoints: [],

    /**
     * Property: toDrawFeatures
     * {Array(<SuperMap.Feature.Vector>)}  当前视图中已经绘制的feature
     */
    toDrawFeatures: null,

    /**
     * Property: openedPoints
     * {Array(<SuperMap.Feature.Vector>)}  保存的从聚散点中散开的小点数组
     */
    openedPoints: [],

    /**
     * Property: lastOpenedPoints
     * {Array(<SuperMap.Feature.Vector>)}  上一次散开的小点数组
     */
    lastOpenedPoints: [],

    /**
     * Property: pointMap
     * {Object(<SuperMap.Feature.Vector>)}  按照网格将所有feature结构化后的三维数组对象
     */
    pointMap: null,

    /**
     * Property: origin
     * {SuperMap.Geometry.Point}  地图的左上角坐标
     */
    origin: null,

    /**
     * Property: curOpenCluster
     * {SuperMap.Feature.Vector}  当前处于散开状态的聚散点对象
     */
    curOpenCluster: null,

    /**
     * Property: drawAllTimeout
     * Array{<Object>}  VML下有效,存储分批绘制点的timeout
     */
    drawAllTimeout: [],

    /**
     * Property: drawDiffusePointTimeout
     * Array{<Object>}  VML下有效,存储分批绘制散开点的timeout
     */
    drawDiffusePointTimeout: [],

    /**
     * Property: displayedBounds
     * {SuperMap.Bounds}  在该范围内的聚散点默认散开
     */
    displayedBounds: null,
    displayedBoundsExtent: [],

    /**
     * Property: dataExtent
     * {SuperMap.Bounds}  所有要素所在的地理范围
     */
    dataExtent: null,

    //displayedLevel:null,

    showFieldName:null,

    /**
     * Constructor: SuperMap.Layer.Vector
     * 创建一个聚散点图层。
     * (start code)
     * //创建一个名为“Cluster Layer”的聚散点图层。
     * var clusterLayer = new SuperMap.Layer.ClusterLayer("Cluster");
     * (end)
     *
     * Parameters:
     * name - 此图层的图层名 {String}
     * options - {Object} 设置此类上没有默认值的属性。
     *
     * Returns:
     * {<SuperMap.Layer.ClusterLayer>} 新的聚散点图层
     */
    initialize: function (name, options) {
        SuperMap.Layer.Vector.prototype.initialize.apply(this, arguments);

        this.EVENT_TYPES = this.EVENT_TYPES.concat(["clusterend"]);    //增加一个聚散完成事件

        this.events = new SuperMap.Events(this, this.div,
            this.EVENT_TYPES);
        if (this.eventListeners instanceof Object) {
            this.events.on(this.eventListeners);
        }

        //this.clusterStyles = this.getClusterModels();
        this.clusterStyles = this.clusterStyles.sort(function (a, b) {
            if (a.count === "moreThanMax") {
                return true;
            }
            else if (b.count === "moreThanMax") {
                return false;
            }
            else {
                return a.count - b.count;
            }
        });
    },

    /**
     * APIMethod: addFeatures
     * 聚散显示features,将需要聚散显示feature传给该方法,便可以实现聚散显示。
     *
     * Parameters:
     * features {Array(<SuperMap.Feature.Vector>)} - 需要聚散显示的feature
     *
     */
    addFeatures_backup: function (ps) {
        var isRefresh = arguments[1];
        if (!ps || (ps instanceof Array && ps.length == 0)) {
            return
        };

        //判断是否是刷新图层时调用该方法
        if (isRefresh === "isRefresh") {
            this.clusterPoints = ps;
        }
        else {
            ps = this.clusterPoints = (this.clusterPoints || []).concat(ps);
            this.isFeatureChanged = true;
        }

        //计算地图起始点,瓦片大小对应的地理范围(256×256),从而将地图切为一块一块的瓦片,聚合就是按照瓦片来聚合的。将同一瓦片中的点聚合到一起
        var tileSizeLonlat = this.getTileSizeLonlat();
        var origin = this.getOrigin();

        var curBounds = this.map.getExtent();
        var idx = this.getIdxOfBounds(curBounds, tileSizeLonlat, origin);
        var minRowIdx = idx.minRowIdx;
        var minColIdx = idx.minColIdx;
        var maxRowIdx = idx.maxRowIdx;
        var maxColIdx = idx.maxColIdx;
        var pointTileInfoArray = [];
        var displayedPoints = [];
        for (var i = 0; i < ps.length; i++) {
            var pointTileInfo = this.getPointTileIdx(ps[i], tileSizeLonlat, origin);
            var x = pointTileInfo[1];
            var y = pointTileInfo[0];
            if (minColIdx <= y && maxColIdx >= y) {
                if (minRowIdx <= x && maxRowIdx >= x) {
                    //var dl = this.displayedLevel;
                    var db = this.displayedBounds;
                    var f = pointTileInfo[2];
                    var g = f.geometry;
                    g = new SuperMap.LonLat(g.x, g.y);
                    if (db && db.containsLonLat(g)) {//&&dl!=null&&dl===this.map.getZoom()
                        displayedPoints.push(f);
                    }
                    else {
                        pointTileInfoArray.push(pointTileInfo);
                    }
                }
            }
        }
        var pointMap = [];
        for (var i = 0; i < pointTileInfoArray.length; i++) {
            var p = pointTileInfoArray[i];
            var y = p[0];
            var x = p[1];
            if (!pointMap[y]) {
                pointMap[y] = [];
            }
            var pmy = pointMap[y];
            if (pmy[x]) {
                pmy[x].push(p[2]);
            }
            else {
                pmy[x] = [p[2]];
            }
        }
        if (displayedPoints.length > 0) {
            pointMap["displayedPoints"] = displayedPoints;
        }
        this.drawPointMap(pointMap, minRowIdx, minColIdx, maxRowIdx, maxColIdx);

        this.pointMap = pointMap;
    },
    /**
     * APIMethod: addMoreFeatures
     * 聚散显示features,将需要聚散显示feature传给该方法,便可以实现聚散显示。
     *
     * Parameters:
     * features {Array(<SuperMap.Feature.Vector>)} - 需要聚散显示的feature
     *
     */
    addFeatures: function (ps) {
        
        var isRefresh = arguments[1];
        if (!ps || (ps instanceof Array && ps.length == 0)) {
            return
        };

        //判断是否是刷新图层时调用该方法
        if (isRefresh === "isRefresh") {
            // this.clusterPoints = this.clusterPoints.concat(ps);
            this.clusterPoints = ps;
        }
        else {
            ps = this.clusterPoints = (this.clusterPoints || []).concat(ps);
            this.isFeatureChanged = true;
        }

        //计算地图起始点,瓦片大小对应的地理范围(256×256),从而将地图切为一块一块的瓦片,聚合就是按照瓦片来聚合的。将同一瓦片中的点聚合到一起
        var tileSizeLonlat = this.getTileSizeLonlat();
        var origin = this.getOrigin();

        var curBounds = this.map.getExtent();
        var idx = this.getIdxOfBounds(curBounds, tileSizeLonlat, origin);
        var minRowIdx = idx.minRowIdx;
        var minColIdx = idx.minColIdx;
        var maxRowIdx = idx.maxRowIdx;
        var maxColIdx = idx.maxColIdx;
        var pointTileInfoArray = [];
        var displayedPoints = [];
        for (var i = 0; i < ps.length; i++) {
            var pointTileInfo = this.getPointTileIdx(ps[i], tileSizeLonlat, origin);
            var x = pointTileInfo[1];
            var y = pointTileInfo[0];
            if (minColIdx <= y && maxColIdx >= y) {
                if (minRowIdx <= x && maxRowIdx >= x) {
                    //var dl = this.displayedLevel;
                    var dbs = this.displayedBoundsExtent;
                    var f = pointTileInfo[2];
                    var g = f.geometry;
                    g = new SuperMap.LonLat(g.x, g.y);

                    var isIndbs = false;
                    for (var k = dbs.length; k--;) {
                        var db = dbs[k];
                        if (db && db.containsLonLat(g)) {//&&dl!=null&&dl===this.map.getZoom()
                            displayedPoints.push(f);
                            isIndbs = true;
                            break;
                        }
                    }
                    if(!isIndbs) {
                        pointTileInfoArray.push(pointTileInfo);
                    }
                }
            }
        }
        var pointMap = [];
        for (var i = 0; i < pointTileInfoArray.length; i++) {
            var p = pointTileInfoArray[i];
            var y = p[0];
            var x = p[1];
            if (!pointMap[y]) {
                pointMap[y] = [];
            }
            var pmy = pointMap[y];
            if (pmy[x]) {
                pmy[x].push(p[2]);
            }
            else {
                pmy[x] = [p[2]];
            }
        }
        if (displayedPoints.length > 0) {
            pointMap["displayedPoints"] = displayedPoints;
        }
        this.drawPointMap(pointMap, minRowIdx, minColIdx, maxRowIdx, maxColIdx);

        this.pointMap = pointMap;
    },

    /**
     * APIMethod: refresh
     * 刷新图层,清除当前已经绘制的feature,重新进行聚散计算并绘制。
     */
    refresh: function () {
        this.renderer.locked = true;
        this.clearCluster();
        this.renderer.locked = false;
        this.addFeatures(this.clusterPoints, "isRefresh");
    },

    /**
     * APIMethod: refresh
     * 刷新图层,清除当前已经绘制的feature,重新进行聚散计算并绘制。
     */
    refresh_backup: function () {
        this.renderer.locked = true;
        this.clearCluster();
        this.renderer.locked = false;
        this.addFeatures(this.clusterPoints, "isRefresh");
    },


    /**
     * APIMethod: displayMoreFeatures
     * 散开显示指定范围内的要素。
     *
     * Parameters:
     * bounds - {SuperMap.Bounds} 指定的范围,默认值为当前视图范围。
     */
    displayFeatures: function (bounds) {
        // this.displayedBounds = bounds||this.map.getExtent();
        this.displayedBoundsExtent.push(bounds);
        //this.displayedLevel = this.map.getZoom();

        this.refresh();
    },

    /**
     * APIMethod: displayFeatures
     * 散开显示指定范围内的要素。
     *
     * Parameters:
     * bounds - {SuperMap.Bounds} 指定的范围,默认值为当前视图范围。
     */
    displayFeatures_backup: function (bounds) {
        this.displayedBounds = bounds || this.map.getExtent();
        //this.displayedLevel = this.map.getZoom();

        this.refresh();
    },

    /**
     * APIMethod: cancelDisplayFeatures
     * 与displayFeatures方法相对应,还原该方法所显示的点。
     */
    cancelDisplayFeatures: function () {
        this.displayedBounds = null;
        this.displayedBoundsExtent = [];
        //this.displayedLevel = null;

        this.refresh();
    },
    /**
     * APIMethod: cancelDisplayMoreFeatures
     * 与displayFeatures方法相对应,还原该方法所显示的点。
     */
    cancelDisplayMoreFeatures: function () {
        this.displayedBounds = null;
        this.displayedBoundsExtent = [];
        
        this.refresh();
    },

    /**
     * APIMethod: getFeaturesByBounds
     * 获取指定范围内的所有要素。
     *
     * Parameters:
     * bounds {SuperMap.bounds} 地理范围
     *
     * Returns:
     * {Array<SuperMap.Feature.vector>}   要素数组
     */
    getFeaturesByBounds: function (bounds) {
        if (!this.pointMap || (this.pointMap.length && this.pointMap.length == 0)) {
            return [];
        }

        var pm = this.pointMap;
        var tileSizeLonlat = this.getTileSizeLonlat();
        var origin = this.getOrigin();

        var curBounds = this.map.getExtent();
        var idx = this.getIdxOfBounds(curBounds, tileSizeLonlat, origin);

        var fs = [];
        for (var y = idx.minColIdx; y <= idx.maxColIdx; y++) {
            if (pm[y]) {
                for (var x = idx.minRowIdx; x <= idx.maxRowIdx; x++) {
                    if (pm[y][x]) {
                        fs = fs.concat(pm[y][x]);
                    }
                }
            }
        }

        return fs;
    },

    /**
     * APIMethod: clearCluster
     * 清除当前视图中已经绘制的要素,但是不清空存储,当平移缩放操作时仍然会重绘
     * */
    clearCluster: function (key) {
        //this.destroyFeatures(this.toDrawFeatures);
        //this.destroyFeatures(this.openedPoints);

        this.removeAllFeatures("isFather");

        this.toDrawFeatures = null;
        if (key !== 123) {
            this.openedPoints = [];
            this.curOpenCluster = null;
        }
    },

    /**
     * APIMethod: destroyCluster
     * 彻底清除所有要素,平移缩放操作时不再重绘
     * */
    destroyCluster: function () {
        this.clearCluster();

        this.clusterPoints = null;
        this.pointMap = null;
        this.isFeatureChanged = true;
    },

    removeAllFeatures: function (isFather) {
        if (isFather === "isFather") {
            SuperMap.Layer.Vector.prototype.removeAllFeatures.apply(this);
        }
        else {
            this.destroyCluster();
        }
    },

    /**
     * APIMethod: assembleFeature
     * 组装散开后的要素,绘制之前会调用该方法,允许用户通过重写该方法自定义要素,通常在复杂要素的情况下使用,比如三叶草对象
     * (start code)
     * //创建一个名为“Cluster”的clusterLayer,并重写assembleFeature方法,重新组装要素
     * clusterLayer = new SuperMap.Layer.ClusterLayer("Cluster",{"assembleFeature":function(feature){
     *   var point = feature.geometry;
     *   var f1 = new SuperMap.Feature.Vector();
     *   f1.geometry = new SuperMap.Geometry.Point(point.x+10,point.y+10);
     *   var f2 = new SuperMap.Feature.Vector();
     *   f2.geometry = new SuperMap.Geometry.Point(point.x-10,point.y-10);
     *   return [f1,f2];
     * }});
     * (end)
     *
     * Parameters:
     * feature{SuperMap.Feature.Vector} 即将绘制的要素
     *
     * Returns:
     * {Array(<SuperMap.Feature.Vector>)}修改后的组合要素
     */
    assembleFeature: function (feature) { //每一个feature绘制之前都会调用该方法,用户可以重写该方法自定义样式
        var f = feature;
        f.style.strokeWidth = 1;

        return f;
    },

    removeFeatures: function (features) {
        if (!features || features.length === 0) {
            return;
        }
        if (features === this.features) {
            return this.removeAllFeatures("isFather");
        }
        if (!(SuperMap.Util.isArray(features))) {
            features = [features];
        }
        if (features === this.selectedFeatures) {
            features = features.slice();
        }
        var featuresFailRemoved = [];

        for (var i = features.length - 1; i >= 0; i--) {
            var feature = features[i];
            delete this.unrenderedFeatures[feature.id];
			var findex = SuperMap.Util.indexOf(this.clusterPoints, feature);
            if (findex === -1) {
                featuresFailRemoved.push(feature);
                continue;
            }
            this.clusterPoints.splice(findex, 1);
            //如果我们传入的feature在features数组中没有的话,则不进行删除,
            //并将其放入未删除的数组中。
            var findex = SuperMap.Util.indexOf(this.features, feature);

            if (findex === -1) {
                featuresFailRemoved.push(feature);
                continue;
            }
            this.features.splice(findex, 1);
            if (SuperMap.Util.indexOf(this.selectedFeatures, feature) !== -1) {
                SuperMap.Util.removeItem(this.selectedFeatures, feature);
            }
            // if(!this.features[feature.id]) {
            // featuresFailRemoved.push(feature);
            // continue;
            // }
            //delete this.features[feature.id];
        }

        //先清除再重绘。
        this.renderer.clear();
        // this.redraw();
        var drawFeatures = [];
        for (var hex = 0, len = this.features.length; hex < len; hex++) {
            feature = this.features[hex];
            drawFeatures.push(feature);
        }
        this.features = [];
        this._addFeatures(drawFeatures);

        var succeed = featuresFailRemoved.length == 0 ? true : false;
        this.events.triggerEvent("featuresremoved", { features: featuresFailRemoved, succeed: succeed });
    },

    /**
     * Method addFeaturesToCluster
     * 在原有要素的基础上,继续添加要素,并聚散显示
     *
     * Parameters:
     * features{Array<SuperMap.Feature.Vector>} 要素数组
     * */
    /*addFeaturesToCluster:function(fs){
        this.clusterPoints = this.clusterPoints.concat(fs);

        var tileSizeLonlat = this.getTileSizeLonlat();
        var origin = this.getOrigin();

        var curBounds = this.map.getExtent();
        var idx = this.getIdxOfBounds(curBounds,tileSizeLonlat,origin);
        var minRowIdx = idx.minRowIdx;
        var minColIdx = idx.minColIdx;
        var maxRowIdx = idx.maxRowIdx;
        var maxColIdx = idx.maxColIdx;

        var pointMap = this.pointMap;
        for(var i=0;i<fs.length;i++){
            var pointTileInfo = this.getPointTileIdx(fs[i],tileSizeLonlat,origin);
            var x = pointTileInfo[1];
            var y = pointTileInfo[0];
            if(minColIdx<=y&&maxColIdx>=y){
                if(minRowIdx<=x&&maxRowIdx>=x){
                    var p = pointTileInfo;
                    var y = p[0];
                    var x = p[1];
                    if(!pointMap[y]){
                        pointMap[y] = [];
                    }
                    var pmy = pointMap[y];
                    if(pmy[x]){
                        pmy[x].push(p[2]);
                    }
                    else{
                        pmy[x] = [p[2]];
                    }
                }
            }
        }

        this.drawPointMap(pointMap,minRowIdx,minColIdx,maxRowIdx,maxColIdx);
    },*/

    /**
     * Method: setMap
     * 图层已经添加到Map控件中。
     *
     * 如果没有设置renderer集合,这个图层将不可用,从map控件中删除,
     * 否则,给当前渲染器添加map的引用,并设置渲染器的大小。
     *
     * Parameters:
     * map - {<SuperMap.Map>}
     */
    setMap: function (map) {
        SuperMap.Layer.Vector.prototype.setMap.apply(this, arguments);
        if (this.isVML()) {
            this.map.events.register("movestart", this, function () {
                this.clearTimeout(this.drawAllTimeout);
                this.clearTimeout(this.drawDiffusePointTimeout);
                this.removeAllFeatures("isFather");
            });
        }
    },

    /**
     * Method: isVML
     * 判断Renderer对象是否是VML
     */
    isVML: function () {          //判断是否是VML的渲染方式,当ie8以下,采用vml渲染时,效率比较低,需要采用分批绘制的策略
        return (this.renderer.CLASS_NAME === "SuperMap.Renderer.VML")
    },

    /**
     * Method: moveTo
     * 重置当前矢量图层的div,再一次与Map控件保持一致。
     * 重新进行聚散计算并绘制
     */
    moveTo: function (bounds, zoomChange) {  //平移缩放时,需要重新计算并绘制聚合点
        this.renderer.locked = true;
        this.clearCluster(zoomChange ? null : 123);

        SuperMap.Layer.Vector.prototype.moveTo.apply(this, arguments);
        this.renderer.locked = this.curOpenCluster ? true : false;
        this.addFeatures(this.clusterPoints, "isRefresh");
        if (this.curOpenCluster) {      //采用vml渲染时,效率比较低,需要采用分批绘制的策略
            if (this.isVML()) {
                window.setTimeout(function (me) {
                    return function () {
                        me.addFeatures20(me.openedPoints, me.curOpenCluster.geometry, null, "drawDiffusePointTimeout");
                    }
                }(this), 100)
            }
            else {
                this.renderer.locked = false;
                this._addFeatures(this.openedPoints);
            }
        }
    },

    /**
     * Method: clickCluster
     * 点击聚散点所进行的操作
     *
     * Parameters:
     * feature {SuperMap.Feature.Vector} - 被点击的聚散点对象
     */
    clickCluster: function (f) {
        if (this.isDiffused) {
            try {
                var isVML = this.isVML();
                if (isVML) {
                    var ts = this.drawDiffusePointTimeout;
                    if (ts.length > 0) {
                        this.clearTimeout(ts);
                        this.clearOpenedPoints(this.lastOpenedPoints);
                    }
                }
                var ps, p, openedPoints;
                this.renderer.locked = true;
                if (this.curOpenCluster) {
                    //this.addFeatures([this.curOpenCluster]);
                    this.showOpenedCluster();
                    this.renderer.locked = true;
                    //this.curOpenCluster.style.display = "";
                    this.curOpenCluster = null;
                }
                if (!isVML) {
                    this.clearOpenedPoints(this.openedPoints);
                }
                else {
                    openedPoints = this.openedPoints.concat([]);
                    this.lastOpenedPoints = openedPoints;
                }
                this.openedPoints = [];
                ps = f.children;

                if (this.maxDiffuseAmount >= ps.length) {
                    for (var i = 0; i < ps.length; i++) {
                        p = this._makeFeature(ps[i], 0, "#0F9FF2", 2);
                        for (var j = 0; j < p.length; j++) {
                            p[j].isPoint = true;
                            this.openedPoints.push(p[j]);
                        }
                    }
                    this.curOpenCluster = f;
                    f.style.display = "none";
                    this.renderer.locked = false;
                    if (isVML) {
                        this.addFeatures20(this.openedPoints, null, function (fs, me) {
                            return function () {
                                me.clearOpenedPoints(fs);
                            }
                        }(openedPoints, this), "drawDiffusePointTimeout");
                    }
                    else {
                        this._addFeatures(this.openedPoints);
                    }
                }
                else {
                    if (isVML) {
                        this.clearOpenedPoints(openedPoints);
                    }
                }
                this.renderer.locked = false;
            }
            catch (e) { }
        }
    },

    /**
     * Method: clickoutCluster
     * 点击聚散点外的空白处所进行的操作
     */
    clickoutCluster: function () {
        try {
            var isVML = this.isVML();
            if (isVML) {
                var ts = this.drawDiffusePointTimeout;
                if (ts.length > 0) {
                    this.clearTimeout(ts);
                    this.clearOpenedPoints(this.lastOpenedPoints);
                }
            }

            //this.clearTimeout(this.drawDiffusePointTimeout);
            //this.renderer.locked = true;
            //this.curOpenCluster.style.display = "";
            this.showOpenedCluster();
            this.clearOpenedPoints(this.openedPoints);
            this.openedPoints = [];
            //this.renderer.locked = false;
            //var f = this.makeCluster(this.curOpenCluster.children)

            //this.addFeatures([this.curOpenCluster]);
            this.curOpenCluster = null;
        } catch (e) { }
    },
    /**
     * Method: showOpenedCluster
     * 显示刚才由于散开而隐藏的聚散点
     */
    showOpenedCluster: function () {
        if (this.curOpenCluster) {
            if (this.curOpenCluster.style.display === "none") {
                this.curOpenCluster.style.display = "";
            }
            else {
                this.renderer.locked = true;
                this._addFeatures([this.curOpenCluster]);
                this.renderer.locked = false;
            }
        }
    },

    /**
     * Method: getIdxOfBounds
     * 根据网格算出一个bounds各个边所在网格的索引值
     */
    getIdxOfBounds: function (bounds, tileSizeLonlat, origin) {
        var topLeft = { "x": bounds.left, "y": bounds.top };
        var rightBottom = { "x": bounds.right, "y": bounds.bottom };

        var a = this.getPointTileIdx(topLeft, tileSizeLonlat, origin);
        var minRowIdx = a[1];
        var minColIdx = a[0];
        a = this.getPointTileIdx(rightBottom, tileSizeLonlat, origin);
        var maxRowIdx = a[1];
        var maxColIdx = a[0];

        return {
            "minRowIdx": minRowIdx,
            "minColIdx": minColIdx,
            "maxRowIdx": maxRowIdx,
            "maxColIdx": maxColIdx
        };
    },

    /**
     * Method: getTileSizeLonlat
     * 计算每个网格在当前比例尺下的地理范围
     */
    getTileSizeLonlat: function () {
        var level = this.map.getZoom();
        var levelResolution = this.map.getResolutionForZoom(level);

        var tileSize = {
            "w": this.tolerance * 2,
            "h": this.tolerance * 2
        }
        var tileSizeLonlat = { "w": tileSize.w * levelResolution, "h": tileSize.h * levelResolution };

        return tileSizeLonlat;
    },

    /**
     * Method: getOrigin
     * 获取地图的地理上的左上角点
     */
    getOrigin: function () {
        if (!this.origin) {
            var maxBounds = this.map.getMaxExtent();
            this.origin = { "x": maxBounds.left, "y": maxBounds.top };
        }

        return this.origin;
    },

    /**
     * Method: isMaxLeve
     * 判断当前比例尺是不是最大比例尺
     *
     * Returens:
     * {Boolean} 是否是最大级别
     * */
    isMaxLeve: function () {
        var is = false;
        try {
            var curZoom = this.map.getZoom();
            var length = this.map.baseLayer.resolutions.length;
            if (this.maxLevel != null) {
                length = this.maxLevel + 1;
            }

            if (curZoom && length) {
                if (curZoom >= length - 1) {
                    is = true;
                }
            }
        }
        catch (e) { }
        return is;
    },

    /**
     * Method: drawPointMap
     * 将pointMap中的要素绘制渲染出来。
     *
     * Parameters:
     * pointMap{Object<SuperMap.Feature.Vector>} pointMap对象
     */
    drawPointMap: function (pointMap, minRowIdx, minColIdx, maxRowIdx, maxColIdx) {
        if (this.noDrawClusters) {
            return;
        }

        var isMaxLeve = this.isMaxLeve();
        var toDrawFeatures = [];

        var clusterPoints = [];
        for (var i = minColIdx; i <= maxColIdx; i++) {
            if (pointMap[i]) {//&&minColIdx<=i&&maxColIdx>=i
                for (var j = minRowIdx; j <= maxRowIdx; j++) {
                    if (pointMap[i][j]) {//&&minRowIdx<=j&&maxRowIdx>=j
                        var points = pointMap[i][j];

                        // if(points.length>=2&&!isMaxLeve){
                        if (points.length >= 1 && !isMaxLeve) {
                            var f = this.makeCluster(points);
                            clusterPoints.push(f);
                            if (this.curOpenCluster) {
                                var g1 = this.curOpenCluster.geometry;
                                var g2 = f.geometry;
                                if (g1.x === g2.x && g1.y === g2.y) {
                                    this.curOpenCluster = f;
                                    f = null;
                                }
                            }
                            if (f) {
                                toDrawFeatures = toDrawFeatures.concat(f);
                            }
                        }
                        else {
                            //                            for(var l=0;l<points.length;l++){
                            //                                var f = this._makeFeature(points[l],0,"#0F9FF2",4);
                            //                                for(var k=0;k< f.length;k++){
                            //                                    f[k].isPoint = true;
                            //                                    toDrawFeatures.push(f[k]);
                            //                                }
                            //                            }
                            toDrawFeatures = preparePoints(points, toDrawFeatures, this);
                            //toDrawFeatures = toDrawFeatures.concat(f);
                        }
                    }
                }
            }
        }
        var displayedPoints = pointMap["displayedPoints"];

        var clusterInfo = { clusterPoints: clusterPoints, displayedPoints: displayedPoints };         //clusterInfo包含了聚散完成所需要的信息,其结构如下clusterInfo={clusterPoints:[],displayedPoints:[],element:null,object:null,type:"clusterEnd"}
        //其中,clusterMaps是包含了聚散点映射关系集合,clusterPoints[i]则表示第i个聚散点映射关系,其类型为{SuperMap.Feature.Vector},其内的children属性包含有对应的实际点坐标
        //而displayedPoints则是用户所设定的某一范围内不需要被聚散的点集合
        this.events.triggerEvent("clusterend", clusterInfo);     //触发聚散完成事件

        if (displayedPoints && displayedPoints.length > 0) {
            toDrawFeatures = preparePoints(displayedPoints, toDrawFeatures, this);
        }

        if (this.toDrawFeatures) {
            this.removeFeatures(this.toDrawFeatures);
        }
        this.toDrawFeatures = toDrawFeatures;
        if (this.isVML()) {
            this.addFeatures20(toDrawFeatures, null, null, "drawAllTimeout");
        } else {
            this._addFeatures(toDrawFeatures);
        }

        function preparePoints(points, toDrawFeatures, me) {
            for (var l = 0; l < points.length; l++) {
                var f = me._makeFeature(points[l], 0, "#0F9FF2", 4);
                for (var k = 0; k < f.length; k++) {
                    f[k].isPoint = true;
                    toDrawFeatures.push(f[k]);
                }
            }

            return toDrawFeatures;
        }
    },

    /**
     * Method: _addFeatures
     * 给这个图层添加features,非聚散的形式显示。
     *
     * Parameters:
     * features - {Array(<SuperMap.Feature.Vector>)}
     */
    _addFeatures: function (features, options) {
        if (!(SuperMap.Util.isArray(features))) {
            features = [features];
        }

        var notify = !options || !options.silent;
        if (notify) {
            var event = { features: features };
            var ret = this.events.triggerEvent("beforefeaturesadded", event);
            if (ret === false) {
                return;
            }
            features = event.features;
        }

        var featuresFailAdded = [];
        this.renderer.locked = true;

        for (var i = 0, len = features.length; i < len; i++) {
            if (i === (len - 1)) {
                this.renderer.locked = false;
            }
            var feature = features[i];
            //如果设置了类型限制,则判断他。
            if (this.geometryType &&
                !(feature.geometry instanceof this.geometryType)) {
                throw new TypeError('addFeatures: component should be an ' +
                    this.geometryType.prototype.CLASS_NAME);
            }
            //给feature当前图层的引用。
            feature.layer = this;

            if (!feature.style && this.style) {
                feature.style = SuperMap.Util.extend({}, this.style);
            }

            // this.features[feature.id] = feature;
            this.features.push(feature);

            this.modifyVMLLabel(feature);
            //此时的feature是新添加的feature。
            var drawn = this.drawFeature(feature, undefined, { isNewAdd: true });

            this.drawTextVML(feature, drawn);
            //设置label的鼠标样式
            this.renderer.textRoot.style.cursor = "pointer";

            //如果当前feature不可被绘制则加入到featuresFailAdded数组中。
            if (!drawn) {
                featuresFailAdded.push(feature);
            }
        }
        var succeed = featuresFailAdded.length == 0 ? true : false;
        this.events.triggerEvent("featuresadded", { features: featuresFailAdded, succeed: succeed });
    },

    /**
     * Method: addFeatures20
     * 给这个图层添加features,分批添加,一次十个,VML下有效。
     *
     * Parameters:
     * fs - {Array(<SuperMap.Feature.Vector>)}
     * center - {SuperMap.Geometry.Point} 这些feature的中心点,会根据距离中心的距离对features进行排序
     * callback - {Funciton} 将所有点绘制完成后的回调函数
     * timeout - {String} 存储timeout函数的句柄的字段名称
     */
    addFeatures20: function (fs, center, callback, timeout) {
        var fs1 = fs.concat([]);
        if (center) {
            center = {
                "lon": center.x,
                "lat": center.y
            };
        }
        var c = center || this.map.getCenter();
        fs1.sort(function (c) {
            return function (a, b) {
                return Math.abs(a.geometry.getBounds().left - c.lon) - Math.abs(b.geometry.getBounds().left - c.lon);
            }
        }(c));

        fs1.sort(function (a, b) {
            var s1 = a.style;
            var s2 = b.style;
            s1.zIndex_c = s1.zIndex_c || 0;
            s2.zIndex_c = s2.zIndex_c || 0;
            return s1.zIndex_c - s2.zIndex_c;
        });
        add(fs1, this, callback, timeout);
        function add(fs, me, callback, timeout) {
            if (fs.length > 0) {
                var fs1 = [];
                for (var i = 0; i < 10; i++) {
                    var f = fs.shift();
                    if (f) {
                        fs1.push(f);
                    }
                    else break;
                }
                me._addFeatures(fs1);
                time(fs, add, me, callback, timeout);
            }
            else {
                if (callback) {
                    callback();
                }
                me[timeout] = [];
            }
        }

        function time(fs, fun, me, callback, timeout) {
            var stt = window.setTimeout(function (fs, fun, me, callback, timeout) {
                return function () {
                    fun(fs, me, callback, timeout);
                }
            }(fs, fun, me, callback, timeout), 14);
            me[timeout].push(stt);
        }
    },

    /**
     * Method: clearTimeout
     * 清除timeout
     *
     * Parameters:
     * ts - {Array(<Object>)} 存储timeout句柄的数组
     */
    clearTimeout: function (ts) {
        //var ds = this.drawTimeout;
        for (var i = 0; i < ts.length; i++) {
            window.clearTimeout(ts[i]);
        }
        ts = [];
    },

    /**
     * Method: drawTextVML
     * 修改VML下的标签的绘制方式,提高效率。
     *
     * Parameters:
     * feature - {SuperMap.Feature.Vector} 存储timeout句柄的数组\
     * drawn - {HTMLDOMElement} 绘制好的DOM对象
     */
    drawTextVML: function (feature, drawn) {
        var fsy = feature.style;
        if (fsy) {
            var l = fsy.clusterLabel;
            if (l && drawn) {
                var sizeH = fsy.pointRadius ? fsy.pointRadius * 2 : (fsy.graphicWidth ? fsy.graphicWidth : fsy.backgroundWidth);
                var sizeW = fsy.pointRadius ? fsy.pointRadius * 2 : (fsy.graphicHeight ? fsy.graphicHeight : fsy.backgroundHeight);
                //                if(fsy.graphicWidth&&fsy.graphicWidth>sizeW){
                //                    sizeW = fsy.graphicWidth;
                //                }
                //                if(fsy.graphicHeight&&fsy.graphicHeight>sizeH){
                //                    sizeH = fsy.graphicHeight;
                //                }
                //                if(fsy.backgroundWidth&&fsy.backgroundWidth>sizeW){
                //                    sizeW = fsy.backgroundWidth;
                //                }
                //                if(fsy.backgroundHeight&&fsy.backgroundHeight>sizeH){
                //                    sizeH = fsy.backgroundHeight;
                //                }
                var sp = document.createElement("span");
                var s = sp.style;
                s.textAlign = "center";
                s.lineHeight = sizeH + "px";
                s.width = sizeW + "px";
                s.display = "inline-block";
                s.color = fsy.fontColor || "#000";
                if (fsy.labelXOffset || fsy.labelYOffset) {
                    s.position = "relative";
                    if (fsy.labelXOffset) {
                        s.left = fsy.labelXOffset + "px";
                    }
                    if (fsy.labelYOffset) {
                        s.top = (-1 * fsy.labelYOffset) + "px";
                    }
                }
                sp._featureId = feature.id;
                sp._geometryClass = feature.geometry.CLASS_NAME;
                var txt = document.createTextNode(l);
                sp.appendChild(txt);
                drawn.appendChild(sp);
            }
        }
    },

    /**
     * Method: drawTextVML
     * 修改VML下的标签的绘制方式,提高效率。
     */
    modifyVMLLabel: function (feature) {
        if (this.isVML() && feature.isCluster) {//icl526
            var s = feature.style;
            if (s) {
                var label = s.label;
                if (label) {
                    s.label = null;
                    s.labelSelect = null;
                    s.clusterLabel = label;
                }
            }
        }
    },

    /**
     * Method: makeCluster
     * 组织创建cluster对象
     *
     * Parameters:
     * points{Array<SuperMap.Feature.Vector>} 需要聚散在一起的要素数组
     *
     * Returns:
     * {SuperMap.Feature.Vector} 组织好的cluster要素
     */
    makeCluster: function (points) {
        var center = this.getTileCenter(points);
        var f, me = this;


        for (var i = 0; i < this.clusterStyles.length; i++) {
            var a = this.clusterStyles[i];
            if (a.count === "moreThanMax") {
                if(this.showFieldName){
                    var value = 0;
                    for(var pointIndex = 0,pointLength = points.length;pointIndex<pointLength;pointIndex++){
                        if(points[pointIndex]["attributes"][this.showFieldName]){
                            value += points[pointIndex]["attributes"][this.showFieldName]/1;
                        }
                    }
                    f = createCluster(center, a.style, value.toFixed(0), points, this);
                }else{
                    f = createCluster(center, a.style, points.length, points, this);
                }

            }
            else {
                if (a.count >= points.length) {
                    //f = a.getFeature(center,points);
                    if(this.showFieldName){
                        var value = 0;
                        for(var pointIndex = 0,pointLength = points.length;pointIndex<pointLength;pointIndex++){
                            if(points[pointIndex]["attributes"][this.showFieldName]){
                                value += points[pointIndex]["attributes"][this.showFieldName]/1;
                            }
                        }
                        f = createCluster(center, a.style, value.toFixed(0), points, this);
                    }else{
                        f = createCluster(center, a.style, points.length, points, this);
                    }
                    break;
                }
            }
        }

        return f;

        function createCluster(center, style, count, children, me) {
            var f = new SuperMap.Feature.Vector();
            f.geometry = new SuperMap.Geometry.Point(center.x, center.y);
            //f.geometry = new SuperMap.Geometry.Rectangle(center.x, center.y, s, s);
            f.style = SuperMap.Util.JSONClone(null, style);
            if (count||count == 0) {
                f.style.label = count + "";
                f.style.labelSelect = true;
                //                var bro = SuperMap.Util.getBrowser();
                //                if(bro.name==="msie"&&bro.version==="9.0"){
                //                    if(f.style.labelYOffset==undefined){
                //                        f.style.labelYOffset = -5;
                //                    }
                //                    else{
                //                        f.style.labelYOffset += -5;
                //                    }
                //                }
            }
            if (children) {
                f.children = children;
                f.isCluster = true;
            }

            if (me.isVML() && (style.externalGraphic || style.backgroundGraphic)) {
                f.style.fillColor = "none";
            }

            return f;
        }
    },

    /**
     * Method:_makeFeature
     * 内部方法,组织要素的样式
     *
     * Parameters:
     * point {SuperMap.Feature.Vector} 即将要绘制的要素
     * count {Number} 若该要素是聚散点,则表示该聚散点聚散了多少个小点
     * color {String} 颜色值
     * radius {Number} 半径
     * ps {Array<SuperMap.Feature.Vector>} 聚散的小点数组
     *
     * Returns:
     * {SuperMap.Feature.Vector} 组织好的要素
     * */
    _makeFeature: function (point, count, color, radius, ps) {
        if (point.geometry) {
            var f1 = this.assembleFeature(point);
            if (f1.length) {
                var f = [];
                for (var i = 0; i < f1.length; i++) {
                    var f2 = f1[i].clone();
                    f2.isPoint = true;
                    f2.info = f1[i].info;
                    f2.attributes = f1[i].attributes;
                    f.push(f2);
                }
            }
            else {
                var f2 = f1.clone();
                f2.isPoint = true;
                f2.info = f1.info;
                f2.attributes = f1.attributes;
                var f = [f2];
            }
        }
        else {
            var f = new SuperMap.Feature.Vector();
            f.geometry = new SuperMap.Geometry.Point(point.x, point.y);
            f.style = {
                strokeColor: "#fff",
                strokeOpacity: 0.8,
                strokeDashstyle: "solid",
                fillColor: color || "#00f",
                //                pointRadius: radius||5,
                fillOpacity: 0.7,
                fontColor: "#fff"
            };
            f.style.strokeWidth = 1;
            if (count) {
                f.style.label = count + "";
                //                var bro = SuperMap.Util.getBrowser();
                //                if(bro.name==="msie"&&bro.version==="9.0"){
                //                    if(f.style.labelYOffset==undefined){
                //                        f.style.labelYOffset = -5;
                //                    }
                //                    else{
                //                        f.style.labelYOffset += -5;
                //                    }
                //                }
            }
            if (ps) {
                f.children = ps;
                f.isCluster = true;
            }
            f = [f];
        }
        //this.renderer.drawFeature(f);
        return f;
    },

    /**
     * Method:clearOpenedPoints
     * 清除已经散开的要素
     * */
    clearOpenedPoints: function (fs) {
        if (fs && fs.length > 0) {
            //var fs = this.openedPoints.concat([]);
            //            window.setTimeout(function(fs,me){
            //                return function(){
            //                    me.removeFeatures(fs);
            //                }
            //            }(fs,this),100);
            this.removeFeatures(fs);
            //this.openedPoints = [];
        }
    },

    /**
     * Method:getPointTileIdx
     * 计算一个要素在网格中的索引值
     *
     * Parameters:
     * feature {SuperMap.Feature.Vector} feature对象
     * size {SuperMap.Size} 每个网格的大小
     * origin {SuperMap.Feature.Point} 地图的起始点
     *
     * returns:
     * {Array<Object>} 描述索引信息的数组
     * */
    getPointTileIdx: function (feature, size, origin) {
        var point = feature.geometry || feature;
        var x = Math.floor((point.x - origin.x) / size.w);
        var y = Math.floor((origin.y - point.y) / size.h);

        return [y, x, feature];
    },

    /**
     * Method:getTileCenter
     * 获取一个组要素的中心点,作为聚散点的坐标
     *
     * Parameters:
     * points {Array<SuperMap.Feature.Vector>} 被聚散的feature对象
     *
     * returns:
     * {SuperMap.Feature.Vector} 中心点
     * */
    getTileCenter: function (points) {
        var f = points[0];
        f = f.geometry;
        var len = points.length;
        var x = f.x;
        var y = f.y;
        for (var i = 1; i < len; i++) {
            x = x + points[i].geometry.x;
            y = y + points[i].geometry.y;
        }
        x = x / len;
        y = y / len;
        return { x: x, y: y };
    },

    getDataExtent: function () {
        if (this.isFeatureChanged) {
            this.isFeatureChanged = false;
            var maxExtent = null;
            var features = this.clusterPoints;
            if (features) {
                var geometry = null;
                for (var id in features) {
                    geometry = features[id].geometry;
                    if (geometry) {
                        if (maxExtent === null) {
                            maxExtent = new SuperMap.Bounds();
                        }
                        maxExtent.extend(geometry.getBounds());
                    }
                }
            }
            this.dataExtent = maxExtent;
        }

        return this.dataExtent;
    },

    CLASS_NAME: "SuperMap.Layer.ClusterLayer"
});