UNPKG

kmap-ui

Version:

A components of zmap base on vue2.X

384 lines (354 loc) 11.8 kB
/* Copyright (c) 2019 Jean-Marc VIGLINO, released under the CeCILL-B license (French BSD license) (http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt). */ import ol_ext_inherits from '../util/ext' import ol_style_Style from 'ol/style/Style' import {asString as ol_color_asString} from 'ol/color' import {asArray as ol_color_asArray} from 'ol/color' import {ol_coordinate_dist2d} from '../geom/GeomUtils' import '../geom/LineStringSplitAt' /** Flow line style * Draw LineString with a variable color / width * NB: the FlowLine style doesn't impress the hit-detection. * If you want your lines to be sectionable you have to add your own style to handle this. * (with transparent line: stroke color opacity to .1 or zero width) * @extends {ol_style_Style} * @constructor * @param {Object} options * @param {boolean} options.visible draw only the visible part of the line, default true * @param {number|function} options.width Stroke width or a function that gets a feature and the position (beetween [0,1]) and returns current width * @param {number} options.width2 Final stroke width (if width is not a function) * @param {number} options.arrow Arrow at start (-1), at end (1), at both (2), none (0), default geta * @param {ol.colorLike|function} options.color Stroke color or a function that gets a feature and the position (beetween [0,1]) and returns current color * @param {ol.colorLike} options.color2 Final sroke color if color is nor a function * @param {ol.colorLike} options.arrowColor Color of arrows, if not defined used color or color2 * @param {string} options.lineCap CanvasRenderingContext2D.lineCap 'butt' | 'round' | 'square', default 'butt' * @param {number|ol.size} options.arrowSize height and width of the arrow, default 16 * @param {number} options.offset0 offset at line start * @param {number} options.offset1 offset at line end */ var ol_style_FlowLine = function(options) { if (!options) options = {}; ol_style_Style.call (this, { renderer: this._render.bind(this), stroke: options.stroke, text: options.text, zIndex: options.zIndex, geometry: options.geometry }); // Draw only visible this._visible = (options.visible !== false); // Width if (typeof options.width === 'function') { this._widthFn = options.width; } else { this.setWidth(options.width); } this.setWidth2(options.width2); // Color if (typeof options.color === 'function') { this._colorFn = options.color; } else { this.setColor(options.color); } this.setColor2(options.color2); // LineCap this.setLineCap(options.lineCap); // Arrow this.setArrow(options.arrow); this.setArrowSize(options.arrowSize); this.setArrowColor(options.arrowColor); // Offset this._offset = [0,0]; this.setOffset(options.offset0, 0); this.setOffset(options.offset1, 1); }; ol_ext_inherits(ol_style_FlowLine, ol_style_Style); /** Set the initial width * @param {number} width width, default 0 */ ol_style_FlowLine.prototype.setWidth = function(width) { this._width = width || 0; }; /** Set the final width * @param {number} width width, default 0 */ ol_style_FlowLine.prototype.setWidth2 = function(width) { this._width2 = width; }; /** Get offset at start or end * @param {number} where 0=start, 1=end * @return {number} width */ ol_style_FlowLine.prototype.getOffset = function(where) { return this._offset[where]; }; /** Add an offset at start or end * @param {number} width * @param {number} where 0=start, 1=end */ ol_style_FlowLine.prototype.setOffset = function(width, where) { width = Math.max(0, parseFloat(width)); switch(where) { case 0: { this._offset[0] = width; break; } case 1: { this._offset[1] = width; break; } } }; /** Set the LineCap * @param {steing} cap LineCap (round or butt), default butt */ ol_style_FlowLine.prototype.setLineCap = function(cap) { this._lineCap = (cap==='round' ? 'round' : 'butt'); }; /** Get the current width at step * @param {ol.feature} feature * @param {number} step current drawing step beetween [0,1] * @return {number} */ ol_style_FlowLine.prototype.getWidth = function(feature, step) { if (this._widthFn) return this._widthFn(feature, step); var w2 = (typeof(this._width2) === 'number') ? this._width2 : this._width; return this._width + (w2-this._width) * step; }; /** Set the initial color * @param {ol.colorLike} color */ ol_style_FlowLine.prototype.setColor = function(color) { try{ this._color = ol_color_asArray(color); } catch(e) { this._color = [0,0,0,1]; } }; /** Set the final color * @param {ol.colorLike} color */ ol_style_FlowLine.prototype.setColor2 = function(color) { try { this._color2 = ol_color_asArray(color); } catch(e) { this._color2 = null; } }; /** Set the arrow color * @param {ol.colorLike} color */ ol_style_FlowLine.prototype.setArrowColor = function(color) { try { this._acolor = ol_color_asString(color); } catch(e) { this._acolor = null; } }; /** Get the current color at step * @param {ol.feature} feature * @param {number} step current drawing step beetween [0,1] * @return {string} */ ol_style_FlowLine.prototype.getColor = function(feature, step) { if (this._colorFn) return ol_color_asString(this._colorFn(feature, step)); var color = this._color; var color2 = this._color2 || this._color return 'rgba('+ + Math.round(color[0] + (color2[0]-color[0]) * step) +',' + Math.round(color[1] + (color2[1]-color[1]) * step) +',' + Math.round(color[2] + (color2[2]-color[2]) * step) +',' + (color[3] + (color2[3]-color[3]) * step) +')'; }; /** Get arrow */ ol_style_FlowLine.prototype.getArrow = function() { return this._arrow; }; /** Set arrow * @param {number} n -1 | 0 | 1 | 2, default: 0 */ ol_style_FlowLine.prototype.setArrow = function(n) { this._arrow = parseInt(n); if (this._arrow < -1 || this._arrow > 2) this._arrow = 0; } /** getArrowSize * @return {ol.size} */ ol_style_FlowLine.prototype.getArrowSize = function() { return this._arrowSize || [16,16]; }; /** setArrowSize * @param {number|ol.size} size */ ol_style_FlowLine.prototype.setArrowSize = function(size) { if (Array.isArray(size)) this._arrowSize = size; else if (typeof(size) === 'number') this._arrowSize = [size,size]; }; /** drawArrow * @param {CanvasRenderingContext2D} ctx * @param {ol.coordinate} p0 * @param ol.coordinate} p1 * @param {number} width * @param {number} ratio pixelratio * @private */ ol_style_FlowLine.prototype.drawArrow = function (ctx, p0, p1, width, ratio) { var asize = this.getArrowSize()[0] * ratio; var l = ol_coordinate_dist2d(p0, p1); var dx = (p0[0]-p1[0])/l; var dy = (p0[1]-p1[1])/l; width = Math.max(this.getArrowSize()[1]/2, width/2) * ratio; ctx.beginPath(); ctx.moveTo(p0[0],p0[1]); ctx.lineTo(p0[0]-asize*dx+width*dy, p0[1]-asize*dy-width*dx); ctx.lineTo(p0[0]-asize*dx-width*dy, p0[1]-asize*dy+width*dx); ctx.lineTo(p0[0],p0[1]); ctx.fill(); }; /** Renderer function * @param {Array<ol.coordinate>} geom The pixel coordinates of the geometry in GeoJSON notation * @param {ol.render.State} e The olx.render.State of the layer renderer */ ol_style_FlowLine.prototype._render = function(geom, e) { if (e.geometry.getType()==='LineString') { var i, g, p, ctx = e.context; // Get geometry used at drawing if (!this._visible) { var a = e.pixelRatio / e.resolution; g = e.geometry.getCoordinates(); var dx = geom[0][0] - g[0][0] * a; var dy = geom[0][1] + g[0][1] * a; geom = []; for (i=0; p=g[i]; i++) { geom[i] = [ dx + p[0] * a, dy - p[1] * a]; } } var asize = this.getArrowSize()[0] * e.pixelRatio; ctx.save(); // Offsets if (this.getOffset(0)) this._splitAsize(geom, this.getOffset(0) * e.pixelRatio) if (this.getOffset(1)) this._splitAsize(geom, this.getOffset(1) * e.pixelRatio, true) // Arrow 1 if (geom.length>1 && (this.getArrow()===-1 || this.getArrow()===2)) { p = this._splitAsize(geom, asize); if (this._acolor) ctx.fillStyle = this._acolor; else ctx.fillStyle = this.getColor(e.feature, 0); this.drawArrow(ctx, p[0], p[1], this.getWidth(e.feature, 0), e.pixelRatio); } // Arrow 2 if (geom.length>1 && this.getArrow()>0) { p = this._splitAsize(geom, asize, true); if (this._acolor) ctx.fillStyle = this._acolor; else ctx.fillStyle = this.getColor(e.feature, 1); this.drawArrow(ctx, p[0], p[1], this.getWidth(e.feature, 1), e.pixelRatio); } // Split into var geoms = this._splitInto(geom, 255, 2); var k = 0; var nb = geoms.length; // Draw ctx.lineJoin = 'round'; ctx.lineCap = this._lineCap || 'butt'; if (geoms.length > 1) { for (k=0; k<geoms.length; k++) { var step = k/nb; g = geoms[k]; ctx.lineWidth = this.getWidth(e.feature, step) * e.pixelRatio; ctx.strokeStyle = this.getColor(e.feature, step); ctx.beginPath(); ctx.moveTo(g[0][0],g[0][1]); for (i=1; p=g[i]; i++) { ctx.lineTo(p[0],p[1]); } ctx.stroke(); } } ctx.restore(); } }; /** Split extremity at * @param {ol.geom.LineString} geom * @param {number} asize * @param {boolean} end start=false or end=true, default false (start) */ ol_style_FlowLine.prototype._splitAsize = function(geom, asize, end) { var p, p1, p0; var dl, d = 0; if (end) p0 = geom.pop(); else p0 = geom.shift(); p = p0; while(geom.length) { if (end) p1 = geom.pop(); else p1 = geom.shift(); dl = ol_coordinate_dist2d(p,p1); if (d+dl > asize) { p = [p[0]+(p1[0]-p[0])*(asize-d)/dl, p[1]+(p1[1]-p[1])*(asize-d)/dl]; dl = ol_coordinate_dist2d(p,p0); if (end) { geom.push(p1); geom.push(p); geom.push([p[0]+(p0[0]-p[0])/dl, p[1]+(p0[1]-p[1])/dl]); } else { geom.unshift(p1); geom.unshift(p); geom.unshift([p[0]+(p0[0]-p[0])/dl, p[1]+(p0[1]-p[1])/dl]); } break; } d += dl; p = p1; } return [p0,p]; }; /** Split line geometry into equal length geometries * @param {Array<ol.coordinate>} geom * @param {number} nb number of resulting geometries, default 255 * @param {number} nim minimum length of the resulting geometries, default 1 */ ol_style_FlowLine.prototype._splitInto = function(geom, nb, min) { var i, p; // Split geom into equal length geoms var geoms = []; var dl, l = 0; for (i=1; p=geom[i]; i++) { l += ol_coordinate_dist2d(geom[i-1], p); } var length = Math.max (min||2, l/(nb||255)); var p0 = geom[0]; l = 0; var g = [p0]; i = 1; p = geom[1]; while (i < geom.length) { var dx = p[0]-p0[0]; var dy = p[1]-p0[1]; dl = Math.sqrt(dx*dx + dy*dy); if (l+dl > length) { var d = (length-l) / dl; g.push([ p0[0] + dx * d, p0[1] + dy * d ]); geoms.push(g); p0 =[ p0[0] + dx * d*.9, p0[1] + dy * d*.9 ]; g = [p0]; l = 0; } else { l += dl; p0 = p; g.push(p0); i++; p = geom[i]; } } geoms.push(g); return geoms; } export default ol_style_FlowLine