UNPKG

ol-ext-datatable

Version:
272 lines (252 loc) 8.6 kB
/* Copyright (c) 2018 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 from 'ol' import ol_has from 'ol/has' import ol_style_Stroke from 'ol/style/stroke' import ol_color from 'ol/color' import ol_style_FillPattern from './FillPattern' /** * @classdesc * Stroke style with named pattern * * @constructor * @param {any} options * @param {ol.style.Image|undefined} options.image an image pattern, image must be preloaded to draw on first call * @param {number|undefined} options.opacity opacity with image pattern, default:1 * @param {olx.style.fillPattern} options.pattern pattern name (override by image option) * @param {ol.colorLike} options.color pattern color * @param {ol.style.Fill} options.fill fill color (background) * @param {number} options.offset pattern offset for hash/dot/circle/cross pattern * @param {number} options.size line size for hash/dot/circle/cross pattern * @param {number} options.spacing spacing for hash/dot/circle/cross pattern * @param {number|bool} options.angle angle for hash pattern / true for 45deg dot/circle/cross * @param {number} options.scale pattern scale * @extends {ol.style.Fill} * @implements {ol.structs.IHasChecksum} * @api */ var ol_style_StrokePattern = function(options) { if (!options) options = {}; var pattern; var canvas = this.canvas_ = document.createElement('canvas'); var scale = Number(options.scale)>0 ? Number(options.scale) : 1; var ratio = scale*ol_has.DEVICE_PIXEL_RATIO || ol_has.DEVICE_PIXEL_RATIO; var ctx = canvas.getContext('2d'); if (options.image) { options.image.load(); var img = options.image.getImage(); if (img.width) { canvas.width = Math.round(img.width *ratio); canvas.height = Math.round(img.height *ratio); ctx.globalAlpha = typeof(options.opacity) == 'number' ? options.opacity:1; ctx.drawImage(img, 0,0, img.width, img.height, 0, 0, canvas.width, canvas.height); pattern = ctx.createPattern(canvas, 'repeat'); } else { var self = this; pattern = [0,0,0,0]; img.onload = function () { canvas.width = Math.round(img.width *ratio); canvas.height = Math.round(img.height *ratio); ctx.globalAlpha = typeof(options.opacity) == 'number' ? options.opacity:1; ctx.drawImage(img, 0,0, img.width, img.height, 0, 0, canvas.width, canvas.height); pattern = ctx.createPattern(canvas, 'repeat'); self.setColor(pattern); } } } else { var pat = this.getPattern_(options); canvas.width = Math.round(pat.width *ratio); canvas.height = Math.round(pat.height *ratio); ctx.beginPath(); if (options.fill) { ctx.fillStyle = ol_color.asString(options.fill.getColor()); ctx.fillRect(0,0, canvas.width, canvas.height); } ctx.scale(ratio,ratio); ctx.lineCap = "round"; ctx.lineWidth = pat.stroke || 1; ctx.fillStyle = ol_color.asString(options.color||"#000"); ctx.strokeStyle = ol_color.asString(options.color||"#000"); if (pat.circles) for (var i=0; i<pat.circles.length; i++) { var ci = pat.circles[i]; ctx.beginPath(); ctx.arc(ci[0], ci[1], ci[2], 0,2*Math.PI); if (pat.fill) ctx.fill(); if (pat.stroke) ctx.stroke(); } if (!pat.repeat) pat.repeat=[[0,0]]; if (pat.char) { ctx.font = pat.font || (pat.width)+"px Arial"; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; if (pat.angle) { ctx.fillText(pat.char, pat.width/4, pat.height/4); ctx.fillText(pat.char, 5*pat.width/4, 5*pat.height/4); ctx.fillText(pat.char, pat.width/4, 5*pat.height/4); ctx.fillText(pat.char, 5*pat.width/4, pat.height/4); ctx.fillText(pat.char, 3*pat.width/4, 3*pat.height/4); ctx.fillText(pat.char, -pat.width/4, -pat.height/4); ctx.fillText(pat.char, 3*pat.width/4, -pat.height/4); ctx.fillText(pat.char, -pat.width/4, 3*pat.height/4); } else ctx.fillText(pat.char, pat.width/2, pat.height/2); } if (pat.lines) for (var i=0; i<pat.lines.length; i++) for (var r=0; r<pat.repeat.length; r++) { var li = pat.lines[i]; ctx.beginPath(); ctx.moveTo(li[0]+pat.repeat[r][0],li[1]+pat.repeat[r][1]); for (var k=2; k<li.length; k+=2) { ctx.lineTo(li[k]+pat.repeat[r][0],li[k+1]+pat.repeat[r][1]); } if (pat.fill) ctx.fill(); if (pat.stroke) ctx.stroke(); ctx.save() ctx.strokeStyle = 'red'; ctx.strokeWidth = 0.1; //ctx.strokeRect(0,0,canvas.width,canvas.height); ctx.restore() } pattern = ctx.createPattern(canvas, 'repeat'); if (options.offset) { var offset = options.offset; if (typeof(offset) == "number") offset = [offset,offset]; if (offset instanceof Array) { var dx = Math.round((offset[0]*ratio)); var dy = Math.round((offset[1]*ratio)); // New pattern ctx.scale(1/ratio,1/ratio) ctx.clearRect(0,0,canvas.width,canvas.height); ctx.translate(dx,dy); ctx.fillStyle = pattern; ctx.fillRect(-dx, -dy, canvas.width,canvas.height); pattern = ctx.createPattern(canvas, 'repeat'); } } } options.color = pattern; ol_style_Stroke.call (this, options); }; ol.inherits(ol_style_StrokePattern, ol_style_Stroke); /** * Clones the style. * @return {ol_style_StrokePattern} */ ol_style_StrokePattern.prototype.clone = function() { var s = ol_style_Fill.prototype.clone.call(this); s.canvas_ = this.canvas_; return s; }; /** Get canvas used as pattern * @return {canvas} */ ol_style_StrokePattern.prototype.getImage = function() { return this.canvas_; } /** Get pattern * @param {olx.style.FillPatternOption} */ ol_style_StrokePattern.prototype.getPattern_ = function(options) { var pat = ol_style_FillPattern.prototype.patterns[options.pattern] || ol_style_FillPattern.prototype.patterns.dot; var d = Math.round(options.spacing)||10; var d2 = Math.round(d/2)+0.5; switch (options.pattern) { case 'dot': case 'circle': { var size = options.size===0 ? 0 : options.size/2 || 2; if (!options.angle) { pat.width = pat.height = d; pat.circles = [[ d/2, d/2, size ]] if (options.pattern=='circle') { pat.circles = pat.circles.concat([ [ d/2+d, d/2, size ], [ d/2-d, d/2, size ], [ d/2, d/2+d, size ], [ d/2, d/2-d, size ], [ d/2+d, d/2+d, size ], [ d/2+d, d/2-d, size ], [ d/2-d, d/2+d, size ], [ d/2-d, d/2-d, size ] ]) }; } else { d = pat.width = pat.height = Math.round(d*1.4); pat.circles = [[ d/4, d/4, size ], [ 3*d/4, 3*d/4, size ]]; if (options.pattern=='circle') { pat.circles = pat.circles.concat([ [ d/4+d, d/4, size ], [ d/4, d/4+d, size ], [ 3*d/4-d, 3*d/4, size ], [ 3*d/4, 3*d/4-d, size ], [ d/4+d, d/4+d, size ], [ 3*d/4-d, 3*d/4-d, size ] ]); } } break; } case 'tile': case 'square': { var size = options.size===0 ? 0 : options.size/2 || 2; if (!options.angle) { pat.width = pat.height = d; pat.lines = [[ d/2-size, d/2-size, d/2+size, d/2-size, d/2+size, d/2+size, d/2-size,d/2+size, d/2-size, d/2-size ]] } else { pat.width = pat.height = d; //size *= Math.sqrt(2); pat.lines = [[ d/2-size,d/2, d/2,d/2-size, d/2+size,d/2, d/2,d/2+size, d/2-size,d/2 ]] } if (options.pattern=='square') pat.repeat = [[0,0], [0,d], [d,0], [0,-d], [-d,0], [-d,-d], [d,d], [-d,d], [d,-d] ] break; } case 'cross': { // Limit angle to 0 | 45 if (options.angle) options.angle = 45; } case 'hatch': { var a = Math.round(((options.angle||0)-90)%360); if (a>180) a -= 360; a *= Math.PI/180; var cos = Math.cos(a); var sin = Math.sin(a); if (Math.abs(sin)<0.0001) { pat.width = pat.height = d; pat.lines = [ [ 0,0.5, d, 0.5 ] ]; pat.repeat = [ [0,0], [0,d] ]; } else if (Math.abs(cos)<0.0001) { pat.width = pat.height = d; pat.lines = [ [ 0.5,0, 0.5, d] ]; pat.repeat = [ [0,0], [d,0] ]; if (options.pattern=='cross') { pat.lines.push ([ 0,0.5, d, 0.5 ]); pat.repeat.push([0,d]); } } else { var w = pat.width = Math.round(Math.abs(d/sin)) || 1; var h = pat.height = Math.round(Math.abs(d/cos)) || 1; if (options.pattern=='cross') { pat.lines = [ [-w,-h, 2*w,2*h], [2*w,-h, -w,2*h] ]; pat.repeat = [ [0,0] ]; } else if (cos*sin>0) { pat.lines = [ [-w,-h, 2*w,2*h] ]; pat.repeat = [ [0,0], [w,0], [0,h] ]; } else { pat.lines = [ [2*w,-h, -w,2*h] ]; pat.repeat = [ [0,0], [-w,0], [0,h] ]; } } pat.stroke = options.size===0 ? 0 : options.size||4; } default: break; } return pat } export default ol_style_StrokePattern