"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Choropleth = void 0;
var tslib_1 = require("tslib");
var util_1 = require("@antv/util");
var plot_1 = require("../../core/plot");
var utils_1 = require("../../utils");
var constants_1 = require("./constants");
var area_layer_1 = require("../../layers/area-layer");
var text_layer_1 = require("../../layers/text-layer");
var types_1 = require("../../types");
var layer_group_1 = require("../../core/layer/layer-group");
var layer_1 = require("./layer");
var cache_1 = require("./cache");
var helper_1 = require("./helper");
var Choropleth = /** @class */ (function (_super) {
    (0, tslib_1.__extends)(Choropleth, _super);
    function Choropleth() {
        var _this = _super !== null && _super.apply(this, arguments) || this;
        /**
         * 图表类型
         */
        _this.type = plot_1.Plot.PlotType.Choropleth;
        /**
         * 国界数据
         */
        _this.chinaBoundaryData = { type: 'FeatureCollection', features: [] };
        /**
         * 当前行政数据数据
         */
        _this.currentDistrictData = { type: 'FeatureCollection', features: [] };
        /**
         * 数据钻取路径
         */
        _this.drillSteps = [];
        /**
         * 钻取行政栈数据
         */
        _this.drillStacks = [];
        /**
         * 向下钻取事件回调
         */
        _this.onDrillDownHander = function (event) {
            var _a;
            var _b = _this.options.drill, steps = _b.steps, onDown = _b.onDown;
            var properties = (_a = event.feature) === null || _a === void 0 ? void 0 : _a.properties;
            var adcode = properties.adcode;
            // 还没有开始钻取
            if (!_this.drillStacks.length) {
                var _c = _this.options.viewLevel, level_1 = _c.level, adcode_1 = _c.adcode, _d = _c.granularity, granularity_1 = _d === void 0 ? constants_1.DEFAULT_AREA_GRANULARITY[level_1] : _d;
                var config = (0, helper_1.getDrillStepDefaultConfig)(_this.options);
                _this.drillStacks = [{ level: level_1, adcode: adcode_1, granularity: granularity_1, config: config }];
            }
            // 已经下钻到最后
            if (_this.drillStacks.length === steps.length + 1) {
                return;
            }
            // 已开始下钻
            var from = _this.drillStacks.slice(-1)[0];
            var depth = _this.drillStacks.length - 1;
            var _e = _this.drillSteps[depth], level = _e.level, _f = _e.granularity, granularity = _f === void 0 ? constants_1.DEFAULT_AREA_GRANULARITY[level] : _f, drillConfig = (0, tslib_1.__rest)(_e, ["level", "granularity"]);
            var downParams = {
                from: { level: from.level, adcode: from.adcode, granularity: from.granularity },
                to: { level: level, adcode: adcode, granularity: granularity, properties: properties },
            };
            var callback = function (config) {
                if (config === void 0) { config = {}; }
                var view = { level: level, adcode: adcode, granularity: granularity };
                var mergeConfig = (0, utils_1.deepAssign)({}, drillConfig, config);
                _this.changeView(view, mergeConfig).then(function (drillData) {
                    if (drillData) {
                        _this.drillStacks.push(drillData);
                        _this.emit('drilldown', downParams);
                    }
                });
            };
            if (onDown) {
                onDown(downParams.from, downParams.to, callback);
            }
            else {
                callback();
            }
        };
        /**
         * 向上钻取事件回调
         */
        _this.onDrillUpHander = function () {
            var onUp = _this.options.drill.onUp;
            // 已经上卷到最高层级
            var isTopDrillStack = _this.drillStacks.length === 0 || _this.drillStacks.length === 1;
            if (isTopDrillStack) {
                return;
            }
            var lastIndex = _this.drillStacks.length - 1;
            var from = _this.drillStacks[lastIndex];
            var to = _this.drillStacks[lastIndex - 1];
            var upParams = {
                from: { level: from.level, adcode: from.adcode, granularity: from.granularity },
                to: { level: to.level, adcode: to.adcode, granularity: to.granularity },
            };
            var callback = function (config) {
                if (config === void 0) { config = {}; }
                var view = upParams.to;
                var mergeConfig = (0, utils_1.deepAssign)({}, to.config, config);
                _this.changeView(view, mergeConfig).then(function (drillData) {
                    if (drillData) {
                        _this.drillStacks.pop();
                        _this.emit('drillup', upParams);
                    }
                });
            };
            if (onUp) {
                onUp(upParams.from, upParams.to, callback);
            }
            else {
                callback();
            }
        };
        return _this;
    }
    /**
     * 初始化图层
     */
    Choropleth.prototype.initLayers = function () {
        var _this = this;
        this.getInitDistrictData().then(function () {
            _this.source = _this.createSource();
            _this.render();
            _this.inited = true;
        });
    };
    /**
     * 渲染
     */
    Choropleth.prototype.render = function () {
        console.time('l7plot choropleth render time');
        if (this.inited) {
            this.updateLayers(this.options);
            // this.scene.render()
            this.updateComponents();
        }
        else {
            var layerGroup = this.createLayers(this.source);
            this.layerGroup = layerGroup;
            this.onLayersLoaded();
            layerGroup.addTo(this.scene);
        }
        this.initLayersEvent();
        console.timeEnd('l7plot choropleth render time');
    };
    /**
     * 更新: 更新配置且重新渲染
     */
    Choropleth.prototype.update = function (options) {
        var _this = this;
        var _a, _b, _c;
        this.updateOption(options);
        if (options.map && !(0, util_1.isEqual)(this.lastOptions.map, this.options.map)) {
            this.updateMap(options.map);
        }
        // 下钻路径发生更新
        if (options.drill &&
            options.drill.enabled !== false &&
            !(0, util_1.isEqual)((_a = this.lastOptions.drill) === null || _a === void 0 ? void 0 : _a.steps, (_b = this.options.drill) === null || _b === void 0 ? void 0 : _b.steps)) {
            this.drillReset();
        }
        // 行政级别及范围发生更新
        if (options.viewLevel && !(0, util_1.isEqual)(this.lastOptions.viewLevel, this.options.viewLevel)) {
            var geoData = (_c = options.source) === null || _c === void 0 ? void 0 : _c.joinBy.geoData;
            console.time('l7plot choropleth update viewLevel time');
            this.getDistrictData(geoData).then(function () {
                var _a = _this.options.source, data = _a.data, sourceConfig = (0, tslib_1.__rest)(_a, ["data"]);
                _this.changeData(data, sourceConfig);
                _this.render();
                console.timeEnd('l7plot choropleth update viewLevel time');
                _this.emit('update');
            });
        }
        else {
            if (options.source && !(0, util_1.isEqual)(this.lastOptions.source, this.options.source)) {
                var _d = this.options.source, data = _d.data, sourceConfig = (0, tslib_1.__rest)(_d, ["data"]);
                this.changeData(data, sourceConfig);
            }
            this.render();
            this.emit('update');
        }
    };
    /**
     * 获取默认配置
     */
    Choropleth.prototype.getDefaultOptions = function () {
        return Choropleth.DefaultOptions;
    };
    /**
     * 解析 source 配置
     */
    Choropleth.prototype.parserSourceConfig = function (source) {
        var joinData = source.data, joinBy = source.joinBy, sourceCFG = (0, tslib_1.__rest)(source, ["data", "joinBy"]);
        var sourceField = joinBy.sourceField, targetField = joinBy.geoField, geoData = joinBy.geoData;
        var data = geoData;
        var config = { type: 'join', sourceField: sourceField, targetField: targetField, data: joinData };
        if (sourceCFG.transforms) {
            sourceCFG.transforms.push(config);
        }
        else {
            sourceCFG.transforms = [config];
        }
        if (sourceCFG['parser']) {
            delete sourceCFG['parser'];
        }
        return { data: data, sourceCFG: sourceCFG };
    };
    /**
     * 创建 source 实例
     */
    Choropleth.prototype.createSource = function () {
        var _a = this.parserSourceConfig(this.options.source), data = _a.data, sourceCFG = _a.sourceCFG;
        var source = new types_1.Source(data, sourceCFG);
        return source;
    };
    /**
     * 更新: 更新数据
     */
    Choropleth.prototype.changeData = function (data, cfg) {
        console.time('l7plot choropleth update data time');
        this.options.source = (0, utils_1.deepAssign)({}, this.options.source, (0, tslib_1.__assign)({ data: data }, cfg));
        var _a = this.parserSourceConfig(this.options.source), geoData = _a.data, sourceCFG = _a.sourceCFG;
        this.source.setData(geoData, sourceCFG);
        console.timeEnd('l7plot choropleth update data time');
        // 更新 legend
        if (this.options.legend) {
            this.updateLegendControl(this.options.legend);
        }
        this.emit('change-data');
    };
    /**
     * 创建图层
     */
    Choropleth.prototype.createLayers = function (source) {
        this.fillAreaLayer = new area_layer_1.AreaLayer((0, tslib_1.__assign)({ name: 'fillAreaLayer', source: source }, (0, util_1.pick)(this.options, area_layer_1.AreaLayer.LayerOptionsKeys)));
        var layerGroup = new layer_group_1.LayerGroup([this.fillAreaLayer]);
        if (this.options.chinaBorder) {
            var _a = (0, layer_1.createCountryBoundaryLayer)(this.chinaBoundaryData, this.options), chinaBoundaryLayer = _a.chinaBoundaryLayer, chinaDisputeBoundaryLayer = _a.chinaDisputeBoundaryLayer;
            this.chinaBoundaryLayer = chinaBoundaryLayer;
            this.chinaDisputeBoundaryLayer = chinaDisputeBoundaryLayer;
            layerGroup.addLayer(this.chinaBoundaryLayer);
            layerGroup.addLayer(this.chinaDisputeBoundaryLayer);
        }
        if (this.options.label) {
            this.labelLayer = this.createLabelLayer(source, this.options.label);
            layerGroup.addLayer(this.labelLayer);
        }
        return layerGroup;
    };
    /**
     * 创建数据标签图层
     */
    Choropleth.prototype.createLabelLayer = function (source, label) {
        var _this = this;
        var data = source['originData'].features
            .map(function (_a) {
            var properties = _a.properties;
            return Object.assign({}, properties, { centroid: properties['centroid'] || properties['center'] });
        })
            .filter(function (_a) {
            var centroid = _a.centroid;
            return centroid;
        });
        var _a = this.options, visible = _a.visible, minZoom = _a.minZoom, maxZoom = _a.maxZoom, _b = _a.zIndex, zIndex = _b === void 0 ? 0 : _b;
        var textLayer = new text_layer_1.TextLayer((0, tslib_1.__assign)({ name: 'labelLayer', source: {
                data: data,
                parser: { type: 'json', coordinates: 'centroid' },
                transforms: source.transforms,
            }, visible: visible, minZoom: minZoom, maxZoom: maxZoom, zIndex: zIndex + 0.1 }, label));
        source.on('update', function () {
            var data = _this.source['originData'].features
                .map(function (_a) {
                var properties = _a.properties;
                return properties;
            })
                .filter(function (_a) {
                var centroid = _a.centroid;
                return centroid;
            });
            textLayer.layer.setData(data);
        });
        return textLayer;
    };
    /**
     * 更新图层
     */
    Choropleth.prototype.updateLayers = function (options) {
        var fillAreaLayerConfig = (0, util_1.pick)(options, area_layer_1.AreaLayer.LayerOptionsKeys);
        this.fillAreaLayer.update(fillAreaLayerConfig);
        if (options.chinaBorder) {
            if (!this.chinaBoundaryLayer) {
                var _a = (0, layer_1.createCountryBoundaryLayer)(this.chinaBoundaryData, this.options), chinaBoundaryLayer = _a.chinaBoundaryLayer, chinaDisputeBoundaryLayer = _a.chinaDisputeBoundaryLayer;
                this.chinaBoundaryLayer = chinaBoundaryLayer;
                this.chinaDisputeBoundaryLayer = chinaDisputeBoundaryLayer;
                this.layerGroup.addLayer(this.chinaBoundaryLayer);
                this.layerGroup.addLayer(this.chinaDisputeBoundaryLayer);
            }
        }
        else {
            if (this.chinaBoundaryLayer) {
                this.layerGroup.removeLayer(this.chinaBoundaryLayer);
            }
            if (this.chinaDisputeBoundaryLayer) {
                this.layerGroup.removeLayer(this.chinaDisputeBoundaryLayer);
            }
        }
        if (options.label) {
            if (this.labelLayer) {
                this.labelLayer.update((0, tslib_1.__assign)({}, options.label));
            }
            else {
                this.labelLayer = this.createLabelLayer(this.source, options.label);
                this.layerGroup.addLayer(this.labelLayer);
            }
        }
        else {
            if (this.labelLayer) {
                this.layerGroup.removeLayer(this.labelLayer);
            }
        }
    };
    /**
     * 初始化图层事件
     */
    Choropleth.prototype.initLayersEvent = function () {
        this.initDrillEvent();
    };
    /**
     * 初始化钻取事件
     */
    Choropleth.prototype.initDrillEvent = function () {
        // 更新：取消上次绑定事件
        if (this.lastOptions.drill) {
            var _a = this.lastOptions.drill, _b = _a.triggerUp, triggerUp_1 = _b === void 0 ? 'unclick' : _b, _c = _a.triggerDown, triggerDown_1 = _c === void 0 ? 'click' : _c;
            this.fillAreaLayer.off(triggerUp_1, this.onDrillUpHander);
            this.fillAreaLayer.off(triggerDown_1, this.onDrillDownHander);
        }
        // 没有下钻
        if (!this.options.drill || this.options.drill.enabled === false) {
            return;
        }
        var _d = this.options.drill, steps = _d.steps, _e = _d.triggerUp, triggerUp = _e === void 0 ? 'unclick' : _e, _f = _d.triggerDown, triggerDown = _f === void 0 ? 'click' : _f;
        var dillSteps = steps.map(function (step) {
            if (typeof step === 'string') {
                return {
                    level: step,
                    granularity: constants_1.DEFAULT_AREA_GRANULARITY[step],
                };
            }
            if (!step.granularity) {
                step.granularity = constants_1.DEFAULT_AREA_GRANULARITY[step.level];
            }
            return step;
        });
        // 初始化或钻取路径更新时
        if (!(0, helper_1.isEqualDrillSteps)(dillSteps, this.drillSteps)) {
            this.drillSteps = dillSteps;
            this.drillStacks = [];
        }
        // 上卷事件
        this.fillAreaLayer.on(triggerUp, this.onDrillUpHander);
        // 下钻事件
        this.fillAreaLayer.on(triggerDown, this.onDrillDownHander);
    };
    /**
     * 重置钻取缓存数据
     */
    Choropleth.prototype.drillReset = function () {
        this.drillStacks = [];
    };
    /**
     * 实现 legend 配置项
     */
    Choropleth.prototype.getLegendOptions = function () {
        var colorLegendItems = this.fillAreaLayer.getColorLegendItems();
        if (colorLegendItems.length !== 0) {
            return { type: 'category', items: colorLegendItems };
        }
        return {};
    };
    /**
     * 请求数据
     */
    Choropleth.prototype.fetchData = function (level, adcode, granularity) {
        return (0, tslib_1.__awaiter)(this, void 0, void 0, function () {
            var fileName, cacheArea, _a, url, type, extension, response, data;
            return (0, tslib_1.__generator)(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        fileName = "".concat(adcode, "_").concat(level, "_").concat(granularity);
                        cacheArea = (0, cache_1.getCacheArea)(fileName);
                        if (cacheArea)
                            return [2 /*return*/, cacheArea];
                        _a = (0, helper_1.getGeoAreaConfig)(this.options.geoArea), url = _a.url, type = _a.type, extension = _a.extension;
                        return [4 /*yield*/, fetch("".concat(url, "/").concat(level, "/").concat(fileName, ".").concat(extension))];
                    case 1:
                        response = _b.sent();
                        return [4 /*yield*/, response.json()];
                    case 2:
                        data = _b.sent();
                        if (type === 'topojson') {
                            data = (0, helper_1.topojson2geojson)(data);
                        }
                        (0, cache_1.registerCacheArea)(fileName, data);
                        return [2 /*return*/, data];
                }
            });
        });
    };
    /**
     * 请求初始化区域数据
     */
    Choropleth.prototype.getInitDistrictData = function () {
        var _a;
        return (0, tslib_1.__awaiter)(this, void 0, void 0, function () {
            var fetchChinaBoundaryData, geoData, err_1;
            var _b;
            return (0, tslib_1.__generator)(this, function (_c) {
                switch (_c.label) {
                    case 0:
                        fetchChinaBoundaryData = this.fetchData('country', '100000', 'boundary');
                        geoData = (_a = this.options.source) === null || _a === void 0 ? void 0 : _a.joinBy.geoData;
                        _c.label = 1;
                    case 1:
                        _c.trys.push([1, 3, , 4]);
                        return [4 /*yield*/, Promise.all([fetchChinaBoundaryData, this.getDistrictData(geoData)])];
                    case 2:
                        _b = tslib_1.__read.apply(void 0, [_c.sent(), 1]), this.chinaBoundaryData = _b[0];
                        return [3 /*break*/, 4];
                    case 3:
                        err_1 = _c.sent();
                        throw new Error("Failed to get china boundary data\uFF0C".concat(err_1));
                    case 4: return [2 /*return*/];
                }
            });
        });
    };
    /**
     * 请求区域数据
     */
    Choropleth.prototype.getDistrictData = function (geoData) {
        return (0, tslib_1.__awaiter)(this, void 0, void 0, function () {
            var _a, level, adcode, _b, granularity, fetchCurrentDistrictData, _c, err_2;
            return (0, tslib_1.__generator)(this, function (_d) {
                switch (_d.label) {
                    case 0:
                        _a = this.options.viewLevel, level = _a.level, adcode = _a.adcode, _b = _a.granularity, granularity = _b === void 0 ? constants_1.DEFAULT_AREA_GRANULARITY[level] : _b;
                        fetchCurrentDistrictData = geoData ? Promise.resolve(geoData) : this.fetchData(level, adcode, granularity);
                        _d.label = 1;
                    case 1:
                        _d.trys.push([1, 3, , 4]);
                        _c = this;
                        return [4 /*yield*/, fetchCurrentDistrictData];
                    case 2:
                        _c.currentDistrictData = _d.sent();
                        this.options.source = (0, utils_1.deepAssign)({}, this.options.source, { joinBy: { geoData: this.currentDistrictData } });
                        return [3 /*break*/, 4];
                    case 3:
                        err_2 = _d.sent();
                        throw new Error("Failed to get district data\uFF0C".concat(err_2));
                    case 4: return [2 /*return*/];
                }
            });
        });
    };
    /**
     * 向下钻取方法
     */
    Choropleth.prototype.drillDown = function (view, config) {
        var _this = this;
        if (config === void 0) { config = {}; }
        this.changeView(view, config).then(function (drillData) {
            drillData && _this.drillStacks.push(drillData);
        });
    };
    /**
     * 向上钻取方法
     */
    Choropleth.prototype.drillUp = function (config) {
        if (config === void 0) { config = {}; }
        // 已经上卷到最高层级
        var isTopDrillStack = this.drillStacks.length === 0 || this.drillStacks.length === 1;
        if (isTopDrillStack) {
            return;
        }
        var lastIndex = this.drillStacks.length - 1;
        var _a = this.drillStacks[lastIndex - 1], drillConfig = _a.config, view = (0, tslib_1.__rest)(_a, ["config"]);
        var mergeConfig = (0, utils_1.deepAssign)({}, drillConfig, config);
        this.changeView(view, mergeConfig);
        this.drillStacks.pop();
    };
    /**
     * 更新显示区域
     */
    Choropleth.prototype.changeView = function (view, config) {
        if (config === void 0) { config = {}; }
        return (0, tslib_1.__awaiter)(this, void 0, void 0, function () {
            var level, adcode, _a, granularity, geoData, mergeConfig, drillData;
            return (0, tslib_1.__generator)(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        level = view.level, adcode = view.adcode, _a = view.granularity, granularity = _a === void 0 ? constants_1.DEFAULT_AREA_GRANULARITY[level] : _a;
                        return [4 /*yield*/, this.fetchData(level, adcode, granularity)];
                    case 1:
                        geoData = _b.sent();
                        if (!geoData.features.length)
                            return [2 /*return*/];
                        mergeConfig = (0, utils_1.deepAssign)({}, (0, helper_1.getDrillStepDefaultConfig)(this.options), config, {
                            viewLevel: { level: level, adcode: adcode, granularity: granularity },
                            source: { joinBy: { geoData: geoData } },
                        });
                        this.update(mergeConfig);
                        drillData = {
                            level: level,
                            adcode: adcode,
                            granularity: granularity,
                            config: mergeConfig,
                        };
                        return [2 /*return*/, drillData];
                }
            });
        });
    };
    /**
     * 默认配置项
     */
    Choropleth.DefaultOptions = constants_1.DEFAULT_OPTIONS;
    /**
     * 地理数据地址
     */
    Choropleth.GeoDataUrl = constants_1.GEO_DATA_URL;
    /**
     * 行政数据地址
     */
    Choropleth.GeoAreaUrl = constants_1.GEO_AREA_URL;
    return Choropleth;
}(plot_1.Plot));
exports.Choropleth = Choropleth;
//# sourceMappingURL=index.js.map