类名 leaflet/document/support/ThemeRenderUtil.js
import * as L from '@mapgis/leaflet'
import { inputCss, isNumber } from '@mapgis/webclient-common/util/Utils'
import { SymbolType, defined } from '@mapgis/webclient-common'
import LeafletPlugin from '../../util/LeafletPlugin'
import ConvertSymbolUtil from '../../util/ConvertSymbolUtil'

function convertClusterSymbol(symbol, textSymbol, text) {
  const dom = document.createElement('div')
  const parentDom = document.createElement('div')
  let bgSize = [10, 10]
  let bgBorderWidth = 0
  let bgColor = 'none'
  // 解析符号为PictureMarker 和 SimpleMarker
  if (SymbolType.pictureMarker === symbol.type) {
    if (defined(symbol.width)) {
      dom.style.width = `${parseFloat(symbol.width)}px`
      bgSize[0] = parseFloat(symbol.width)
    }
    if (defined(symbol.height)) {
      dom.style.height = `${parseFloat(symbol.height)}px`
      bgSize[1] = parseFloat(symbol.height)
    }
    // 图片和几何点中心统一
    if (defined(symbol.xoffset)) {
      dom.style.marginLeft = symbol.xoffset
    }
    if (defined(symbol.yoffset)) {
      dom.style.marginTop = symbol.yoffset
    }
    if (defined(symbol.angle)) {
      dom.style.transform = `rotate(${symbol.angle}deg)`
    }
    if (defined(symbol.url)) {
      dom.style.backgroundImage = `url(${symbol.url})`
      dom.style.backgroundSize = `cover`
    }
  } else {
    const {
      size = 20,
      outline = null,
      style = 'circle',
      path = '',
      angle = 0,
      xoffset = 0,
      yoffset = 0,
      color
    } = symbol

    // 不支持path 和 style
    if (defined(outline)) {
      const { width, color } = outline
      if (style === 'circle') {
        dom.style.borderRadius = `${size}px`
        dom.style.backgroundClip = 'padding-box'
      }
      bgBorderWidth = width
      bgColor = LeafletPlugin.convertColorToRgb(color)
    }

    if (defined(color)) {
      dom.style.backgroundColor = LeafletPlugin.convertColorToRgb(color)
      dom.style.backgroundSize = `cover`
    }
    if (defined(size)) {
      bgSize = [size, size]
      dom.style.width = `${size}px`
      dom.style.height = `${size}px`
    }
    if (defined(xoffset)) {
      dom.style.marginLeft = `${xoffset}px`
    }
    if (defined(yoffset)) {
      dom.style.marginTop = `${yoffset}px`
    }
    if (defined(angle)) {
      dom.style.transform = `rotate(${angle}deg)`
    }
    // 不支持path
  }

  const span = document.createElement('span')
  // 设置文字居中
  dom.style.textAlign = 'center'
  span.style.lineHeight = `${bgSize[1]}px`
  if (textSymbol) {
    const {
      color = '#000000',
      angle = 0,
      backgroundColor,
      borderLineColor,
      borderLineSize,
      font,
      haloColor,
      haloSize,
      xoffset,
      yoffset
    } = textSymbol
    span.style.color = LeafletPlugin.convertColorToRgb(color)
    span.style.transform = `rotate(${angle}deg)`
    if (defined(backgroundColor)) {
      span.style.backgroundColor =
        LeafletPlugin.convertColorToRgb(backgroundColor)
    }
    if (defined(borderLineColor) && defined(borderLineSize)) {
      span.style.border = `${borderLineSize}px solid ${LeafletPlugin.convertColorToRgb(
        borderLineColor
      )}`
    }
    if (defined(font)) {
      const { family = 'Helvetica Neue', size, style, weight } = font
      span.style.fontFamily = family
      span.style.fontSize = `${size}px`
      span.style.fontStyle = style
      span.style.fontWeight = weight
    }
    if (defined(haloColor) && defined(haloSize)) {
      span.style[
        '-webkit-text-stroke'
      ] = `${haloSize}px ${LeafletPlugin.convertColorToRgb(borderLineColor)}`
    }
    // 不支持xoffset yoffset
  }

  const parentDomWidth = bgSize[0] + bgBorderWidth * 2
  const parentDomHeight = bgSize[1] + bgBorderWidth * 2

  parentDom.style = `border:none;width:${parentDomWidth}px;height:${parentDomHeight}px;background-color:${bgColor};border-radius:${
    symbol.style === 'circle' ? `${parentDomWidth}px` : 'none'
  };padding:${bgBorderWidth}px;`

  span.innerText = text
  dom.appendChild(span)
  parentDom.appendChild(dom)
  // divIcon
  const divIcon = new L.DivIcon({
    html: parentDom,
    iconSize: new L.Point(parentDomWidth, parentDomHeight),
    className: ``
  })
  return divIcon
}

