/* 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_style_Style from 'ol/style/Style.js' import {asString as ol_color_asString} from 'ol/color.js' import {asArray as ol_color_asArray} from 'ol/color.js' import {ol_coordinate_dist2d} from '../geom/GeomUtils.js' /** 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) * @constructor * @extends {ol_style_Style} * @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 {boolean} [options.noOverlap=false] prevent segments overlaping * @param {number} options.offset0 offset at line start * @param {number} options.offset1 offset at line end */ var ol_style_FlowLine = class olstyleFlowLine extends ol_style_Style { constructor(options) { options = options || {} super({ stroke: options.stroke, text: options.text, zIndex: options.zIndex, geometry: options.geometry }) this.setRenderer(this._render.bind(this)) // 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) // Overlap this._noOverlap = options.noOverlap } /** Set the initial width * @param {number} width width, default 0 */ setWidth(width) { this._width = width || 0 } /** Set the final width * @param {number} width width, default 0 */ setWidth2(width) { this._width2 = width } /** Get offset at start or end * @param {number} where 0=start, 1=end * @return {number} width */ getOffset(where) { return this._offset[where] } /** Add an offset at start or end * @param {number} width * @param {number} where 0=start, 1=end */ setOffset(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 */ setLineCap(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} */ getWidth(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 */ setColor(color) { try { this._color = ol_color_asArray(color) } catch (e) { this._color = [0, 0, 0, 1] } } /** Set the final color * @param {ol.colorLike} color */ setColor2(color) { try { this._color2 = ol_color_asArray(color) } catch (e) { this._color2 = null } } /** Set the arrow color * @param {ol.colorLike} color */ setArrowColor(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} */ getColor(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 */ getArrow() { return this._arrow } /** Set arrow * @param {number} n -1 | 0 | 1 | 2, default: 0 */ setArrow(n) { this._arrow = parseInt(n) if (this._arrow < -1 || this._arrow > 2) this._arrow = 0 } /** getArrowSize * @return {ol.size} */ getArrowSize() { return this._arrowSize || [16, 16] } /** setArrowSize * @param {number|ol.size} size */ setArrowSize(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 */ drawArrow(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