文章目录
- 前言
- 表达式逻辑
- mapbox表达式转数学表达式
- 数学表达式转mapbox表达式
- 实现效果
前言
mapbox-gl 支持表达式编辑 2.5D 建筑物高度,但是 style 文件原生的表达式很不直观,本文实现一个简单的 2.5D高度图层编辑器,核心是理解mapbox表达式规则与递归算法。界面如下:
表达式逻辑
mapbox 表达式规则建议认真参考官网,复杂表达式的组装方式需要自己去 mapbox-studio 官网配图,下载style文件查看。这里列举两个输入式与mapbox表达式的关系:
const input1 = ['F1', '*', 'F2', '/', 'F3']
const result1 =
[
"/",
[
"*", ["get", "F1"], ["get", "F2"]
],
["get", "F3"]
]
const input2 = ['F1', '*', 'F2', '/', 'F3', '-', '10']
const result2 = [
"-",
[
"/",
[
"*", ["get", "F1"], ["get", "F2"]
],
[
"get",
"F3"
]
],
10
]
mapbox表达式转数学表达式
mapbox转换变为直观的数学表达式,用于表达式回显
function flat(arr) {
const isDeep = arr.some(item => //判断是否包含需要拍平的数组
item instanceof Array
)
if (!isDeep) {
return arr //不需要拍平,返回
}
const res = Array.prototype.concat.apply([], arr) //需要拍平,拍平第一层
return flat(res) //递归
}
// 由mapbox支持的表达式转换为普通表达式
export function express2formula(input) {
const _arr = flat(input).filter(item => item !== 'get')
const sign_arr = _arr.filter(item => ['+', '-', '*', '/'].includes(item)).reverse().map(item => ` ${item} `)
const data_arr = _arr.filter(item => !['+', '-', '*', '/'].includes(item))
return (data_arr.reduce((r, a, i) => r.concat(a, sign_arr[i]), [0]).slice(1, -1)).join("")
}
数学表达式转mapbox表达式
直观的数学表达式经过转换变为mapox可识别的表达式,用于更改地图样式
// 递归判断条件
function notFlatten(arr) {
const res = arr.filter((item) =>
['+', '-', '*', '/'].includes(item)
)
return res.length > 1
}
function reSort(arr) {
return [arr[1], arr[0], arr[2]]
}
// 将get拼装给非数字和计算符 ['+', '-', '*', '/']
export function pickGet(arr) {
return arr.map((item) => {
if (['+', '-', '*', '/'].includes(item)) {
return item
}
if (!isNaN(item)) {
return Number(item)
}
// if (Array.isArray(item)) {
// getExpression(item)
// }
return ['get', item]
})
}
// 拼装获取mapbox支持的表达式
export function formula2express(arr) {
console.log(reSort(arr))
const l = arr.length
if (l === 3) return reSort(arr)
let last = arr[l - 1]
let first = arr[l - 2]
const rest = arr.slice(0, l - 2)
const data = [first, last]
data.splice(1, 0, rest.length === 3 ? reSort(rest) : rest)
if (notFlatten(data[1])) {
const _arr = formula2express(data[1])
data.splice(1, 1, _arr)
}
return (data)
}
实现效果
- 属性字段从下拉框自选,不可手动输入
- 表达式由输入框负责展现,可以删除字段或者输入数字,不可输入属性字段
- 运算支持 + - * /,由左向右运算
- 点击应用效果时会改变样式,若表达式有误则会提示错误
设置图层高
错误提示