UNPKG

geoportal-extensions-openlayers

Version:

![GitHub package.json version](https://img.shields.io/github/package-json/v/IGNF/geoportal-extensions?filename=build%2Fscripts%2Frelease%2Fpackage-openlayers.json)

879 lines (843 loc) 30.3 kB
import Color from "../../Common/Utils/ColorUtils"; import Logger from "../../Common/Utils/LoggerByDefault"; import Markers from "../Controls/Utils/Markers"; // import ol import Feature from "ol/Feature"; // import Style import Style from "ol/style/Style"; import CircleStyle from "ol/style/Circle"; import IconStyle from "ol/style/Icon"; import FillStyle from "ol/style/Fill"; import StrokeStyle from "ol/style/Stroke"; import TextStyle from "ol/style/Text"; // import geom import Polygon from "ol/geom/Polygon"; import MultiPolygon from "ol/geom/MultiPolygon"; var logger = Logger.getLogger("styling"); Feature.prototype.setPropertyFill = function () { var style = this.getStyle(); if (!style) { return; } if (Array.isArray(style) && style.length === 0) { return; } var fill = style.getFill(); if (fill) { var colorFill = fill.getColor(); // array if (Array.isArray(colorFill)) { var cf = "rgba("; cf += colorFill[0] + ","; cf += colorFill[1] + ","; cf += colorFill[2] + ","; cf += colorFill[3] + ")"; colorFill = cf; } if (Color.isRGB(colorFill)) { var oColorFill = Color.rgbaToHex(colorFill); this.set("fill", oColorFill.hex); this.set("fill-opacity", oColorFill.opacity); } else { this.set("fill", colorFill); this.set("fill-opacity", 1); } } }; Feature.prototype.setPropertyStroke = function () { var style = this.getStyle(); if (!style) { return; } if (Array.isArray(style) && style.length === 0) { return; } var stroke = style.getStroke(); if (stroke) { var colorStroke = stroke.getColor(); // array if (Array.isArray(colorStroke)) { var cs = "rgba("; cs += colorStroke[0] + ","; cs += colorStroke[1] + ","; cs += colorStroke[2] + ","; cs += colorStroke[3] + ")"; colorStroke = cs; } if (Color.isRGB(colorStroke)) { var oColorStroke = Color.rgbaToHex(colorStroke); this.set("stroke", oColorStroke.hex); this.set("stroke-opacity", oColorStroke.opacity); } else { this.set("stroke", colorStroke); this.set("stroke-opacity", 1); } this.set("stroke-width", stroke.getWidth()); } }; Feature.prototype.setPropertyLabel = function () { var style = this.getStyle(); if (!style) { return; } if (Array.isArray(style) && style.length === 0) { return; } var isName = this.get("name") !== undefined; var label = style.getText(); if (label && isName) { var fill = style.getText().getFill(); if (fill) { var colorFill = fill.getColor(); // array if (Array.isArray(colorFill)) { var cf = "rgba("; cf += colorFill[0] + ","; cf += colorFill[1] + ","; cf += colorFill[2] + ","; cf += colorFill[3] + ")"; colorFill = cf; } if (Color.isRGB(colorFill)) { var oColorFill = Color.rgbaToHex(colorFill); this.set("label-fill", oColorFill.hex); this.set("label-fill-opacity", oColorFill.opacity); } else { this.set("label-fill", colorFill); this.set("label-fill-opacity", 1); } } var stroke = style.getText().getStroke(); if (stroke) { var colorStroke = stroke.getColor(); // array if (Array.isArray(colorStroke)) { var cs = "rgba("; cs += colorStroke[0] + ","; cs += colorStroke[1] + ","; cs += colorStroke[2] + ","; cs += colorStroke[3] + ")"; colorStroke = cs; } if (Color.isRGB(colorStroke)) { var oColorStroke = Color.rgbaToHex(colorStroke); this.set("label-stroke", oColorStroke.hex); this.set("label-stroke-opacity", oColorStroke.opacity); } else { this.set("label-stroke", colorStroke); this.set("label-stroke-opacity", 1); } this.set("label-stroke-width", stroke.getWidth()); } this.set("label-font", style.getText().getFont() || Styling.DEFAULT_TEXT.font); this.set("label-textAlign", style.getText().getTextAlign() || Styling.DEFAULT_TEXT.textAlign); } }; Feature.prototype.setPropertyMarker = function () { var style = this.getStyle(); if (!style) { return; } if (Array.isArray(style) && style.length === 0) { return; } var image = style.getImage(); if (image) { // si le tag image est seul... // c'est soit un marker ou soit un cercle ! if (image instanceof IconStyle) { var color = image.getColor(); // array if (Array.isArray(color)) { var c = "rgba("; c += color[0] + ","; c += color[1] + ","; c += color[2] + ","; c += color[3] + ")"; color = c; } // feature.set("marker-color", ""); // par defaut if (color) { var colorIcon = Color.rgbaToHex(color); this.set("marker-color", colorIcon.hex); } var scaleIcon = image.getScale(); switch (Math.round(scaleIcon * 2) / 2) { case 0: case 0.5: this.set("marker-size", "small"); break; case 1: this.set("marker-size", "medium"); break; case 1.5: case 2: this.set("marker-size", "large"); break; default: // this.set("marker-size", ""); // par defaut break; } // feature.set("marker-symbol", ""); // par defaut var srcImage = image.getSrc(); if (srcImage) { this.set("marker-symbol", srcImage); } // INFO // cas particulier où un objet est transformé : // * un cercle est transformé en icone // > les attributs du cercle sont à supprimer ! this.unset("circle-fill"); this.unset("circle-fill-opacity"); this.unset("circle-stroke"); this.unset("circle-stroke-width"); this.unset("circle-stroke-opacity"); this.unset("circle-radius"); } else { var fillImg = image.getFill(); if (fillImg) { var colorFillImg = fillImg.getColor(); // array if (Array.isArray(colorFillImg)) { var cfi = "rgba("; cfi += colorFillImg[0] + ","; cfi += colorFillImg[1] + ","; cfi += colorFillImg[2] + ","; cfi += colorFillImg[3] + ")"; colorFillImg = cfi; } if (Color.isRGB(colorFillImg)) { var oColorFillImg = Color.rgbaToHex(colorFillImg); this.set("circle-fill", oColorFillImg.hex); this.set("circle-fill-opacity", oColorFillImg.opacity); } else { this.set("circle-fill", colorFillImg); this.set("circle-fill-opacity", 1); } } var strokeImg = image.getStroke(); if (strokeImg) { var colorStrokeImg = strokeImg.getColor(); // array if (Array.isArray(colorStrokeImg)) { var csi = "rgba("; csi += colorStrokeImg[0] + ","; csi += colorStrokeImg[1] + ","; csi += colorStrokeImg[2] + ","; csi += colorStrokeImg[3] + ")"; colorStrokeImg = csi; } if (Color.isRGB(colorStrokeImg)) { var oColorStrokeImg = Color.rgbaToHex(colorStrokeImg); this.set("circle-stroke", oColorStrokeImg.hex); this.set("circle-stroke-opacity", oColorStrokeImg.opacity); } else { this.set("circle-stroke", colorStrokeImg); this.set("circle-stroke-opacity", 1); } this.set("circle-stroke-width", strokeImg.getWidth()); } var radius = image.getRadius(); this.set("circle-radius", radius); } } }; /** * @module Styling * @alias Gp.Styling * @todo ... * @description * A simple specification for styling GeoJSON / GPX / KML data. * * @see ol.format.GeoJSONExtended * @see ol.format.KMLExtended * @see ol.format.GPXExtended * * @example * feature.getStyle(); // null * feature.getProperties(); // {"stroke": "#ff0000", "stroke-width": 2} * Styling.defineStyleFromProperties(feature); * feature.getStyle(); // [Object Style] * * feature.getStyle(); // [Object Style] * feature.getProperties(); // {} * Styling.definePropertiesFromStyle(feature); * feature.getProperties(); // {"stroke": "#ff0000", "stroke-width": 2} * * var style = feature.getStyle(); // [Object Style] * var tag = Styling.setTag(style, "GPX"); * * ex. output GeoJSON: * ```json * "properties": { * "stroke": "#ff0000", * "stroke-width": 2 * } * ``` */ var Styling = { /** * Options to convert geometry */ APPLY_CONVERT_GEOM_GPX : true, /** * Default icon style options */ DEFAULT_ICON : { src : Markers["lightOrange"], anchor : [0.5, 1], scale : 1 }, /** * Default circle style options */ DEFAULT_CIRCLE : { radius : 10, fill : { opacity : 1, color : [0, 0, 0, 1] }, stroke : { width : 1, opacity : 1, color : [0, 0, 0, 1] } }, /** * Default stroke style options */ DEFAULT_STROKE : { width : 5, opacity : 1, color : [250, 250, 250, 1] }, /** * Default fill style options */ DEFAULT_FILL : { opacity : 1, color : [0, 0, 0, 1] }, /** * Default text style options * @see https://openlayers.org/en/v6.15.1/apidoc/module-ol_style_Text-Text.html */ DEFAULT_TEXT : { font : "16px sans", textAlign : "left", stroke : { color : [250, 250, 250, 1], width : 5, opactity : 1 }, fill : { opacity : 1, color : [0, 0, 0, 1] } // offsetX // offsetY // placement // scale // rotation // justify // padding }, /** * All styling tags * @function getListTags * @returns {Array} all styling tags * @example * "type", // type de geometrie * "fill", * "fill-opacity", * "stroke", * "stroke-opacity", * "stroke-width", * "circle-fill", * "circle-fill-opacity", * "circle-stroke", * "circle-stroke-opacity", * "circle-stroke-width", * "circle-radius", * "marker-symbol", * "marker-color", * "marker-size" */ getListTags : function () { return [ "type", "fill", "fill-opacity", "stroke", "stroke-opacity", "stroke-width", "circle-fill", "circle-fill-opacity", "circle-stroke", "circle-stroke-opacity", "circle-stroke-width", "circle-radius", "marker-symbol", "marker-color", "marker-size", "label-fill", "label-fill-opacity", "label-stroke", "label-stroke-width", "label-stroke-opacity", "label-font", "label-textAlign" ]; }, /** * Transform feature properties to a native style * * @function defineStyleFromProperties * @param {*} feature - ... * @returns {*} style - ... * @public * * @description * A la lecture du format : * > tag styling ---> feature properties ---> feature style * * Les balises de 'styling' du fichier sont ajoutées dans les properties de chaque features * (opération native sous OpenLayers): * * Ex. avec le format GeoJSON : * ```json * "properties": { * "stroke": "#000000", -> feature.get("stroke"); * "stroke-width": 13, -> feature.get("stroke-width"); * "stroke-opacity": 0.8, -> feature.get("stroke-opacity"); * "fill": "#a03737", -> feature.get("fill"); * "fill-opacity": 0.5 -> feature.get("fill-opacity"); * } * ``` * * Ensuite, les properties des features sont transformées dans le style natif : * * ```js * // Ex. * feature.setStyle(new Style({ * fill : new FillStyle({ * color : Color.hexToRgba(feature.get("fill"), feature.get("fill-opacity") || 1) * }), * stroke : new StrokeStyle({ * color : Color.hexToRgba(feature.get("stroke"), feature.get("stroke-opacity")) * width : feature.get("stroke-width") * }) * })); * ``` */ defineStyleFromProperties : function (feature) { // style var style = null; // les options de styles définis dans le format var options = {}; // properties : // "marker-size" -> icon // "marker-symbol" -> icon // "marker-color" -> icon var marker = null; if (feature.get("marker-color") || feature.get("marker-size") || feature.get("marker-symbol")) { marker = {}; // icone par defaut marker["src"] = this.DEFAULT_ICON.src; marker["anchor"] = this.DEFAULT_ICON.anchor; var symbolMarker = feature.get("marker-symbol"); if (symbolMarker) { if (symbolMarker.search("data:image/png;base64") !== -1) { // icone du portail marker["src"] = symbolMarker; } else { // TODO // utiliser les symboles de Maki // (cf. https://labs.mapbox.com/maki-icons/) } } var colorMarker = feature.get("marker-color"); if (Color.isHex(colorMarker)) { marker["color"] = Color.hexToRgba(colorMarker, 1); } var size = feature.get("marker-size"); if (size) { switch (size) { case "small": marker["scale"] = 0.5; break; case "medium": marker["scale"] = 1; break; case "large": marker["scale"] = 1.5; break; default: marker["scale"] = this.DEFAULT_ICON.scale; break; } } } // properties : // "stroke" -> line / polygon // "stroke-opacity" -> line / polygon // "stroke-width" -> line / polygon var stroke = null; if (feature.get("stroke") || feature.get("stroke-opacity") || feature.get("stroke-width")) { stroke = {}; stroke["color"] = Color.hexToRgba(feature.get("stroke"), +feature.get("stroke-opacity") || this.DEFAULT_STROKE.opacity); stroke["width"] = +feature.get("stroke-width") || this.DEFAULT_STROKE.width; } // properties : // "fill" -> polygon // "fill-opacity" -> polygon var fill = null; if (feature.get("fill") || feature.get("fill-opacity")) { fill = {}; fill["color"] = Color.hexToRgba(feature.get("fill"), +feature.get("fill-opacity") || this.DEFAULT_FILL.opacity); } // properties : // "label-fill", // "label-fill-opacity", // "label-stroke", // "label-stroke-width", // "label-stroke-opacity", // "label-font", // "label-textAlign" // "name" -> text var labelStroke = null; var labelFill = null; var isLabel = feature.get("name") !== ""; if (isLabel) { if (feature.get("label-fill") || feature.get("label-fill-opacity")) { labelFill = {}; labelFill["color"] = Color.hexToRgba(feature.get("label-fill"), +feature.get("label-fill-opacity") || this.DEFAULT_TEXT.fill.opacity); } if (feature.get("label-stroke") || feature.get("label-stroke-opacity") || feature.get("label-stroke-width")) { labelStroke = {}; labelStroke["color"] = Color.hexToRgba(feature.get("label-stroke"), +feature.get("label-stroke-opacity") || this.DEFAULT_TEXT.stroke.opacity); labelStroke["width"] = +feature.get("label-stroke-width") || this.DEFAULT_TEXT.stroke.width; } } // properties : // "circle-fill" // "circle-stroke" // "circle-stroke-width" // "circle-radius" var circleRadius = feature.get("circle-radius") || this.DEFAULT_CIRCLE.radius; var circleStroke = null; if (feature.get("circle-stroke") || feature.get("circle-stroke-opacity") || feature.get("circle-stroke-width")) { circleStroke = {}; circleStroke["color"] = Color.hexToRgba(feature.get("circle-stroke"), +feature.get("circle-stroke-opacity") || this.DEFAULT_CIRCLE.stroke.opacity); circleStroke["width"] = +feature.get("circle-stroke-width") || this.DEFAULT_CIRCLE.stroke.width; } var circleFill = null; if (feature.get("circle-fill") || feature.get("circle-fill-opacity")) { circleFill = {}; circleFill["color"] = Color.hexToRgba(feature.get("circle-fill"), +feature.get("circle-fill-opacity") || this.DEFAULT_CIRCLE.fill.opacity); } // options du Style en fonction du type de geometrie var type = feature.getGeometry().getType(); switch (type) { case "Circle": case "Point": case "MultiPoint": // Cercle var isCircle = false; var optionsCircle = {}; if (circleStroke) { optionsCircle["stroke"] = new StrokeStyle(circleStroke); } if (circleFill) { optionsCircle["fill"] = new FillStyle(circleFill); } if (Object.keys(optionsCircle).length !== 0) { isCircle = true; optionsCircle["radius"] = +circleRadius; // Conversion en nombre options["image"] = new CircleStyle(optionsCircle); } // Ponctuel if (marker) { options["image"] = new IconStyle(marker); } // Label if (isLabel) { var optionsText = {}; if (labelStroke) { optionsText["stroke"] = new StrokeStyle(labelStroke); } if (labelFill) { optionsText["fill"] = new FillStyle(labelFill); } if (Object.keys(optionsText).length !== 0) { optionsText["text"] = feature.get("name"); optionsText["textAlign"] = feature.get("label-textAlign") || this.DEFAULT_TEXT.textAlign; optionsText["font"] = feature.get("label-font") || this.DEFAULT_TEXT.font; options["text"] = new TextStyle( Object.assign({}, this.DEFAULT_TEXT, optionsText )); } else { // on applique un style par defaut sur le label // pour un marker ou un cercle if (marker || isCircle) { var styleText = new TextStyle( Object.assign({}, this.DEFAULT_TEXT, { fill : new FillStyle(this.DEFAULT_TEXT.fill), stroke : new StrokeStyle(this.DEFAULT_TEXT.stroke) } ) ); if (styleText) { var cloneStyleText = styleText.clone(); cloneStyleText.setText(feature.get("name")); options["text"] = cloneStyleText; } } } } break; case "Polygon": case "MultiPolygon": if (stroke) { options["stroke"] = new StrokeStyle(stroke); } if (fill) { options["fill"] = new FillStyle(fill); } break; case "LineString": case "MultiLineString": if (stroke) { options["stroke"] = new StrokeStyle(stroke); } if (this.APPLY_CONVERT_GEOM_GPX && fill) { // INFO // Lors d'une transformation de type de geometrie, le type est renseigné. // Pour le format GPX, // -> on transforme une surface vers ligne lors de l'écriture // -> on transforme une ligne vers une surface lors de la lecture si le type est précisé ! var initType = feature.get("type"); if (initType && (initType === "Polygon" || initType === "MultiPolygon")) { options["fill"] = new FillStyle(fill); var f = feature.clone(); var ClassPoly = (type === "LineString") ? Polygon : MultiPolygon; feature.setGeometry(new ClassPoly([f.getGeometry().getCoordinates()])); } } break; default: break; } // si aucun style disponible, on utilisera le style par defaut defini // par l'utilisateur ou l'application if (Object.keys(options).length !== 0) { style = new Style(options); } return style; }, /** * Define a default style function to apply to a feature * * @function defineStyleFunctionByDefault * @param {Object} defaultStyle - ... * @returns {Function} style function * @public * * @description * ... */ defineStyleFunctionByDefault : function (defaultStyle) { if (!defaultStyle) { return []; } if (Object.keys(defaultStyle).length === 0) { return []; } // les styles par defaut var styleFunction = (feature, resolution) => { var style = null; var type = feature.getGeometry().getType(); switch (type) { case "Point": case "MultiPoint": // on n'a aucune information sur le type de style à appliquer sur un "Point" : // * label ou // * marker ou // * marker avec label // donc, c'est en fonction des styles par defaut... var opts = {}; if (defaultStyle.getImage()) { opts["image"] = defaultStyle.getImage(); } if (defaultStyle.getText() && feature.get("name")) { var styleText = defaultStyle.getText().clone(); styleText.setText(feature.get("name")); opts["text"] = styleText; } style = new Style(opts); break; case "Circle": var optsc = {}; var optsCircle = {}; if (defaultStyle.getFill()) { optsCircle.fill = defaultStyle.getFill(); } if (defaultStyle.getStroke()) { optsCircle.stroke = defaultStyle.getStroke(); } if (defaultStyle.getText() && feature.get("name")) { var styleTextCircle = defaultStyle.getText().clone(); styleTextCircle.setText(feature.get("name")); optsc.text = styleTextCircle; } if (Object.keys(optsCircle).length !== 0) { // FIXME param radius ? optsCircle.radius = 3; optsc.image = new CircleStyle(optsCircle); } style = new Style(optsc); break; case "Polygon": case "MultiPolygon": var optsp = {}; if (defaultStyle.getFill()) { optsp.fill = defaultStyle.getFill(); } if (defaultStyle.getStroke()) { optsp.stroke = defaultStyle.getStroke(); } style = new Style(optsp); break; case "LineString": case "LinearRing": case "MultiLineString": var optsl = {}; if (defaultStyle.getStroke()) { optsl.stroke = defaultStyle.getStroke(); } style = new Style(optsl); break; } return [style]; }; return styleFunction; }, /** * Transform a native style to feature properties by type of geometry * * @todo not yet implemented ! * @param {*} feature - feature */ definePropertiesFromStyleByType : function (feature) { var geomType = feature.getGeometry().getType(); switch (geomType) { case "Point": case "MultiPoint": feature.setPropertyMarker(); feature.setPropertyLabel(); break; case "LineString": case "MultiLineString": feature.setPropertyStroke(); break; case "Polygon": case "MultiPolygon": feature.setPropertyStroke(); feature.setPropertyFill(); break; default: break; } }, /** * Transform a native style to feature properties * * @function definePropertiesFromStyle * @param {*} feature - ... * @public * * @description * A l'écriture du format. * > feature style --> feature properties --> tag styling * * Le style natif est récupéré pour chaque feature : * * ```js * // Ex. * var style = feature.getStyle(); * ``` * * Ensuite, le style natif est transformé en properties pour chaque feature : * * ```js * // Ex. * var stroke = style.getStroke(); * var oColorStroke = Color.rgbaToHex(stroke.getColor()); * feature.set("stroke", oColorStroke.hex); // #000000 * feature.set("stroke-opacity", oColorStroke.opacity); // 0.8 * ``` * * Et, chaque properties des features sont ecrites dans le format du fichier * (opération native sous OpenLayers) : * * Ex. avec le format GeoJSON : * ```json * "properties": { * "stroke": "#000000", * "stroke-opacity": 0.8 * } * ``` */ definePropertiesFromStyle : function (feature) { var style = feature.getStyle() || feature.getStyleFunction(); if (style) { // style ajouté via une fonction, pour les styles par defaut par ex. if (typeof style === "function") { var styles = style.call(this, feature, 0); if (styles && styles.length !== 0) { style = (Array.isArray(styles)) ? styles[0] : styles; feature.setStyle(style); } else { // au cas où... return; } } this.definePropertiesFromStyleByType(feature); } }, /** * Transform a native style to tags 'styling' into the format * * @function defineTagFromStyle * @param {*} style - ... * @param {String} format - ... * @returns {String} tags stringify into the format (json / xml) * @todo * @public * * @description * A partir d'un style natif, on le transforme en balise de 'styling' dans le format demandé, * que l'on peut ensuite inserer dans le fichier. * > style ---> tag styling * */ defineTagFromStyle : function (style, format) { logger.trace("todo..."); return null; } }; export default Styling;