园林绿化
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

335 lines
11 KiB

  1. //taitan公司自定义的Sld 样式
  2. //sld与mvt样式区别:sld针对一个要素多个rule的样式可以同时独立生效,而mvt只能给一个要素设置一个样式
  3. ;(function (window) {
  4. function TaitanPbfStyle(options) {
  5. this.ol = null
  6. this.json = {}
  7. this.options = {}
  8. this.style = {}
  9. this.iconCache = {}
  10. this.properties = null
  11. this.type = null
  12. this.scale = null
  13. this.resolution = null
  14. this.filterIsPass = null
  15. this.scaleIsPass = true
  16. this.init(options)
  17. }
  18. TaitanPbfStyle.prototype = {
  19. constructor: TaitanPbfStyle,
  20. defaults: {
  21. ol: null,
  22. json: {},
  23. },
  24. init: function (options) {
  25. let opts = Object.assign({}, this.defaults, options)
  26. this.json = opts.json
  27. this.ol = opts.ol
  28. },
  29. reset: function () {
  30. this.options = {}
  31. this.style = {}
  32. this.properties = null
  33. this.type = null
  34. this.scale = null
  35. this.resolution = null
  36. this.filterIsPass = null
  37. this.scaleIsPass = true
  38. },
  39. getStyle: function () {
  40. let This = this
  41. return function (feature, resolution) {
  42. This.reset()
  43. This.type = feature.getGeometry().getType()
  44. This.properties = feature.getProperties()
  45. This.resolution = resolution
  46. This.scale = 1 / (0.0254 / (96 * resolution))
  47. This.filter()
  48. return This.buildStyle()
  49. }
  50. },
  51. // 根据options组装最终的样式对象
  52. buildStyle: function () {
  53. if (Object.keys(this.options).length == 0) return [new this.ol.style.Style({})]
  54. // if (JSON.stringify(this.options) == '{}') return;
  55. // 组装基础样式
  56. switch (this.type.toLowerCase()) {
  57. case 'point':
  58. if (this.options.image.imageStyle) this.style.image = this.options.image.imageStyle
  59. break
  60. case 'linestring':
  61. if (this.options.stroke) this.style.stroke = this.options.stroke
  62. break
  63. case 'polygon':
  64. if (this.options.fill) this.style.fill = this.options.fill
  65. if (this.options.stroke) this.style.stroke = this.options.stroke
  66. break
  67. default:
  68. break
  69. }
  70. // 组装label样式,这里控制了下显示层级,只有分辨率小于40的时候才会显示label,后续可以做成可配置项
  71. if (this.resolution < 40 && this.options.text) {
  72. this.style.text = new this.ol.style.Text({
  73. text: this.options.text.text ? this.options.text.text + '' : '',
  74. textBaseline: 'top',
  75. overflow: 'line',
  76. font: `${this.options.text.font || 10}px sans-serif`,
  77. offsetX: this.options.text.offsetX,
  78. offsetY: this.options.text.offsetY,
  79. fill: this.options.text.fill,
  80. stroke: this.options.text.stroke,
  81. rotateWithView: false,
  82. })
  83. }
  84. // 组装层级样式
  85. this.style.zIndex = this.options.zIndex || 1
  86. return [new this.ol.style.Style(this.style)]
  87. },
  88. // 构建样式options
  89. buildOptions: function (rule) {
  90. // rule.Symbolizer.WellKnownName = 'img';
  91. // rule.Symbolizer.src = 'https://unpkg.com/@mapbox/maki@4.0.0/icons/park-15.svg';
  92. this.options.image = {}
  93. this.options.image.rotation = rule.Symbolizer.Rotation || 0
  94. if (rule.Symbolizer.FillColor && rule.Symbolizer.WellKnownName != 'img') {
  95. let imgFillColor = this.buildRgba(rule.Symbolizer.FillColor, rule.Symbolizer.FillOpacity)
  96. this.options.image.fill = new this.ol.style.Fill({
  97. color: imgFillColor,
  98. })
  99. if (rule.Symbolizer.StrokeColor) {
  100. let imgStrokeColor = this.buildRgba(rule.Symbolizer.StrokeColor, rule.Symbolizer.StrokeOpacity)
  101. this.options.image.stroke = new this.ol.style.Stroke({
  102. color: imgStrokeColor,
  103. width: rule.Symbolizer.StrokeWidth,
  104. lineDash: rule.Symbolizer.StrokeDasharray.split(' '),
  105. })
  106. }
  107. }
  108. this.options.image.render = 'image'
  109. switch (rule.Symbolizer.WellKnownName) {
  110. case 'circle':
  111. // 圆形
  112. this.options.image.radius = rule.Symbolizer.Size
  113. this.options.image.imageStyle = new this.ol.style.Circle(this.options.image)
  114. break
  115. case 'square':
  116. // 正方形
  117. this.options.image.radius = rule.Symbolizer.Size
  118. this.options.image.points = 4
  119. this.options.image.angle = Math.PI / 4
  120. this.options.image.imageStyle = new this.ol.style.RegularShape(this.options.image)
  121. break
  122. case 'triangle':
  123. // 三角形
  124. this.options.image.radius = rule.Symbolizer.Size
  125. this.options.image.points = 3
  126. this.options.image.angle = 0
  127. this.options.image.imageStyle = new this.ol.style.RegularShape(this.options.image)
  128. break
  129. case 'star':
  130. // 五角形
  131. this.options.image.radius = rule.Symbolizer.Size
  132. this.options.image.points = 5
  133. this.options.image.radius2 = rule.Symbolizer.Size / 2.5
  134. this.options.image.angle = 0
  135. this.options.image.imageStyle = new this.ol.style.RegularShape(this.options.image)
  136. break
  137. case 'cross':
  138. // 十字架
  139. this.options.image.radius = rule.Symbolizer.Size
  140. this.options.image.points = 4
  141. this.options.image.radius2 = 0
  142. this.options.image.angle = 0
  143. this.options.image.imageStyle = new this.ol.style.RegularShape(this.options.image)
  144. break
  145. case 'x':
  146. // ×形
  147. this.options.image.radius = rule.Symbolizer.Size
  148. this.options.image.points = 4
  149. this.options.image.radius2 = 0
  150. this.options.image.angle = Math.PI / 4
  151. this.options.image.imageStyle = new this.ol.style.RegularShape(this.options.image)
  152. break
  153. case 'img':
  154. let icon = this.iconCache[rule.Symbolizer.src]
  155. if (!icon) {
  156. this.options.image.src = rule.Symbolizer.src
  157. this.options.image.anchorXUnits = 'fraction'
  158. this.options.image.anchorYUnits = 'fraction'
  159. this.options.image.anchor = [0.5, 0.5]
  160. this.options.image.offset = [0, 0]
  161. this.options.image.scale = 1
  162. this.options.image.rotation = rule.Symbolizer.Rotation
  163. ;(this.options.image.crossOrigin = 'anonymous'), (this.options.image.imageStyle = new this.ol.style.Icon(this.options.image))
  164. this.iconCache[rule.Symbolizer.src] = this.options.image.imageStyle
  165. } else {
  166. this.options.image.imageStyle = icon
  167. }
  168. break
  169. default:
  170. break
  171. }
  172. // 构建option中的填充色
  173. if (rule.Symbolizer.FillColor) {
  174. let fillColor = this.buildRgba(rule.Symbolizer.FillColor, rule.Symbolizer.FillOpacity)
  175. this.options.fill = new this.ol.style.Fill({
  176. color: fillColor,
  177. })
  178. }
  179. // 构建option中的边框
  180. let strokeColor, strokeWidth, strokeDasharray
  181. if (rule.Symbolizer.StrokeColor) {
  182. strokeColor = this.buildRgba(rule.Symbolizer.StrokeColor, rule.Symbolizer.StrokeOpacity)
  183. if (rule.Symbolizer.StrokeWidth && rule.Symbolizer.StrokeWidth > 1) {
  184. strokeWidth = rule.Symbolizer.StrokeWidth
  185. }
  186. if (rule.Symbolizer.StrokeDasharray && rule.Symbolizer.StrokeDasharray.split(' ')) {
  187. strokeDasharray = rule.Symbolizer.StrokeDasharray.split(' ')
  188. }
  189. this.options.stroke = new this.ol.style.Stroke({
  190. color: strokeColor,
  191. width: strokeWidth,
  192. lineDash: strokeDasharray,
  193. })
  194. }
  195. // 构建option中的标签
  196. if (rule.Label && JSON.stringify(rule.Label) != '{}') {
  197. this.options.text = {}
  198. this.options.text.text = this.properties[rule.Label.PropertyName]
  199. this.options.text.font = rule.Label.FontSize
  200. this.options.text.offsetX = rule.Label.AnchorPointX
  201. this.options.text.offsetY = rule.Label.AnchorPointY
  202. if (rule.Label.FillColor) {
  203. let fillColor = this.buildRgba(rule.Label.FillColor, rule.Label.FillOpacity)
  204. this.options.text.fill = new this.ol.style.Fill({
  205. color: fillColor,
  206. })
  207. }
  208. if (rule.Label.HaloFillColor) {
  209. let haloFillColor = this.buildRgba(rule.Label.HaloFillColor, rule.Label.HaloFillOpacity)
  210. this.options.text.stroke = new this.ol.style.Stroke({
  211. color: haloFillColor,
  212. width: rule.Label.HaloRadius,
  213. })
  214. }
  215. }
  216. },
  217. // 根据属性和比例条件进行判断
  218. filter: function () {
  219. for (let rule of this.json.Rule) {
  220. // 每次循环开始前将重置filterIsPass参数
  221. this.filterIsPass = undefined
  222. // 判断属性过滤条件,如果属性过滤条件参数不存在或者为空,则不做进一步的判断,直接赋值true
  223. if (
  224. rule.Filter instanceof Object == false ||
  225. JSON.stringify(rule.Filter) == '{}' ||
  226. rule.Filter.Conditions == undefined ||
  227. rule.Filter.Conditions.length == 0
  228. ) {
  229. this.filterIsPass = true
  230. } else {
  231. this.filterConditions(rule.Filter)
  232. }
  233. this.buildOptions(rule)
  234. // 判断比例条件是否符合
  235. // let minScale = rule.MinScaleDenominator ? rule.MinScaleDenominator : 10;
  236. // let maxScale = rule.MaxScaleDenominator ? rule.MaxScaleDenominator : 10000000000;
  237. // this.scaleIsPass = (this.scale < minScale || this.scale > maxScale) ? false : true;
  238. // if (this.filterIsPass && this.scaleIsPass) this.buildOptions(rule);
  239. }
  240. },
  241. // 根据属性过滤条件进行判断
  242. filterConditions: function (filter) {
  243. for (let condition of filter.Conditions) {
  244. let bool,
  245. val = this.properties[condition.PropertyName] + '' || ''
  246. switch (condition.Condition) {
  247. case 'PropertyIsEqualTo':
  248. bool = val == condition.Literal
  249. break
  250. case 'PropertyIsNotEqualTo':
  251. bool = val != condition.Literal
  252. break
  253. case 'PropertyIsLike':
  254. bool = val.indexOf(condition.Literal) > -1
  255. break
  256. case 'PropertyIsBetween':
  257. let num = parseFloat(val)
  258. bool = num >= condition.LowerBoundary.Literal && num <= condition.UpperBoundary.Literal
  259. break
  260. default:
  261. break
  262. }
  263. if (filter.FilterType == 'And') {
  264. this.filterIsPass = this.filterIsPass == undefined ? bool : this.filterIsPass && bool
  265. } else if (filter.FilterType == 'Or') {
  266. this.filterIsPass = this.filterIsPass == undefined ? bool : this.filterIsPass || bool
  267. }
  268. }
  269. },
  270. hexToRgb: function (hex) {
  271. let result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)
  272. return result
  273. ? {
  274. r: parseInt(result[1], 16),
  275. g: parseInt(result[2], 16),
  276. b: parseInt(result[3], 16),
  277. }
  278. : null
  279. },
  280. buildRgba: function (hex, opa) {
  281. hex = this.hexToRgb(hex)
  282. if (hex == 'null') return ''
  283. return `rgba(${hex.r},${hex.g},${hex.b},${opa})`
  284. },
  285. }
  286. //对外接口
  287. window.mars3d.TaitanPbfStyle = TaitanPbfStyle
  288. })(window)