mapbox-gl实现 2.5D 图层高度编辑器


前言

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表达式

直观的数学表达式经过转换变为mapbox可识别的表达式,用于更改地图样式

// 递归判断条件
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
}

console.log(formula2express(pickGet(input1)))

实现效果

  • 属性字段从下拉框自选,不可手动输入
  • 表达式由输入框负责展现,可以删除字段或者输入数字,不可输入属性字段
  • 运算支持 + - * /,由左向右运算
  • 点击应用效果时会改变样式,若表达式有误则会提示错误

设置图层高
在这里插入图片描述

错误提示

在这里插入图片描述

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值