335 lines
13 KiB
JavaScript
335 lines
13 KiB
JavaScript
|
|
//taitan公司自定义的Sld 样式
|
|||
|
|
//sld与mvt样式区别:sld针对一个要素多个rule的样式可以同时独立生效,而mvt只能给一个要素设置一个样式
|
|||
|
|
|
|||
|
|
(function (window) {
|
|||
|
|
|
|||
|
|
function TaitanPbfStyle(options) {
|
|||
|
|
this.ol = null;
|
|||
|
|
this.json = {};
|
|||
|
|
this.options = {};
|
|||
|
|
this.style = {};
|
|||
|
|
this.iconCache = {};
|
|||
|
|
this.properties = null;
|
|||
|
|
this.type = null;
|
|||
|
|
this.scale = null;
|
|||
|
|
this.resolution = null;
|
|||
|
|
this.filterIsPass = null;
|
|||
|
|
this.scaleIsPass = true;
|
|||
|
|
this.init(options);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
TaitanPbfStyle.prototype = {
|
|||
|
|
constructor: TaitanPbfStyle,
|
|||
|
|
|
|||
|
|
defaults: {
|
|||
|
|
ol: null,
|
|||
|
|
json: {}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
init: function (options) {
|
|||
|
|
let opts = Object.assign({}, this.defaults, options);
|
|||
|
|
this.json = opts.json;
|
|||
|
|
this.ol = opts.ol;
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
reset: function () {
|
|||
|
|
this.options = {};
|
|||
|
|
this.style = {};
|
|||
|
|
this.properties = null;
|
|||
|
|
this.type = null;
|
|||
|
|
this.scale = null;
|
|||
|
|
this.resolution = null;
|
|||
|
|
this.filterIsPass = null;
|
|||
|
|
this.scaleIsPass = true;
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
getStyle: function () {
|
|||
|
|
let This = this;
|
|||
|
|
return function (feature, resolution) {
|
|||
|
|
This.reset();
|
|||
|
|
This.type = feature.getGeometry().getType();
|
|||
|
|
This.properties = feature.getProperties();
|
|||
|
|
This.resolution = resolution;
|
|||
|
|
This.scale = 1 / (0.0254 / (96 * resolution));
|
|||
|
|
This.filter();
|
|||
|
|
return This.buildStyle();
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 根据options组装最终的样式对象
|
|||
|
|
buildStyle: function () {
|
|||
|
|
if (Object.keys(this.options).length == 0) return [new this.ol.style.Style({})];
|
|||
|
|
// if (JSON.stringify(this.options) == '{}') return;
|
|||
|
|
|
|||
|
|
// 组装基础样式
|
|||
|
|
switch (this.type.toLowerCase()) {
|
|||
|
|
case 'point':
|
|||
|
|
if (this.options.image.imageStyle) this.style.image = this.options.image.imageStyle;
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case 'linestring':
|
|||
|
|
if (this.options.stroke) this.style.stroke = this.options.stroke;
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case 'polygon':
|
|||
|
|
if (this.options.fill) this.style.fill = this.options.fill;
|
|||
|
|
if (this.options.stroke) this.style.stroke = this.options.stroke;
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
default:
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 组装label样式,这里控制了下显示层级,只有分辨率小于40的时候才会显示label,后续可以做成可配置项
|
|||
|
|
if (this.resolution < 40 && this.options.text) {
|
|||
|
|
this.style.text = new this.ol.style.Text({
|
|||
|
|
text: this.options.text.text ? this.options.text.text + '' : '',
|
|||
|
|
textBaseline: "top",
|
|||
|
|
overflow: 'line',
|
|||
|
|
font: `${this.options.text.font || 10}px sans-serif`,
|
|||
|
|
offsetX: this.options.text.offsetX,
|
|||
|
|
offsetY: this.options.text.offsetY,
|
|||
|
|
fill: this.options.text.fill,
|
|||
|
|
stroke: this.options.text.stroke,
|
|||
|
|
rotateWithView: false
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 组装层级样式
|
|||
|
|
this.style.zIndex = this.options.zIndex || 1;
|
|||
|
|
return [new this.ol.style.Style(this.style)];
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 构建样式options
|
|||
|
|
buildOptions: function (rule) {
|
|||
|
|
// rule.Symbolizer.WellKnownName = 'img';
|
|||
|
|
// rule.Symbolizer.src = 'https://unpkg.com/@mapbox/maki@4.0.0/icons/park-15.svg';
|
|||
|
|
|
|||
|
|
this.options.image = {};
|
|||
|
|
this.options.image.rotation = rule.Symbolizer.Rotation || 0;
|
|||
|
|
|
|||
|
|
if (rule.Symbolizer.FillColor && rule.Symbolizer.WellKnownName != 'img') {
|
|||
|
|
let imgFillColor = this.buildRgba(rule.Symbolizer.FillColor, rule.Symbolizer.FillOpacity);
|
|||
|
|
this.options.image.fill = new this.ol.style.Fill({
|
|||
|
|
color: imgFillColor
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (rule.Symbolizer.StrokeColor) {
|
|||
|
|
let imgStrokeColor = this.buildRgba(rule.Symbolizer.StrokeColor, rule.Symbolizer.StrokeOpacity);
|
|||
|
|
this.options.image.stroke = new this.ol.style.Stroke({
|
|||
|
|
color: imgStrokeColor,
|
|||
|
|
width: rule.Symbolizer.StrokeWidth,
|
|||
|
|
lineDash: rule.Symbolizer.StrokeDasharray.split(' ')
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
this.options.image.render = "image";
|
|||
|
|
|
|||
|
|
switch (rule.Symbolizer.WellKnownName) {
|
|||
|
|
case 'circle':
|
|||
|
|
// 圆形
|
|||
|
|
this.options.image.radius = rule.Symbolizer.Size;
|
|||
|
|
this.options.image.imageStyle = new this.ol.style.Circle(this.options.image);
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case 'square':
|
|||
|
|
// 正方形
|
|||
|
|
this.options.image.radius = rule.Symbolizer.Size;
|
|||
|
|
this.options.image.points = 4;
|
|||
|
|
this.options.image.angle = Math.PI / 4;
|
|||
|
|
this.options.image.imageStyle = new this.ol.style.RegularShape(this.options.image);
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case 'triangle':
|
|||
|
|
// 三角形
|
|||
|
|
this.options.image.radius = rule.Symbolizer.Size;
|
|||
|
|
this.options.image.points = 3;
|
|||
|
|
this.options.image.angle = 0;
|
|||
|
|
this.options.image.imageStyle = new this.ol.style.RegularShape(this.options.image);
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case 'star':
|
|||
|
|
// 五角形
|
|||
|
|
this.options.image.radius = rule.Symbolizer.Size;
|
|||
|
|
this.options.image.points = 5;
|
|||
|
|
this.options.image.radius2 = rule.Symbolizer.Size / 2.5;
|
|||
|
|
this.options.image.angle = 0;
|
|||
|
|
this.options.image.imageStyle = new this.ol.style.RegularShape(this.options.image);
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case 'cross':
|
|||
|
|
// 十字架
|
|||
|
|
this.options.image.radius = rule.Symbolizer.Size;
|
|||
|
|
this.options.image.points = 4;
|
|||
|
|
this.options.image.radius2 = 0;
|
|||
|
|
this.options.image.angle = 0;
|
|||
|
|
this.options.image.imageStyle = new this.ol.style.RegularShape(this.options.image);
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case 'x':
|
|||
|
|
// ×形
|
|||
|
|
this.options.image.radius = rule.Symbolizer.Size;
|
|||
|
|
this.options.image.points = 4;
|
|||
|
|
this.options.image.radius2 = 0;
|
|||
|
|
this.options.image.angle = Math.PI / 4;
|
|||
|
|
this.options.image.imageStyle = new this.ol.style.RegularShape(this.options.image);
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case 'img':
|
|||
|
|
let icon = this.iconCache[rule.Symbolizer.src];
|
|||
|
|
if (!icon) {
|
|||
|
|
this.options.image.src = rule.Symbolizer.src;
|
|||
|
|
this.options.image.anchorXUnits = 'fraction';
|
|||
|
|
this.options.image.anchorYUnits = 'fraction';
|
|||
|
|
this.options.image.anchor = [0.5, 0.5];
|
|||
|
|
this.options.image.offset = [0, 0];
|
|||
|
|
this.options.image.scale = 1;
|
|||
|
|
this.options.image.rotation = rule.Symbolizer.Rotation;
|
|||
|
|
this.options.image.crossOrigin = 'anonymous',
|
|||
|
|
this.options.image.imageStyle = new this.ol.style.Icon(this.options.image);
|
|||
|
|
this.iconCache[rule.Symbolizer.src] = this.options.image.imageStyle;
|
|||
|
|
} else {
|
|||
|
|
this.options.image.imageStyle = icon;
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
default:
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 构建option中的填充色
|
|||
|
|
if (rule.Symbolizer.FillColor) {
|
|||
|
|
let fillColor = this.buildRgba(rule.Symbolizer.FillColor, rule.Symbolizer.FillOpacity);
|
|||
|
|
this.options.fill = new this.ol.style.Fill({
|
|||
|
|
color: fillColor
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 构建option中的边框
|
|||
|
|
let strokeColor, strokeWidth, strokeDasharray;
|
|||
|
|
if (rule.Symbolizer.StrokeColor) {
|
|||
|
|
strokeColor = this.buildRgba(rule.Symbolizer.StrokeColor, rule.Symbolizer.StrokeOpacity);
|
|||
|
|
|
|||
|
|
if (rule.Symbolizer.StrokeWidth && rule.Symbolizer.StrokeWidth > 1) {
|
|||
|
|
strokeWidth = rule.Symbolizer.StrokeWidth;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (rule.Symbolizer.StrokeDasharray && rule.Symbolizer.StrokeDasharray.split(' ')) {
|
|||
|
|
strokeDasharray = rule.Symbolizer.StrokeDasharray.split(' ');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
this.options.stroke = new this.ol.style.Stroke({
|
|||
|
|
color: strokeColor,
|
|||
|
|
width: strokeWidth,
|
|||
|
|
lineDash: strokeDasharray
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 构建option中的标签
|
|||
|
|
if (rule.Label && JSON.stringify(rule.Label) != '{}') {
|
|||
|
|
this.options.text = {};
|
|||
|
|
this.options.text.text = this.properties[rule.Label.PropertyName];
|
|||
|
|
this.options.text.font = rule.Label.FontSize;
|
|||
|
|
this.options.text.offsetX = rule.Label.AnchorPointX;
|
|||
|
|
this.options.text.offsetY = rule.Label.AnchorPointY;
|
|||
|
|
|
|||
|
|
if (rule.Label.FillColor) {
|
|||
|
|
let fillColor = this.buildRgba(rule.Label.FillColor, rule.Label.FillOpacity);
|
|||
|
|
this.options.text.fill = new this.ol.style.Fill({
|
|||
|
|
color: fillColor
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (rule.Label.HaloFillColor) {
|
|||
|
|
let haloFillColor = this.buildRgba(rule.Label.HaloFillColor, rule.Label.HaloFillOpacity);
|
|||
|
|
this.options.text.stroke = new this.ol.style.Stroke({
|
|||
|
|
color: haloFillColor,
|
|||
|
|
width: rule.Label.HaloRadius
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 根据属性和比例条件进行判断
|
|||
|
|
filter: function () {
|
|||
|
|
for (let rule of this.json.Rule) {
|
|||
|
|
// 每次循环开始前将重置filterIsPass参数
|
|||
|
|
this.filterIsPass = undefined;
|
|||
|
|
|
|||
|
|
// 判断属性过滤条件,如果属性过滤条件参数不存在或者为空,则不做进一步的判断,直接赋值true
|
|||
|
|
if (rule.Filter instanceof Object == false ||
|
|||
|
|
JSON.stringify(rule.Filter) == '{}' ||
|
|||
|
|
rule.Filter.Conditions == undefined ||
|
|||
|
|
rule.Filter.Conditions.length == 0) {
|
|||
|
|
this.filterIsPass = true;
|
|||
|
|
} else {
|
|||
|
|
this.filterConditions(rule.Filter);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
this.buildOptions(rule);
|
|||
|
|
|
|||
|
|
// 判断比例条件是否符合
|
|||
|
|
// let minScale = rule.MinScaleDenominator ? rule.MinScaleDenominator : 10;
|
|||
|
|
// let maxScale = rule.MaxScaleDenominator ? rule.MaxScaleDenominator : 10000000000;
|
|||
|
|
// this.scaleIsPass = (this.scale < minScale || this.scale > maxScale) ? false : true;
|
|||
|
|
// if (this.filterIsPass && this.scaleIsPass) this.buildOptions(rule);
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 根据属性过滤条件进行判断
|
|||
|
|
filterConditions: function (filter) {
|
|||
|
|
for (let condition of filter.Conditions) {
|
|||
|
|
let bool, val = this.properties[condition.PropertyName] + '' || '';
|
|||
|
|
switch (condition.Condition) {
|
|||
|
|
case 'PropertyIsEqualTo':
|
|||
|
|
bool = (val == condition.Literal);
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case 'PropertyIsNotEqualTo':
|
|||
|
|
bool = (val != condition.Literal);
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case 'PropertyIsLike':
|
|||
|
|
bool = (val.indexOf(condition.Literal) > -1);
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case 'PropertyIsBetween':
|
|||
|
|
let num = parseFloat(val);
|
|||
|
|
bool = (num >= condition.LowerBoundary.Literal) && (num <= condition.UpperBoundary.Literal);
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
default:
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (filter.FilterType == 'And') {
|
|||
|
|
this.filterIsPass = (this.filterIsPass == undefined) ? bool : (this.filterIsPass && bool);
|
|||
|
|
} else if (filter.FilterType == 'Or') {
|
|||
|
|
this.filterIsPass = (this.filterIsPass == undefined) ? bool : (this.filterIsPass || bool);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
hexToRgb: function (hex) {
|
|||
|
|
let result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|||
|
|
return result ? {
|
|||
|
|
r: parseInt(result[1], 16),
|
|||
|
|
g: parseInt(result[2], 16),
|
|||
|
|
b: parseInt(result[3], 16)
|
|||
|
|
} : null;
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
buildRgba: function (hex, opa) {
|
|||
|
|
hex = this.hexToRgb(hex);
|
|||
|
|
if (hex == 'null') return "";
|
|||
|
|
return `rgba(${hex.r},${hex.g},${hex.b},${opa})`;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
//对外接口
|
|||
|
|
window.mars3d.TaitanPbfStyle = TaitanPbfStyle;
|
|||
|
|
|
|||
|
|
|
|||
|
|
})(window);
|