// 部分专题图强依赖plugin层,因此需要对这些专题图特殊处理
class ThemeRenderUtil {
  /**
   * @description: 渲染聚类图
   * @param {*} innerLayer
   * @param {*} layer
   * @param {*} innerView
   * @param {*} features
   * @return {*}
   */
  static renderCluster(innerLayer, layer, innerView, features) {
    // 添加聚类样式
    inputCss(`
    .leaflet-cluster-anim .leaflet-marker-icon, .leaflet-cluster-anim .leaflet-marker-shadow {
      -webkit-transition: -webkit-transform 0.3s ease-out, opacity 0.3s ease-in;
      -moz-transition: -moz-transform 0.3s ease-out, opacity 0.3s ease-in;
      -o-transition: -o-transform 0.3s ease-out, opacity 0.3s ease-in;
      transition: transform 0.3s ease-out, opacity 0.3s ease-in;
    }
    .leaflet-cluster-spider-leg {
      /* stroke-dashoffset (duration and function) should match with leaflet-marker-icon transform in order to track it exactly */
      -webkit-transition: -webkit-stroke-dashoffset 0.3s ease-out, -webkit-stroke-opacity 0.3s ease-in;
      -moz-transition: -moz-stroke-dashoffset 0.3s ease-out, -moz-stroke-opacity 0.3s ease-in;
      -o-transition: -o-stroke-dashoffset 0.3s ease-out, -o-stroke-opacity 0.3s ease-in;
      transition: stroke-dashoffset 0.3s ease-out, stroke-opacity 0.3s ease-in;
    }
    `)
    // 初始化配置
    ThemeRenderUtil.updateCluster(innerLayer, layer, innerView)
    features = features || []
    features.forEach((feature) => {
      const marker = L.marker(LeafletPlugin.getAreaCenter(feature.geometry))
      innerLayer.addLayer(marker)
    })
  }

  static updateCluster(innerLayer, layer, innerView) {
    const options = innerLayer.options
    const renderer = layer.renderer

    const {
      defaultSymbol,
      radius,
      clusterBoundSymbol,
      maxScale,
      isExpandOnClick,
      isHoverShowBound
    } = renderer

    let clusterInfos = renderer.clusterInfos || []

    // 设置聚类最大zoom
    let zoom = 20
    if (innerView) {
      const resolution = (maxScale / 96) * 0.0254
      const latlng1 = innerView.unproject(L.point(0, 0), 0)
      const latlng2 = innerView.unproject(L.point(0, 1), 0)
      let dis = innerView.distance(latlng1, latlng2)
      let calcZoom = 0
      while (calcZoom <= 20 && dis > resolution) {
        calcZoom += 1
        dis /= 2
      }
      zoom = Math.max(calcZoom - 1, 0)
    }

    options.disableClusteringAtZoom = zoom
    options.singleMarkerMode = true
    options.maxClusterRadius = radius
    options.polygonOptions =
      ConvertSymbolUtil.convertSymboltoLeafletStyle(clusterBoundSymbol)
    options.zoomToBoundsOnClick = isExpandOnClick
    options.showCoverageOnHover = isHoverShowBound

    // 过滤不合法的聚类
    clusterInfos = clusterInfos.filter(
      (v) =>
        v &&
        isNumber(v.minValue) &&
        isNumber(v.maxValue) &&
        v.maxValue > v.minValue
    )

    options.iconCreateFunction = (cluster) => {
      const childCount = cluster.getChildCount()

      let infoSymbol = defaultSymbol
      let infoTextSymbol
      for (let i = 0; i < clusterInfos.length; i++) {
        const { symbol, labelSymbol, minValue, maxValue } = clusterInfos[i]
        if (childCount >= minValue && childCount < maxValue) {
          infoSymbol = symbol
          infoTextSymbol = labelSymbol
          break
        }
      }
      return convertClusterSymbol(
        infoSymbol,
        infoTextSymbol,
        String(childCount)
      )
    }
  }
}
export default ThemeRenderUtil
构造函数
成员变量
方法
事件