UNPKG

ol-ext

Version:

A set of cool extensions for OpenLayers (ol) in node modules structure

512 lines (485 loc) 16.7 kB
import ol_ext_element from '../element.js'; import ol_ext_input_PopupBase from './PopupBase.js' import ol_Collection from 'ol/Collection.js'; import { toHSV as ol_color_toHSV, fromHSV as ol_color_fromHSV } from '../color.js' import { toHexa as ol_color_toHexa } from '../color.js' import { asArray as ol_color_asArray } from 'ol/color.js' /** Color picker * @constructor * @extends {ol_ext_input_PopupBase} * @fires color * @param {*} options * @param {string} [options.className] * @param {ol.colorLike} [options.color] default color * @param {Element} [options.input] input element, if non create one * @param {Element} [options.parent] parent element, if create an input * @param {boolean} [options.hastab=false] use tabs for palette / picker * @param {string} [options.paletteLabel="palette"] label for the palette tab * @param {string} [options.pickerLabel="picker"] label for the picker tab * @param {string} [options.position='popup'] fixed | static | popup | inline (no popup) * @param {boolean} [options.opacity=true] enable opacity * @param {boolean} [options.autoClose=true] close when click on color * @param {boolean} [options.hidden=true] display the input */ var ol_ext_input_Color = class olextinputColor extends ol_ext_input_PopupBase { constructor(options) { options = options || {}; options.hidden = options.hidden !== false; options.className = ('ol-ext-colorpicker ' + (options.hastab ? 'ol-tab ' : '') + (options.className || '')).trim(); super(options); this.input.disabled = true; if (options.opacity === false) { this.element.classList.add('ol-nopacity'); } this.element.addEventListener('keydown', function(e) { if (e.target === this.element) { if (this._handleColorByKey(e.key)) { this.element.classList.remove('ol-picker-tab'); e.preventDefault() e.stopPropagation() } } }.bind(this)) this._cursor = {}; var hsv = this._hsv = {}; // Vignet this._elt.vignet = ol_ext_element.create('DIV', { className: 'ol-vignet', parent: this.element }); // Bar var bar = ol_ext_element.create('DIV', { className: 'ol-tabbar', parent: this._elt.popup }); ol_ext_element.create('DIV', { className: 'ol-tab', html: options.paletteLabel || 'palette', tabindex: 0, on: { keydown: function(e) { this._handlePickerKey(e, 'palette') }.bind(this), focus: function() { this.element.classList.remove('ol-picker-tab'); }.bind(this) }, parent: bar }); ol_ext_element.create('DIV', { className: 'ol-tab', html: options.pickerLabel || 'picker', tabindex: 0, on: { keydown: function(e) { this._handlePickerKey(e, 'picker') }.bind(this), focus: function() { this.element.classList.add('ol-picker-tab'); }.bind(this) }, parent: bar }); // Popup container var container = ol_ext_element.create('DIV', { className: 'ol-container', parent: this._elt.popup }); // Color picker var picker = this._elt.picker = ol_ext_element.create('DIV', { className: 'ol-picker', parent: container }); var pickerCursor = this._cursor.picker = ol_ext_element.create('DIV', { className: 'ol-cursor', parent: picker }); this._listenDrag(picker, function (e) { var tx = Math.max(0, Math.min(e.offsetX / picker.clientWidth, 1)); var ty = Math.max(0, Math.min(e.offsetY / picker.clientHeight, 1)); pickerCursor.style.left = Math.round(tx * 100) + '%'; pickerCursor.style.top = Math.round(ty * 100) + '%'; hsv.s = tx * 100; hsv.v = 100 - ty * 100; this.setColor(); }.bind(this)); // Opacity cursor var slider = ol_ext_element.create('DIV', { className: 'ol-slider', parent: container }); this._elt.slider = ol_ext_element.create('DIV', { parent: slider }); var sliderCursor = this._cursor.slide = ol_ext_element.create('DIV', { className: 'ol-cursor', parent: slider }); this._listenDrag(slider, function (e) { var t = Math.max(0, Math.min(e.offsetX / slider.clientWidth, 1)); hsv.a = t * 100; sliderCursor.style.left = Math.round(t * 100) + '%'; this.setColor(); }.bind(this)); // Tint cursor var tint = ol_ext_element.create('DIV', { className: 'ol-tint', parent: container }); var tintCursor = this._cursor.tint = ol_ext_element.create('DIV', { className: 'ol-cursor', parent: tint }); this._listenDrag(tint, function (e) { var t = Math.max(0, Math.min(e.offsetY / tint.clientHeight, 1)); hsv.h = t * 360; tintCursor.style.top = Math.round(t * 100) + '%'; this.setColor(); }.bind(this)); // Clear button ol_ext_element.create('DIV', { className: 'ol-clear', click: function () { this.setColor([0, 0, 0, 0]); }.bind(this), parent: container }); // RVB input var rgb = ol_ext_element.create('DIV', { className: 'ol-rgb', parent: container }); var changergb = function () { var r = Math.max(0, Math.min(255, parseInt(this._elt.r.value))); var g = Math.max(0, Math.min(255, parseInt(this._elt.g.value))); var b = Math.max(0, Math.min(255, parseInt(this._elt.b.value))); var a = Math.max(0, Math.min(1, parseFloat(this._elt.a.value))); this.setColor([r, g, b, a]); }.bind(this); this._elt.r = ol_ext_element.create('INPUT', { type: 'number', lang: 'en-GB', change: changergb, min: 0, max: 255, parent: rgb }); this._elt.g = ol_ext_element.create('INPUT', { type: 'number', lang: 'en-GB', change: changergb, min: 0, max: 255, parent: rgb }); this._elt.b = ol_ext_element.create('INPUT', { type: 'number', lang: 'en-GB', change: changergb, min: 0, max: 255, parent: rgb }); this._elt.a = ol_ext_element.create('INPUT', { type: 'number', lang: 'en-GB', change: changergb, min: 0, max: 1, step: .1, parent: rgb }); // Text color input this._elt.txtColor = ol_ext_element.create('INPUT', { type: 'text', className: 'ol-txt-color', change: function () { var color; this._elt.txtColor.classList.remove('ol-error'); try { color = ol_color_asArray(this._elt.txtColor.value); } catch (e) { this._elt.txtColor.classList.add('ol-error'); } if (color) this.setColor(color); }.bind(this), parent: container }); ol_ext_element.create('BUTTON', { html: 'OK', click: function () { this._addCustomColor(this.getColor()); this.collapse(true); }.bind(this), on: { keydown: function(e) { if (e.key === 'Tab') { this.collapse(true); } }.bind(this) }, parent: container }); var i; // Color palette this._paletteColor = {}; this._elt.palette = ol_ext_element.create('DIV', { className: 'ol-palette', parent: this._elt.popup }); for (i = 0; i < 8; i++) { var c = Math.round(255 - 255 * i / 7); this.addPaletteColor([c, c, c], c); //ol_color_toHexa([c,c,c])); } var colors = ['#f00', '#f90', '#ff0', '#0f0', '#0ff', '#48e', '#00f', '#f0f']; colors.forEach(function (c) { this.addPaletteColor(c, ol_color_toHexa(ol_color_asArray(c))); }.bind(this)); for (i = 0; i < 5; i++) { colors.forEach(function (c) { c = ol_color_toHSV(ol_color_asArray(c)); c = [c[0], i / 4 * 80 + 20, 100 - i / 4 * 60]; c = ol_color_fromHSV(c, 1); this.addPaletteColor(c, ol_color_toHexa(c)); }.bind(this)); } // Custom colors ol_ext_element.create('HR', { parent: this._elt.palette }); // Create custom color list if (!ol_ext_input_Color.customColorList) { ol_ext_input_Color.customColorList = new ol_Collection(); var ccolor = JSON.parse(localStorage.getItem('ol-ext@colorpicker') || '[]'); ccolor.forEach(function (c) { ol_ext_input_Color.customColorList.push(c); }); ol_ext_input_Color.customColorList.on(['add', 'remove'], function () { localStorage.setItem('ol-ext@colorpicker', JSON.stringify(ol_ext_input_Color.customColorList.getArray())); }); } // Handle custom color ol_ext_input_Color.customColorList.on('add', function (e) { this.addPaletteColor(this.getColorFromID(e.element)); }.bind(this)); ol_ext_input_Color.customColorList.on('remove', function (e) { if (this._paletteColor[e.element]) this._paletteColor[e.element].element.remove(); delete this._paletteColor[e.element]; }.bind(this)); // Add new one ol_ext_input_Color.customColorList.forEach(function (c) { this._addCustomColor(this.getColorFromID(c)); }.bind(this)); // Current color this.setColor(options.color || [0, 0, 0, 0]); this._currentColor = this.getColorID(this.getColor()); // Add new palette color this.on('color', function () { this._addCustomColor(this.getColor()); this._currentColor = this.getColorID(this.getColor()); this.setColor(); }.bind(this)); // Update color on hide this.on('collapse', function (e) { if (!e.visible) { var c = this.getColor(); if (this._currentColor !== this.getColorID(c)) { this.dispatchEvent({ type: 'color', color: c }); } } else { this._currentColor = this.getColorID(this.getColor()); } }.bind(this)); } /** * @private * @param {string} key */ _handleColorByKey(key) { // 0 = transparent if (key === '0' && !this.element.classList.contains('ol-nopacity')) { this.setColor([0, 0, 0, 0]) return true; } if (!/^Arrow/.test(key)) return false; // Arrow key var col = 0, colors = []; Object.keys(this._paletteColor).forEach(function(c) { var p = this._paletteColor[c] if (p.element.classList.contains('ol-select')) { col = colors.length; } if (!this.element.classList.contains('ol-nopacity') || !p.element.classList.contains('ol-alpha')) { colors.push(p) } }.bind(this)) switch (key) { case 'ArrowRight': { col += 1; break; } case 'ArrowLeft': { col -= 1; break; } case 'ArrowUp': { col -= 8; break; } case 'ArrowDown': { col += 8; break; } } if (colors[col]) { this._selectPalette(colors[col].color) this.setColor(colors[col].color) } return true; } /** * @private */ _handlePickerKey(e, what) { if (e.key === 'Tab') return; e.stopPropagation(); e.preventDefault(); switch (e.key) { case 'Enter': case ' ': case 'Space': { if (what === 'palette') { this.element.classList.remove('ol-picker-tab'); } else { this.element.classList.add('ol-picker-tab'); } break; } case 'ArrowRight': case 'ArrowLeft': case 'ArrowUp': case 'ArrowDown': { if (what === 'palette') { this._handleColorByKey(e.key) } break; } case 'Escape': { this.collapse(true); break; } } } /** Add color to palette * @param {ol.colorLike} color * @param {string} title * @param {boolean} select */ addPaletteColor(color, title, select) { // Get color id try { color = ol_color_asArray(color); } catch (e) { return; } var id = this.getColorID(color); // Add new one if (!this._paletteColor[id] && color[3]) { this._paletteColor[id] = { color: color, element: ol_ext_element.create('DIV', { title: title || '', className: (color[3] < 1 ? 'ol-alpha' : ''), style: { color: 'rgb(' + (color.join(',')) + ')' }, click: function () { this.setColor(color); if (this.get('autoClose')) this.collapse(true); }.bind(this), parent: this._elt.palette }) }; } if (select) { this._selectPalette(color); } } /** Show palette or picker tab * @param {string} what palette or picker */ showTab(what) { if (what === 'palette'){ this.element.classList.remove('ol-picker-tab'); } else{ this.element.classList.add('ol-picker-tab'); } } /** Show palette or picker tab * @returns {string} palette or picker */ getTab() { return this.element.classList.contains('ol-picker-tab') ? 'picker' : 'palette'; } /** Select a color in the palette * @private */ _selectPalette(color) { var id = this.getColorID(color); Object.keys(this._paletteColor).forEach(function (c) { this._paletteColor[c].element.classList.remove('ol-select'); }.bind(this)); if (this._paletteColor[id]) { this._paletteColor[id].element.classList.add('ol-select'); } } /** Set Color * @param { Array<number> } */ setColor(color) { var hsv = this._hsv; if (color) { color = ol_color_asArray(color); var hsv2 = ol_color_toHSV(color); hsv.h = hsv2[0]; hsv.s = hsv2[1]; hsv.v = hsv2[2]; if (hsv2.length > 3){ hsv.a = hsv2[3] * 100; } else{ hsv.a = 100; } this._cursor.picker.style.left = hsv.s + '%'; this._cursor.picker.style.top = (100 - hsv.v) + '%'; this._cursor.tint.style.top = (hsv.h / 360 * 100) + '%'; this._cursor.slide.style.left = hsv.a + '%'; if (this.isCollapsed()) { this.dispatchEvent({ type: 'color', color: color }); } } else { /* hsv.h = Math.round(hsv.h) % 360; hsv.s = Math.round(hsv.s); hsv.v = Math.round(hsv.v); */ hsv.a = Math.round(hsv.a); color = this.getColor(); } var val = 'rgba(' + color.join(', ') + ')'; // Show color this._elt.picker.style.color = 'hsl(' + hsv.h + ', 100%, 50%)'; this._elt.slider.style.backgroundImage = 'linear-gradient(45deg, transparent, rgba(' + this.getColor(false).join(',') + '))'; this._elt.vignet.style.color = val; // RGB this._elt.r.value = color[0]; this._elt.g.value = color[1]; this._elt.b.value = color[2]; this._elt.a.value = color[3]; // Txt color this._elt.txtColor.classList.remove('ol-error'); if (color[3] === 1) { this._elt.txtColor.value = ol_color_toHexa(color); } else { this._elt.txtColor.value = val; } this._selectPalette(color); // Set input value if (this.input.value !== val) { this.input.value = val; this.input.dispatchEvent(new Event('change')); } } /** Get current color * @param {boolean} [opacity=true] * @return {Array<number>} */ getColor(opacity) { return ol_color_fromHSV([this._hsv.h, this._hsv.s, this._hsv.v, (opacity !== false) ? this._hsv.a / 100 : 1], 1); } /** * @private */ _addCustomColor(color) { var id = this.getColorID(color); if (this._paletteColor[id]) return; if (!color[3]) return; if (ol_ext_input_Color.customColorList.getArray().indexOf(id) < 0) { ol_ext_input_Color.customColorList.push(id); if (ol_ext_input_Color.customColorList.getLength() > 24) { ol_ext_input_Color.customColorList.removeAt(0); } } this.addPaletteColor(color); } clearCustomColor() { ol_ext_input_Color.customColorList.clear(); } /** Convert color to id * @param {ol.colorLike} Color * @returns {number} */ getColorID(color) { color = ol_color_asArray(color); if (color[3] === undefined) color[3] = 1; return color.join('-'); } /** Convert color to id * @param {number} id * @returns {Array<number>} Color */ getColorFromID(id) { var c = id.split('-'); return ([parseFloat(c[0]), parseFloat(c[1]), parseFloat(c[2]), parseFloat(c[3])]); } } /** Custom color list * @private */ ol_ext_input_Color.customColorList = null; export default ol_ext_input_Color