762 lines
29 KiB
JavaScript
762 lines
29 KiB
JavaScript
|
/* eslint-disable */
|
||
|
/********************************************************************************
|
||
|
MIT License
|
||
|
|
||
|
Copyright (c) 2018 Stijlbreuk
|
||
|
|
||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||
|
of this software and associated documentation files (the "Software"), to deal
|
||
|
in the Software without restriction, including without limitation the rights
|
||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||
|
copies of the Software, and to permit persons to whom the Software is
|
||
|
furnished to do so, subject to the following conditions:
|
||
|
|
||
|
The above copyright notice and this permission notice shall be included in all
|
||
|
copies or substantial portions of the Software.
|
||
|
|
||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||
|
SOFTWARE.
|
||
|
********************************************************************************/
|
||
|
function isIE () {
|
||
|
var userAgent = window.navigator.userAgent;
|
||
|
return /MSIE|Trident/.test(userAgent);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
|
||
|
var DEFAULT_WIDTH_HEIGHT = 300;
|
||
|
var DEFAULT_START_COLOR = '#000000';
|
||
|
|
||
|
var script = {
|
||
|
name: 'color-picker',
|
||
|
props: {
|
||
|
width: {
|
||
|
required: false,
|
||
|
type: Number,
|
||
|
default: DEFAULT_WIDTH_HEIGHT
|
||
|
},
|
||
|
height: {
|
||
|
required: false,
|
||
|
type: Number,
|
||
|
default: DEFAULT_WIDTH_HEIGHT
|
||
|
},
|
||
|
disabled: {
|
||
|
required: false,
|
||
|
type: Boolean,
|
||
|
default: false
|
||
|
},
|
||
|
startColor: {
|
||
|
required: false,
|
||
|
type: String,
|
||
|
},
|
||
|
value: {
|
||
|
required: false,
|
||
|
type: String
|
||
|
}
|
||
|
},
|
||
|
mounted: function mounted() {
|
||
|
/**
|
||
|
* @deprecated since: 0.4.0, remove in: 1.0.0, https://github.com/stijlbreuk/vue-color-picker-wheel/issues/6
|
||
|
*/
|
||
|
if (this.hasCamelCaseColorChangeListener) {
|
||
|
console.warn("Using the colorChange event is deprecated since version 0.4.0. It will be deleted in version 1.0.0. 'v-model' or the kebab-case variant 'color-change' should be used.");
|
||
|
}
|
||
|
this.initWidget();
|
||
|
this.setColor(this.value || this.startColor || DEFAULT_START_COLOR);
|
||
|
},
|
||
|
data: function data() {
|
||
|
return {
|
||
|
debug: false,
|
||
|
dragging: false,
|
||
|
circleDrag: false,
|
||
|
color: '',
|
||
|
rgb: '',
|
||
|
hsl: '',
|
||
|
radius: '',
|
||
|
square: '',
|
||
|
mid: '',
|
||
|
markerSize: '',
|
||
|
ctxMask: '',
|
||
|
ctxOverlay: '',
|
||
|
cnvMask: '',
|
||
|
cnvOverlay: '',
|
||
|
offset: {
|
||
|
left: '',
|
||
|
top: ''
|
||
|
}
|
||
|
};
|
||
|
},
|
||
|
watch: {
|
||
|
value: function value(newVal, oldVal) {
|
||
|
if (newVal !== oldVal) {
|
||
|
this.setColor(newVal);
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
computed: {
|
||
|
/**
|
||
|
* @deprecated since: 0.4.0, remove in: 1.0.0, https://github.com/stijlbreuk/vue-color-picker-wheel/issues/6
|
||
|
*/
|
||
|
hasCamelCaseColorChangeListener: function hasCamelCaseColorChangeListener() {
|
||
|
return this.$listeners && this.$listeners.colorChange;
|
||
|
},
|
||
|
solidStyle: function solidStyle() {
|
||
|
return {
|
||
|
'background-color': this.pack(this.HSLToRGB([this.hsl[0], 1, 0.5])),
|
||
|
width: ((this.square * 2 - 1) + "px"),
|
||
|
height: ((this.square * 2 - 1) + "px"),
|
||
|
left: ((this.mid - this.square) + "px"),
|
||
|
top: ((this.mid - this.square) + "px")
|
||
|
};
|
||
|
},
|
||
|
wheelWidth: function wheelWidth() {
|
||
|
return (this.width || 300) / 10;
|
||
|
}
|
||
|
},
|
||
|
methods: {
|
||
|
setColor: function setColor(color, noEmit) {
|
||
|
if ( noEmit === void 0 ) noEmit = false;
|
||
|
|
||
|
var unpack = this.unpack(color);
|
||
|
if (this.color !== color && unpack) {
|
||
|
this.color = color;
|
||
|
this.rgb = unpack;
|
||
|
this.hsl = this.RGBToHSL(this.rgb);
|
||
|
this.updateDisplay(noEmit);
|
||
|
}
|
||
|
return this;
|
||
|
},
|
||
|
setHSL: function setHSL(hsl) {
|
||
|
this.hsl = hsl;
|
||
|
this.rgb = this.HSLToRGB(hsl);
|
||
|
this.color = this.pack(this.rgb);
|
||
|
this.updateDisplay();
|
||
|
return this;
|
||
|
},
|
||
|
initWidget: function initWidget() {
|
||
|
// Determine layout
|
||
|
this.radius = (this.width - this.wheelWidth) / 2 - 1;
|
||
|
this.square = Math.floor((this.radius - this.wheelWidth / 2) * 0.7) - 1;
|
||
|
this.mid = Math.floor(this.width / 2);
|
||
|
this.markerSize = this.wheelWidth * 0.3;
|
||
|
|
||
|
// Set up drawing context.
|
||
|
this.cnvMask = this.$refs['farbtastic-mask'];
|
||
|
this.ctxMask = this.cnvMask.getContext('2d');
|
||
|
this.cnvOverlay = this.$refs['farbtastic-overlay'];
|
||
|
this.ctxOverlay = this.cnvOverlay.getContext('2d');
|
||
|
this.devicePixelRatio = window.devicePixelRatio || 1;
|
||
|
this.upscaleCanvas(this.cnvMask);
|
||
|
this.upscaleCanvas(this.cnvOverlay);
|
||
|
this.ctxMask.translate(this.mid, this.mid);
|
||
|
this.ctxOverlay.translate(this.mid, this.mid);
|
||
|
|
||
|
// Draw widget base layers.
|
||
|
this.drawCircle();
|
||
|
this.drawMask();
|
||
|
},
|
||
|
upscaleCanvas: function upscaleCanvas(cnv) {
|
||
|
var ctx = cnv.getContext('2d');
|
||
|
var backingStoreRatio =
|
||
|
ctx.webkitBackingStorePixelRatio ||
|
||
|
ctx.mozBackingStorePixelRatio ||
|
||
|
ctx.msBackingStorePixelRatio ||
|
||
|
ctx.oBackingStorePixelRatio ||
|
||
|
ctx.backingStorePixelRatio ||
|
||
|
1;
|
||
|
if (this.devicePixelRatio !== backingStoreRatio) {
|
||
|
var ratio = this.devicePixelRatio / backingStoreRatio;
|
||
|
|
||
|
var oldWidth = cnv.width;
|
||
|
var oldHeight = cnv.height;
|
||
|
cnv.width = oldWidth * ratio;
|
||
|
cnv.height = oldHeight * ratio;
|
||
|
cnv.style.width = oldWidth + "px";
|
||
|
cnv.style.height = oldHeight + "px";
|
||
|
ctx.scale(ratio, ratio);
|
||
|
}
|
||
|
},
|
||
|
drawCircle: function drawCircle() {
|
||
|
var tm = +(new Date());
|
||
|
// Draw a hue circle with a bunch of gradient-stroked beziers.
|
||
|
// Have to use beziers, as gradient-stroked arcs don't work.
|
||
|
var n = 24;
|
||
|
var r = this.radius;
|
||
|
var w = this.wheelWidth;
|
||
|
var nudge = (8 / r / n) * Math.PI; // Fudge factor for seams.
|
||
|
var m = this.ctxMask;
|
||
|
var angle1 = 0;
|
||
|
var angle2;
|
||
|
// let d1;
|
||
|
var color1;
|
||
|
var color2;
|
||
|
m.save();
|
||
|
m.lineWidth = w / r;
|
||
|
m.scale(r, r);
|
||
|
// Each segment goes from angle1 to angle2.
|
||
|
// eslint-disable-next-line
|
||
|
for (var i = 0; i <= n; ++i) {
|
||
|
var d2 = i / n;
|
||
|
angle2 = d2 * Math.PI * 2;
|
||
|
// Endpoints
|
||
|
var x1 = Math.sin(angle1);
|
||
|
var y1 = -Math.cos(angle1);
|
||
|
var x2 = Math.sin(angle2);
|
||
|
var y2 = -Math.cos(angle2);
|
||
|
// Midpoint chosen so that the endpoints are tangent to the circle.
|
||
|
var am = (angle1 + angle2) / 2;
|
||
|
var tan = 1 / Math.cos((angle2 - angle1) / 2);
|
||
|
var xm = Math.sin(am) * tan;
|
||
|
var ym = -Math.cos(am) * tan;
|
||
|
// New color
|
||
|
color2 = this.pack(this.HSLToRGB([d2, 1, 0.5]));
|
||
|
if (i > 0) {
|
||
|
// Create gradient fill between the endpoints.
|
||
|
var grad = m.createLinearGradient(x1, y1, x2, y2);
|
||
|
grad.addColorStop(0, color1);
|
||
|
grad.addColorStop(1, color2);
|
||
|
m.strokeStyle = grad;
|
||
|
// Draw quadratic curve segment.
|
||
|
m.beginPath();
|
||
|
m.moveTo(x1, y1);
|
||
|
m.quadraticCurveTo(xm, ym, x2, y2);
|
||
|
m.stroke();
|
||
|
}
|
||
|
// Prevent seams where curves join.
|
||
|
angle1 = angle2 - nudge;
|
||
|
color1 = color2;
|
||
|
// d1 = d2;
|
||
|
}
|
||
|
m.restore();
|
||
|
if (this.debug) {
|
||
|
var debugElement = document.createElement('div');
|
||
|
debugElement.textContent = "drawCircle " + ((+(new Date()) - tm)) + " ms";
|
||
|
document.body.appendChild(debugElement);
|
||
|
}
|
||
|
},
|
||
|
drawMask: function drawMask() {
|
||
|
var this$1 = this;
|
||
|
|
||
|
var tm = +(new Date());
|
||
|
|
||
|
// Iterate over sat/lum space and calculate appropriate mask pixel values.
|
||
|
var size = this.square * 2;
|
||
|
var sq = this.square;
|
||
|
function calculateMask(sizex, sizey, outputPixel) {
|
||
|
var isx = 1 / sizex;
|
||
|
var isy = 1 / sizey;
|
||
|
// eslint-disable-next-line
|
||
|
for (var y = 0; y <= sizey; ++y) {
|
||
|
var l = 1 - y * isy;
|
||
|
// eslint-disable-next-line
|
||
|
for (var x = 0; x <= sizex; ++x) {
|
||
|
var s = 1 - x * isx;
|
||
|
// From sat/lum to alpha and color (grayscale)
|
||
|
var a = 1 - 2 * Math.min(l * s, (1 - l) * s);
|
||
|
var c = a > 0 ? (2 * l - 1 + a) * (0.5 / a) : 0;
|
||
|
outputPixel(x, y, c, a);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Method #1: direct pixel access (new Canvas).
|
||
|
if (this.ctxMask.getImageData) {
|
||
|
// Create half-resolution buffer.
|
||
|
var sz = Math.floor(size / 2);
|
||
|
var buffer = document.createElement('canvas');
|
||
|
buffer.width = sz + 1;
|
||
|
buffer.height = sz + 1;
|
||
|
var ctx = buffer.getContext('2d');
|
||
|
var frame = ctx.getImageData(0, 0, sz + 1, sz + 1);
|
||
|
|
||
|
var i = 0;
|
||
|
calculateMask(sz, sz, function (x, y, c, a) {
|
||
|
// eslint-disable-next-line
|
||
|
frame.data[i++] = frame.data[i++] = frame.data[i++] = c * 255;
|
||
|
// eslint-disable-next-line
|
||
|
frame.data[i++] = a * 255;
|
||
|
});
|
||
|
|
||
|
ctx.putImageData(frame, 0, 0);
|
||
|
this.ctxMask.drawImage(
|
||
|
buffer,
|
||
|
0,
|
||
|
0,
|
||
|
sz + 1,
|
||
|
sz + 1,
|
||
|
-sq,
|
||
|
-sq,
|
||
|
sq * 2,
|
||
|
sq * 2
|
||
|
);
|
||
|
} else if (!isIE()) {
|
||
|
// Render directly at half-resolution
|
||
|
var sz$1 = Math.floor(size / 2);
|
||
|
calculateMask(sz$1, sz$1, function (x, y, _c, a) {
|
||
|
var c = Math.round(_c * 255);
|
||
|
this$1.ctxMask.fillStyle = "rgba(" + c + ", " + c + ", " + c + ", " + a + ")";
|
||
|
this$1.ctxMask.fillRect(x * 2 - sq - 1, y * 2 - sq - 1, 2, 2);
|
||
|
});
|
||
|
} else {
|
||
|
var cacheLast;
|
||
|
var cache;
|
||
|
var w = 6; // Each strip is 6 pixels wide.
|
||
|
var sizex = Math.floor(size / w);
|
||
|
// 6 vertical pieces of gradient per strip.
|
||
|
calculateMask(sizex, 6, function (x, y, c, a) {
|
||
|
if (x === 0) {
|
||
|
cacheLast = cache;
|
||
|
cache = [];
|
||
|
}
|
||
|
c = Math.round(c * 255);
|
||
|
a = Math.round(a * 255);
|
||
|
// We can only start outputting gradients
|
||
|
// once we have two rows of pixels.
|
||
|
if (y > 0) {
|
||
|
var cLast = cacheLast[x][0];
|
||
|
var aLast = cacheLast[x][1];
|
||
|
var color1 = this$1.packDX(cLast, aLast);
|
||
|
var color2 = this$1.packDX(c, a);
|
||
|
var y1 = Math.round(this$1.mid + ((y - 1) * 0.333 - 1) * sq);
|
||
|
var y2 = Math.round(this$1.mid + (y * 0.333 - 1) * sq);
|
||
|
// Append div to canvasMask
|
||
|
var div = document.createElement('div');
|
||
|
div.style.position = 'absolute';
|
||
|
div.style.filter = "progid:DXImageTransform.Microsoft.Gradient(StartColorStr=" + color1 + ", EndColorStr=" + color2 + ", GradientType=0)";
|
||
|
div.style.top = y1;
|
||
|
div.style.height = y2 - y1;
|
||
|
div.style.left = this$1.mid + (x * w - sq - 1);
|
||
|
div.style.width = this$1.mid + (x * w - sq - 1);
|
||
|
this$1.cnvMask.appendChild(div);
|
||
|
}
|
||
|
cache.push([c, a]);
|
||
|
});
|
||
|
}
|
||
|
if (this.debug) {
|
||
|
var debugElement = document.createElement('div');
|
||
|
debugElement.textContent = "drawMask " + ((+(new Date()) - tm)) + " ms";
|
||
|
document.body.appendChild(debugElement);
|
||
|
}
|
||
|
},
|
||
|
drawMarkers: function drawMarkers() {
|
||
|
// Determine marker dimensions
|
||
|
var sz = this.width;
|
||
|
var lw = Math.ceil(this.markerSize / 4);
|
||
|
var r = this.markerSize - lw + 1;
|
||
|
var angle = this.hsl[0] * 6.28;
|
||
|
var x1 = Math.sin(angle) * this.radius;
|
||
|
var y1 = -Math.cos(angle) * this.radius;
|
||
|
var x2 = 2 * this.square * (0.5 - this.hsl[1]);
|
||
|
var y2 = 2 * this.square * (0.5 - this.hsl[2]);
|
||
|
var c1 = this.invert ? '#fff' : '#000';
|
||
|
var c2 = this.invert ? '#000' : '#fff';
|
||
|
var circles = [
|
||
|
{ x: x1, y: y1, r: r, c: '#000', lw: lw + 1 },
|
||
|
{ x: x1, y: y1, r: this.markerSize, c: '#fff', lw: lw },
|
||
|
{ x: x2, y: y2, r: r, c: c2, lw: lw + 1 },
|
||
|
{ x: x2, y: y2, r: this.markerSize, c: c1, lw: lw }
|
||
|
];
|
||
|
|
||
|
// Update the overlay canvas.
|
||
|
this.ctxOverlay.clearRect(-this.mid, -this.mid, sz, sz);
|
||
|
for (var i = 0; i < circles.length; i += 1) {
|
||
|
var c = circles[i];
|
||
|
this.ctxOverlay.lineWidth = c.lw;
|
||
|
this.ctxOverlay.strokeStyle = c.c;
|
||
|
this.ctxOverlay.beginPath();
|
||
|
this.ctxOverlay.arc(c.x, c.y, c.r, 0, Math.PI * 2, true);
|
||
|
this.ctxOverlay.stroke();
|
||
|
}
|
||
|
},
|
||
|
updateDisplay: function updateDisplay(noEmit) {
|
||
|
// Determine whether labels/markers should invert.
|
||
|
this.invert =
|
||
|
this.rgb[0] * 0.3 + this.rgb[1] * 0.59 + this.rgb[2] * 0.11 <= 0.6;
|
||
|
|
||
|
// Draw markers
|
||
|
this.drawMarkers();
|
||
|
|
||
|
if (!noEmit) {
|
||
|
// Emit color
|
||
|
this.$emit('input', this.color);
|
||
|
/**
|
||
|
* @deprecated since: 0.4.0, remove in: 1.0.0, https://github.com/stijlbreuk/vue-color-picker-wheel/issues/6
|
||
|
*/
|
||
|
this.$emit('colorChange', this.color);
|
||
|
this.$emit('color-change', this.color);
|
||
|
}
|
||
|
},
|
||
|
widgetCoords: function widgetCoords(event) {
|
||
|
return {
|
||
|
x: event.clientX - this.offset.left - this.mid,
|
||
|
y: event.clientY - this.offset.top - this.mid
|
||
|
};
|
||
|
},
|
||
|
mousedown: function mousedown(event) {
|
||
|
if (this.disabled) { return false; }
|
||
|
// Capture mouse
|
||
|
if (!this.dragging) {
|
||
|
document.addEventListener('mousemove', this.mousemove);
|
||
|
document.addEventListener('mouseup', this.mouseup);
|
||
|
this.dragging = true;
|
||
|
}
|
||
|
|
||
|
// Update the stored offset for the widget.
|
||
|
this.offset = {
|
||
|
left: this.$refs['color-wheel'].getBoundingClientRect().left,
|
||
|
top: this.$refs['color-wheel'].getBoundingClientRect().top
|
||
|
};
|
||
|
|
||
|
// Check which area is being dragged
|
||
|
var pos = this.widgetCoords(event);
|
||
|
this.circleDrag =
|
||
|
Math.max(Math.abs(pos.x), Math.abs(pos.y)) > this.square + 2;
|
||
|
|
||
|
// Process
|
||
|
this.mousemove(event);
|
||
|
return false;
|
||
|
},
|
||
|
mousemove: function mousemove(event) {
|
||
|
// Get coordinates relative to color picker center
|
||
|
var pos = this.widgetCoords(event);
|
||
|
|
||
|
// Set new HSL parameters
|
||
|
if (this.circleDrag) {
|
||
|
var hue = Math.atan2(pos.x, -pos.y) / 6.28;
|
||
|
this.setHSL([(hue + 1) % 1, this.hsl[1], this.hsl[2]]);
|
||
|
} else {
|
||
|
var sat = Math.max(0, Math.min(1, -(pos.x / this.square / 2) + 0.5));
|
||
|
var lum = Math.max(0, Math.min(1, -(pos.y / this.square / 2) + 0.5));
|
||
|
this.setHSL([this.hsl[0], sat, lum]);
|
||
|
}
|
||
|
return false;
|
||
|
},
|
||
|
mouseup: function mouseup() {
|
||
|
// Uncapture mouse
|
||
|
document.removeEventListener('mousemove', this.mousemove);
|
||
|
document.removeEventListener('mouseup', this.mouseup);
|
||
|
this.dragging = false;
|
||
|
},
|
||
|
/* Constious color utility functions */
|
||
|
dec2hex: function dec2hex(x) {
|
||
|
return (x < 16 ? '0' : '') + x.toString(16);
|
||
|
},
|
||
|
packDX: function packDX(c, a) {
|
||
|
return ("#" + (this.dec2hex(a) +
|
||
|
this.dec2hex(c) +
|
||
|
this.dec2hex(c) +
|
||
|
this.dec2hex(c)));
|
||
|
},
|
||
|
pack: function pack(rgb) {
|
||
|
var r = Math.round(rgb[0] * 255);
|
||
|
var g = Math.round(rgb[1] * 255);
|
||
|
var b = Math.round(rgb[2] * 255);
|
||
|
return ("#" + (this.dec2hex(r) + this.dec2hex(g) + this.dec2hex(b)));
|
||
|
},
|
||
|
unpack: function unpack(color) {
|
||
|
if (color.length === 7) {
|
||
|
return [1, 3, 5].map(
|
||
|
function (i) { return parseInt(color.substring(i, i + 2), 16) / 255; }
|
||
|
);
|
||
|
} else if (color.length === 4) {
|
||
|
return [1, 2, 3].map(function (i) { return parseInt(color.substring(i, i + 1), 16) / 15; });
|
||
|
}
|
||
|
return false;
|
||
|
},
|
||
|
HSLToRGB: function HSLToRGB(hsl) {
|
||
|
var h = hsl[0];
|
||
|
var s = hsl[1];
|
||
|
var l = hsl[2];
|
||
|
var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;
|
||
|
var m1 = l * 2 - m2;
|
||
|
return [
|
||
|
this.hueToRGB(m1, m2, h + 0.33333),
|
||
|
this.hueToRGB(m1, m2, h),
|
||
|
this.hueToRGB(m1, m2, h - 0.33333)
|
||
|
];
|
||
|
},
|
||
|
hueToRGB: function hueToRGB(m1, m2, h) {
|
||
|
h = (h + 1) % 1;
|
||
|
if (h * 6 < 1) { return m1 + (m2 - m1) * h * 6; }
|
||
|
if (h * 2 < 1) { return m2; }
|
||
|
if (h * 3 < 2) { return m1 + (m2 - m1) * (0.66666 - h) * 6; }
|
||
|
return m1;
|
||
|
},
|
||
|
RGBToHSL: function RGBToHSL(rgb) {
|
||
|
var r = rgb[0];
|
||
|
var g = rgb[1];
|
||
|
var b = rgb[2];
|
||
|
var min = Math.min(r, g, b);
|
||
|
var max = Math.max(r, g, b);
|
||
|
var delta = max - min;
|
||
|
var h = 0;
|
||
|
var s = 0;
|
||
|
var l = (min + max) / 2;
|
||
|
if (l > 0 && l < 1) {
|
||
|
s = delta / (l < 0.5 ? 2 * l : 2 - 2 * l);
|
||
|
}
|
||
|
if (delta > 0) {
|
||
|
if (max === r && max !== g) { h += (g - b) / delta; }
|
||
|
if (max === g && max !== b) { h += 2 + (b - r) / delta; }
|
||
|
if (max === b && max !== r) { h += 4 + (r - g) / delta; }
|
||
|
h /= 6;
|
||
|
}
|
||
|
return [h, s, l];
|
||
|
},
|
||
|
/**
|
||
|
* Helper for returning coordinates relative to the center with touch event
|
||
|
*/
|
||
|
widgetCoordsTouch: function widgetCoordsTouch(event) {
|
||
|
return {
|
||
|
x: event.targetTouches[0].clientX - this.offset.left - this.mid,
|
||
|
y: event.targetTouches[0].clientY - this.offset.top - this.mid
|
||
|
};
|
||
|
},
|
||
|
/**
|
||
|
* Handle the touchstart events
|
||
|
*/
|
||
|
touchHandleStart: function touchHandleStart(event) {
|
||
|
// Ignore the event if another is already being handled
|
||
|
if (this.touchHandled) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Set the flag to prevent others from inheriting the touch event
|
||
|
this.touchHandled = true;
|
||
|
|
||
|
// Track movement to determine if interaction was a click
|
||
|
this._touchMoved = false;
|
||
|
|
||
|
// Update the stored offset for the widget.
|
||
|
this.offset = {
|
||
|
left: this.$refs['color-wheel'].getBoundingClientRect().left,
|
||
|
top: this.$refs['color-wheel'].getBoundingClientRect().top
|
||
|
};
|
||
|
|
||
|
// Check which area is being dragged
|
||
|
var pos = this.widgetCoordsTouch(event);
|
||
|
this.circleDrag =
|
||
|
Math.max(Math.abs(pos.x), Math.abs(pos.y)) > this.square + 2;
|
||
|
},
|
||
|
/**
|
||
|
* Handle the touchstart events
|
||
|
*/
|
||
|
touchHandleMove: function touchHandleMove(event) {
|
||
|
// Ignore event if not handled
|
||
|
if (!this.touchHandled) {
|
||
|
return;
|
||
|
}
|
||
|
event.preventDefault();
|
||
|
|
||
|
// Interaction was not a click
|
||
|
this._touchMoved = true;
|
||
|
|
||
|
// Get coordinates relative to color picker center
|
||
|
var pos = this.widgetCoordsTouch(event);
|
||
|
|
||
|
// Set new HSL parameters
|
||
|
if (this.circleDrag) {
|
||
|
var hue = Math.atan2(pos.x, -pos.y) / 6.28;
|
||
|
this.setHSL([(hue + 1) % 1, this.hsl[1], this.hsl[2]]);
|
||
|
} else {
|
||
|
var sat = Math.max(0, Math.min(1, -(pos.x / this.square / 2) + 0.5));
|
||
|
var lum = Math.max(0, Math.min(1, -(pos.y / this.square / 2) + 0.5));
|
||
|
this.setHSL([this.hsl[0], sat, lum]);
|
||
|
}
|
||
|
},
|
||
|
/**
|
||
|
* Handle the touchstart events
|
||
|
*/
|
||
|
touchHandleEnd: function touchHandleEnd() {
|
||
|
// Ignore event if not handled
|
||
|
if (!this.touchHandled) {
|
||
|
return;
|
||
|
}
|
||
|
// Unset the flag to allow other widgets to inherit the touch event
|
||
|
this.touchHandled = false;
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/* script */
|
||
|
var __vue_script__ = script;
|
||
|
|
||
|
/* template */
|
||
|
var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{ref:"color-wheel",staticClass:"cpw_container",class:{s_disabled: _vm.disabled},style:({width: (_vm.width + "px"), height: (_vm.height + "px"), position: 'relative'}),attrs:{"id":"color-wheel"}},[_c('div',{ref:"farbtastic-solid",staticClass:"farbtastic-solid",staticStyle:{"position":"absolute"},style:(_vm.solidStyle)}),_vm._v(" "),_c('canvas',{ref:"farbtastic-mask",staticClass:"farbtastic-mask",style:({width: _vm.width, height: _vm.height}),attrs:{"width":_vm.width,"height":_vm.height}}),_vm._v(" "),_c('canvas',{ref:"farbtastic-overlay",staticClass:"farbtastic-overlay",style:({width: _vm.width, height: _vm.height}),attrs:{"width":_vm.width,"height":_vm.height},on:{"mousedown":_vm.mousedown,"touchstart":_vm.touchHandleStart,"touchmove":_vm.touchHandleMove,"touchend":_vm.touchHandleEnd}})])};
|
||
|
var __vue_staticRenderFns__ = [];
|
||
|
|
||
|
/* style */
|
||
|
var __vue_inject_styles__ = function (inject) {
|
||
|
if (!inject) { return }
|
||
|
inject("data-v-58e7c5c8_0", { source: "\n.s_disabled[data-v-58e7c5c8]{opacity:.5\n}\n.cpw_container[data-v-58e7c5c8]{-webkit-touch-callout:none;-webkit-text-size-adjust:none;-moz-text-size-adjust:none;-ms-text-size-adjust:none;text-size-adjust:none;tap-highlight-color:transparent;tap-highlight-color:transparent;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none\n}\n.cpw_container .farbtastic-mask[data-v-58e7c5c8]{position:absolute;left:0\n}\n.cpw_container .farbtastic-overlay[data-v-58e7c5c8]{position:absolute;left:0\n}", map: undefined, media: undefined });
|
||
|
|
||
|
};
|
||
|
/* scoped */
|
||
|
var __vue_scope_id__ = "data-v-58e7c5c8";
|
||
|
/* module identifier */
|
||
|
var __vue_module_identifier__ = undefined;
|
||
|
/* functional template */
|
||
|
var __vue_is_functional_template__ = false;
|
||
|
/* component normalizer */
|
||
|
function __vue_normalize__(
|
||
|
template, style, script$$1,
|
||
|
scope, functional, moduleIdentifier,
|
||
|
createInjector, createInjectorSSR
|
||
|
) {
|
||
|
var component = (typeof script$$1 === 'function' ? script$$1.options : script$$1) || {};
|
||
|
|
||
|
// For security concerns, we use only base name in production mode.
|
||
|
component.__file = "color-picker.vue";
|
||
|
|
||
|
if (!component.render) {
|
||
|
component.render = template.render;
|
||
|
component.staticRenderFns = template.staticRenderFns;
|
||
|
component._compiled = true;
|
||
|
|
||
|
if (functional) { component.functional = true; }
|
||
|
}
|
||
|
|
||
|
component._scopeId = scope;
|
||
|
|
||
|
{
|
||
|
var hook;
|
||
|
if (style) {
|
||
|
hook = function(context) {
|
||
|
style.call(this, createInjector(context));
|
||
|
};
|
||
|
}
|
||
|
|
||
|
if (hook !== undefined) {
|
||
|
if (component.functional) {
|
||
|
// register for functional component in vue file
|
||
|
var originalRender = component.render;
|
||
|
component.render = function renderWithStyleInjection(h, context) {
|
||
|
hook.call(context);
|
||
|
return originalRender(h, context)
|
||
|
};
|
||
|
} else {
|
||
|
// inject component registration as beforeCreate hook
|
||
|
var existing = component.beforeCreate;
|
||
|
component.beforeCreate = existing ? [].concat(existing, hook) : [hook];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return component
|
||
|
}
|
||
|
/* style inject */
|
||
|
function __vue_create_injector__() {
|
||
|
var head = document.head || document.getElementsByTagName('head')[0];
|
||
|
var styles = __vue_create_injector__.styles || (__vue_create_injector__.styles = {});
|
||
|
var isOldIE =
|
||
|
typeof navigator !== 'undefined' &&
|
||
|
/msie [6-9]\\b/.test(navigator.userAgent.toLowerCase());
|
||
|
|
||
|
return function addStyle(id, css) {
|
||
|
if (document.querySelector('style[data-vue-ssr-id~="' + id + '"]')) { return } // SSR styles are present.
|
||
|
|
||
|
var group = isOldIE ? css.media || 'default' : id;
|
||
|
var style = styles[group] || (styles[group] = { ids: [], parts: [], element: undefined });
|
||
|
|
||
|
if (!style.ids.includes(id)) {
|
||
|
var code = css.source;
|
||
|
var index = style.ids.length;
|
||
|
|
||
|
style.ids.push(id);
|
||
|
|
||
|
if (css.map) {
|
||
|
// https://developer.chrome.com/devtools/docs/javascript-debugging
|
||
|
// this makes source maps inside style tags work properly in Chrome
|
||
|
code += '\n/*# sourceURL=' + css.map.sources[0] + ' */';
|
||
|
// http://stackoverflow.com/a/26603875
|
||
|
code +=
|
||
|
'\n/*# sourceMappingURL=data:application/json;base64,' +
|
||
|
btoa(unescape(encodeURIComponent(JSON.stringify(css.map)))) +
|
||
|
' */';
|
||
|
}
|
||
|
|
||
|
if (isOldIE) {
|
||
|
style.element = style.element || document.querySelector('style[data-group=' + group + ']');
|
||
|
}
|
||
|
|
||
|
if (!style.element) {
|
||
|
var el = style.element = document.createElement('style');
|
||
|
el.type = 'text/css';
|
||
|
|
||
|
if (css.media) { el.setAttribute('media', css.media); }
|
||
|
if (isOldIE) {
|
||
|
el.setAttribute('data-group', group);
|
||
|
el.setAttribute('data-next-index', '0');
|
||
|
}
|
||
|
|
||
|
head.appendChild(el);
|
||
|
}
|
||
|
|
||
|
if (isOldIE) {
|
||
|
index = parseInt(style.element.getAttribute('data-next-index'));
|
||
|
style.element.setAttribute('data-next-index', index + 1);
|
||
|
}
|
||
|
|
||
|
if (style.element.styleSheet) {
|
||
|
style.parts.push(code);
|
||
|
style.element.styleSheet.cssText = style.parts
|
||
|
.filter(Boolean)
|
||
|
.join('\n');
|
||
|
} else {
|
||
|
var textNode = document.createTextNode(code);
|
||
|
var nodes = style.element.childNodes;
|
||
|
if (nodes[index]) { style.element.removeChild(nodes[index]); }
|
||
|
if (nodes.length) { style.element.insertBefore(textNode, nodes[index]); }
|
||
|
else { style.element.appendChild(textNode); }
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
/* style inject SSR */
|
||
|
|
||
|
|
||
|
|
||
|
var component = __vue_normalize__(
|
||
|
{ render: __vue_render__, staticRenderFns: __vue_staticRenderFns__ },
|
||
|
__vue_inject_styles__,
|
||
|
__vue_script__,
|
||
|
__vue_scope_id__,
|
||
|
__vue_is_functional_template__,
|
||
|
__vue_module_identifier__,
|
||
|
__vue_create_injector__,
|
||
|
undefined
|
||
|
);
|
||
|
|
||
|
// Import vue component
|
||
|
|
||
|
// Declare install function executed by Vue.use()
|
||
|
function install(Vue) {
|
||
|
if (install.installed) { return; }
|
||
|
install.installed = true;
|
||
|
Vue.component('ColorPicker', component);
|
||
|
}
|
||
|
|
||
|
// Create module definition for Vue.use()
|
||
|
var plugin = {
|
||
|
install: install,
|
||
|
};
|
||
|
|
||
|
// Auto-install when vue is found (eg. in browser via <script> tag)
|
||
|
var GlobalVue = null;
|
||
|
if (typeof window !== 'undefined') {
|
||
|
GlobalVue = window.Vue;
|
||
|
} else if (typeof global !== 'undefined') {
|
||
|
GlobalVue = global.Vue;
|
||
|
}
|
||
|
if (GlobalVue) {
|
||
|
GlobalVue.use(plugin);
|
||
|
}
|
||
|
|
||
|
export default component;
|
||
|
export { install };
|