目录
前端代码实现
根据xml配置文件计算出行列号
1、xml配置文件信息样例
2、代码实现
运用到的知识
该文档是根据本人做的项目进行的总结,可能存在知识不准确,仅做参考;
前端代码实现
根据提供一个瓦片服务地址,解析服务的元数据,获取到范围,根据范围,计算出行列号
根据xml配置文件计算出行列号
1、xml配置文件信息样例

2、代码实现
1、解析xml数据为json格式的数据,借助插件x2js
2、本例中,只做了3857和4326坐标系的支持;请求用axios进行请求
3、因为文档中的比例尺分母使用的是米,所以4236中,如果没有提供level时,将度数转为米进行匹配层级信息的
4、4326坐标系的地球半径取值为:6371004;3857坐标系的地球半径取值为:6378137;
import X2JS from 'x2js';
// 1、请求配置文件路径,获取元数据,通过插件x2js解析xml数据为json格式
let url = 'http://xxxxx';
axios.get(url).then((res) => {
    if (res.status != 200) {
        alert('请检查您的配置文件路径');
        return false;
    }
    var x2js = new X2JS();
    var json = x2js.xml2js(res.data);
    getColRowLevel({data:json,dpi:90.714});
});
// 2、 根据获取的元数据,获取行列号和层级
const getColRowLevel = (json) => {
    let { data, dpi, level } = json;
    let Contents = data.Capabilities.Contents;
    let TileMatrixSet = Contents.TileMatrixSet;
    // 元数据中的crs坐标系
    let SupportedCRS = TileMatrixSet.SupportedCRS.__text || TileMatrixSet.SupportedCRS;
    
    // 默认crs是3857
    //默认dpi为90.714,dpi一般为90.714或者96;如果不确定dpi请咨询提供服务的后台
    dpi = dpi ? Number(dpi) : 90.714;
    level = level ? Number(level) : null;
    if (SupportedCRS.toLowerCase().includes('epsg::4326')) {
        // 4326
        return colRowLevel4326(Contents, dpi, level);
    } else {
        // 3857
        return colRowLevel3857(Contents, dpi, level);
    }
};
const colRowLevel4326 = (Contents, dpi, level) => {
    let Layer = Contents.Layer;
   
    // 服务范围,如果给指定范围,则去掉下面四行,直接let extentObj = {minX,minY,maxX,maxY}
    let WGS84BoundingBox = Layer.WGS84BoundingBox;
    let LowerCorner = WGS84BoundingBox.LowerCorner.__text;
    let UpperCorner = WGS84BoundingBox.UpperCorner.__text;
    let extentObj = getExtent4326(LowerCorner, UpperCorner);
    let { minX, maxX, minY, maxY } = extentObj;
    let canvasWidth = 1000;
    let tileSize = 256;
    let realTileWidthDegree = (maxX - minX) / (canvasWidth / tileSize);
    let realTileWidthMeter = (realTileWidthDegree / 180) * (Math.PI * 6371004);
    let resolutions = realTileWidthMeter / tileSize;
    let scaleDenominator = resolutions / (0.0254 / dpi);
    // // Identifier  ScaleDenominator TileHeight  TopLeftCorner
    let TileMatrixSet = Contents.TileMatrixSet;
    let TileMatrixArr = TileMatrixSet.TileMatrix;
    // 当前比例尺最接近的对象
    let curScaleObj = getScaleInfo(TileMatrixArr,scaleDenominator,level);
    
    if (curScaleObj) {
        // Identifier  ScaleDenominator TileWidth  TopLeftCorner
        let { ScaleDenominator, TopLeftCorner, Identifier, TileWidth } = curScaleObj;
        Identifier = Identifier.__text;
        ScaleDenominator = eToNumber(ScaleDenominator);
        let originObj = TopLeftCorner.split(' ');
        let originX = originObj[1];
        let originY = originObj[0];
        var resolution = (((0.0254 / dpi) * ScaleDenominator) / (Math.PI * 6371004)) * 180;
        let minCol = Math.floor(Math.abs(originX - minX) / (resolution * tileSize));
        let minRow = Math.floor(Math.abs(originY - maxY) / (resolution * tileSize));
        let maxCol = Math.ceil(Math.abs(originX - maxX) / (resolution * tileSize));
        let maxRow = Math.ceil(Math.abs(originY - minY) / (resolution * tileSize));
        return {
            minCol,
            minRow,
            maxCol,
            maxRow,
            level: Identifier
        };
    }
    return false;
};
const colRowLevel3857 = (Contents, dpi, level) => {
    let Layer = Contents.Layer;
    
    // 服务范围,如果给指定范围,则去掉下面四行,直接let extentObj = {minX,minY,maxX,maxY}
    let WGS84BoundingBox = Layer.WGS84BoundingBox;
    let LowerCorner = WGS84BoundingBox.LowerCorner.__text;
    let UpperCorner = WGS84BoundingBox.UpperCorner.__text;
    let extentObj = getExtent3857(LowerCorner, UpperCorner);
    let { minX, maxX, minY, maxY } = extentObj;
    let canvasWidth = 1000;
    let tileSize = 256;
    let realTileWidth = (maxX - minX) / (canvasWidth / tileSize);
    let resolutions = realTileWidth / tileSize;
    let scaleDenominator = resolutions / (0.0254 / dpi);
    // Identifier  ScaleDenominator TileHeight  TopLeftCorner
    let TileMatrixSet = Contents.TileMatrixSet;
    let TileMatrixArr = TileMatrixSet.TileMatrix;
    // 当前比例尺最接近的对象
    let curScaleObj = getScaleInfo(TileMatrixArr,scaleDenominator,level);
    if (curScaleObj) {
        // Identifier  ScaleDenominator TileWidth  TopLeftCorner
        let { ScaleDenominator, TopLeftCorner, Identifier, TileWidth } = curScaleObj;
        Identifier = Identifier.__text;
        ScaleDenominator = eToNumber(ScaleDenominator);
        let originObj = getOrigin(TopLeftCorner);
        let originX = originObj.x;
        let originY = originObj.y;
       
        let resolution = (0.0254 / dpi) * ScaleDenominator;
        let minCol = Math.floor(Math.abs(originX - minX) / (resolution * tileSize));
        let minRow = Math.floor(Math.abs(originY - maxY) / (resolution * tileSize));
        let maxCol = Math.ceil(Math.abs(originX - maxX) / (resolution * tileSize));
        let maxRow = Math.ceil(Math.abs(originY - minY) / (resolution * tileSize));
        return {
            minCol,
            minRow,
            maxCol,
            maxRow,
            level: Identifier
        };
    }
    return false;
};
// 得到当前比例尺信息
const getScaleInfo = (TileMatrixArr,scaleDenominator,level)=>{
    let curScaleObj = null;
    let neastScaleD = undefined;
    if (level) {
        curScaleObj = TileMatrixArr.find((item) => item.Identifier.__text == level);
    }
    if (!curScaleObj) {
        TileMatrixArr.forEach((item) => {
            let ScaleDenominator = eToNumber(item.ScaleDenominator);
            let dist = Math.abs(scaleDenominator - ScaleDenominator);
            if (neastScaleD == undefined) {
                neastScaleD = dist;
                curScaleObj = item;
            } else if (dist < neastScaleD) {
                neastScaleD = dist;
                curScaleObj = item;
            }
        });
    }
    return curScaleObj;
}
// 得到origin
const getOrigin = (TopLeftCorner) => {
    let arr = TopLeftCorner.split(' ');
    return { x: eToNumber(arr[0]), y: eToNumber(arr[1]) };
};
// 将自然计数转化为数字
const eToNumber = (eNum) => {
    eNum = (eNum + '').toLowerCase();
    if (eNum.includes('e')) {
        let arr = eNum.split('e');
        return Number(arr[0]) * Math.pow(10, arr[1]);
    }
    return Number(eNum);
};
// 得到范围的坐标点
const getExtent3857 = (LowerCorner, UpperCorner) => {
    let lowerArr = LowerCorner.split(' ');
    let upperArr = UpperCorner.split(' ');
    let min = WGS84ToMercator({ lng: lowerArr[0], lat: lowerArr[1] });
    let max = WGS84ToMercator({ lng: upperArr[0], lat: upperArr[1] });
    return {
        minX: min.lng,
        minY: min.lat,
        maxX: max.lng,
        maxY: max.lat
    };
};
const getExtent4326 = (LowerCorner, UpperCorner) => {
    let lowerArr = LowerCorner.split(' ');
    let upperArr = UpperCorner.split(' ');
    return {
        minX: lowerArr[0],
        minY: lowerArr[1],
        maxX: upperArr[0],
        maxY: upperArr[1]
    };
};
运用到的知识
1、像素和米的换算
1英寸 = 2.54厘米 = 0.0254米
1英寸 = 96像素
所以:1像素 = (0.0254/dpi)米
dpi一般取值96或者90.714,dpi的值不确定的话,需要咨询提供瓦片服务的人
2、分辨率的计算
分辨率 = (0.0254/dpi)*比例尺分母;


















