update ColorPicker
This commit is contained in:
parent
dab3947668
commit
e7893a68ed
12 changed files with 994 additions and 26 deletions
77
src/components/color-picker/alpha.vue
Normal file
77
src/components/color-picker/alpha.vue
Normal file
|
@ -0,0 +1,77 @@
|
|||
<template>
|
||||
<div class="ivu-color-picker-alpha">
|
||||
<div class="ivu-color-picker-alpha-checkboard-wrap">
|
||||
<div class="ivu-color-picker-alpha-checkerboard"></div>
|
||||
</div>
|
||||
<div class="ivu-color-picker-alpha-gradient" :style="{background: gradientColor}"></div>
|
||||
<div class="ivu-color-picker-alpha-container" ref="container"
|
||||
@mousedown="handleMouseDown"
|
||||
@touchmove="handleChange"
|
||||
@touchstart="handleChange">
|
||||
<div class="ivu-color-picker-alpha-pointer" :style="{left: colors.a * 100 + '%'}">
|
||||
<div class="ivu-color-picker-alpha-picker"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'Alpha',
|
||||
props: {
|
||||
value: Object,
|
||||
onChange: Function
|
||||
},
|
||||
computed: {
|
||||
colors () {
|
||||
return this.value;
|
||||
},
|
||||
gradientColor () {
|
||||
const rgba = this.colors.rgba;
|
||||
const rgbStr = [rgba.r, rgba.g, rgba.b].join(',');
|
||||
return 'linear-gradient(to right, rgba(' + rgbStr + ', 0) 0%, rgba(' + rgbStr + ', 1) 100%)';
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleChange (e, skip) {
|
||||
!skip && e.preventDefault();
|
||||
const container = this.$refs.container;
|
||||
const containerWidth = container.clientWidth;
|
||||
|
||||
const xOffset = container.getBoundingClientRect().left + window.pageXOffset;
|
||||
const pageX = e.pageX || (e.touches ? e.touches[0].pageX : 0);
|
||||
const left = pageX - xOffset;
|
||||
|
||||
let a;
|
||||
if (left < 0) {
|
||||
a = 0;
|
||||
} else if (left > containerWidth) {
|
||||
a = 1;
|
||||
} else {
|
||||
a = Math.round(left * 100 / containerWidth) / 100;
|
||||
}
|
||||
|
||||
if (this.colors.a !== a) {
|
||||
this.$emit('change', {
|
||||
h: this.colors.hsl.h,
|
||||
s: this.colors.hsl.s,
|
||||
l: this.colors.hsl.l,
|
||||
a: a,
|
||||
source: 'rgba'
|
||||
});
|
||||
}
|
||||
},
|
||||
handleMouseDown (e) {
|
||||
this.handleChange(e, true);
|
||||
window.addEventListener('mousemove', this.handleChange);
|
||||
window.addEventListener('mouseup', this.handleMouseUp);
|
||||
},
|
||||
handleMouseUp () {
|
||||
this.unbindEventListeners();
|
||||
},
|
||||
unbindEventListeners () {
|
||||
window.removeEventListener('mousemove', this.handleChange);
|
||||
window.removeEventListener('mouseup', this.handleMouseUp);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
|
@ -8,12 +8,14 @@
|
|||
</div>
|
||||
<Dropdown-menu slot="list">
|
||||
<div :class="[prefixCls + '-picker']">
|
||||
<div :class="[prefixCls + '-picker-panel']"></div>
|
||||
<div :class="[prefixCls + '-picker-panel']">
|
||||
<Saturation v-model="saturationColors" @change="childChange"></Saturation>
|
||||
</div>
|
||||
<div :class="[prefixCls + '-picker-hue-slider']">
|
||||
<Slider v-model="hueNumber" :min="0" :max="255"></Slider>
|
||||
<Hue v-model="saturationColors" @change="childChange"></Hue>
|
||||
</div>
|
||||
<div v-if="alpha" :class="[prefixCls + '-picker-alpha-slider']">
|
||||
<Slider v-model="alphaNumber" :min="0" :max="100"></Slider>
|
||||
<Alpha v-model="saturationColors" @change="childChange"></Alpha>
|
||||
</div>
|
||||
<recommend-colors v-if="colors.length" :list="colors" :class="[prefixCls + '-picker-colors']"></recommend-colors>
|
||||
<recommend-colors v-if="!colors.length && recommend" :list="recommendedColor" :class="[prefixCls + '-picker-colors']"></recommend-colors>
|
||||
|
@ -23,22 +25,76 @@
|
|||
</Dropdown>
|
||||
</template>
|
||||
<script>
|
||||
import tinycolor from 'tinycolor2';
|
||||
|
||||
import Dropdown from '../dropdown/dropdown.vue';
|
||||
import DropdownMenu from '../dropdown/dropdown-menu.vue';
|
||||
import Slider from '../slider/slider.vue';
|
||||
import RecommendColors from './recommend-colors.vue';
|
||||
import Confirm from '../date-picker/base/confirm.vue';
|
||||
|
||||
import Saturation from './saturation.vue';
|
||||
import Hue from './hue.vue';
|
||||
import Alpha from './alpha.vue';
|
||||
|
||||
import { oneOf } from '../../utils/assist';
|
||||
|
||||
const prefixCls = 'ivu-color-picker';
|
||||
const inputPrefixCls = 'ivu-input';
|
||||
|
||||
function _colorChange (data, oldHue) {
|
||||
const alpha = data && data.a;
|
||||
let color;
|
||||
|
||||
// hsl is better than hex between conversions
|
||||
if (data && data.hsl) {
|
||||
color = tinycolor(data.hsl);
|
||||
} else if (data && data.hex && data.hex.length > 0) {
|
||||
color = tinycolor(data.hex);
|
||||
} else {
|
||||
color = tinycolor(data);
|
||||
}
|
||||
|
||||
if (color && (color._a === undefined || color._a === null)) {
|
||||
color.setAlpha(alpha || 1);
|
||||
}
|
||||
|
||||
const hsl = color.toHsl();
|
||||
const hsv = color.toHsv();
|
||||
|
||||
if (hsl.s === 0) {
|
||||
hsv.h = hsl.h = data.h || (data.hsl && data.hsl.h) || oldHue || 0;
|
||||
}
|
||||
|
||||
// when the hsv.v is less than 0.0164 (base on test)
|
||||
// because of possible loss of precision
|
||||
// the result of hue and saturation would be miscalculated
|
||||
if (hsv.v < 0.0164) {
|
||||
hsv.h = data.h || (data.hsv && data.hsv.h) || 0;
|
||||
hsv.s = data.s || (data.hsv && data.hsv.s) || 0;
|
||||
}
|
||||
|
||||
if (hsl.l < 0.01) {
|
||||
hsl.h = data.h || (data.hsl && data.hsl.h) || 0;
|
||||
hsl.s = data.s || (data.hsl && data.hsl.s) || 0;
|
||||
}
|
||||
|
||||
return {
|
||||
hsl: hsl,
|
||||
hex: color.toHexString().toUpperCase(),
|
||||
rgba: color.toRgb(),
|
||||
hsv: hsv,
|
||||
oldHue: data.h || oldHue || hsl.h,
|
||||
source: data.source,
|
||||
a: data.a || color.getAlpha()
|
||||
};
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'ColorPicker',
|
||||
components: { Dropdown, DropdownMenu, Slider, Confirm, RecommendColors },
|
||||
components: { Dropdown, DropdownMenu, Confirm, RecommendColors, Saturation, Hue, Alpha },
|
||||
props: {
|
||||
value: {
|
||||
type: String
|
||||
type: Object
|
||||
},
|
||||
alpha: {
|
||||
type: Boolean,
|
||||
|
@ -81,10 +137,8 @@
|
|||
},
|
||||
data () {
|
||||
return {
|
||||
val: _colorChange(this.value),
|
||||
prefixCls: prefixCls,
|
||||
currentValue: this.value,
|
||||
hueNumber: 0,
|
||||
alphaNumber: 0,
|
||||
recommendedColor: [
|
||||
'#2d8cf0',
|
||||
'#19be6b',
|
||||
|
@ -110,6 +164,15 @@
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
saturationColors: {
|
||||
get () {
|
||||
return this.val;
|
||||
},
|
||||
set (newVal) {
|
||||
this.val = newVal;
|
||||
this.$emit('input', newVal);
|
||||
}
|
||||
},
|
||||
wrapClasses () {
|
||||
return [
|
||||
`${prefixCls}-rel`,
|
||||
|
@ -129,8 +192,41 @@
|
|||
];
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value (newVal) {
|
||||
this.val = _colorChange(newVal);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
childChange (data) {
|
||||
this.colorChange(data);
|
||||
},
|
||||
colorChange (data, oldHue) {
|
||||
this.oldHue = this.saturationColors.hsl.h;
|
||||
this.saturationColors = _colorChange(data, oldHue || this.oldHue);
|
||||
},
|
||||
isValidHex (hex) {
|
||||
return tinycolor(hex).isValid();
|
||||
},
|
||||
simpleCheckForValidColor (data) {
|
||||
const keysToCheck = ['r', 'g', 'b', 'a', 'h', 's', 'l', 'v'];
|
||||
let checked = 0;
|
||||
let passed = 0;
|
||||
|
||||
for (let i = 0; i < keysToCheck.length; i++) {
|
||||
const letter = keysToCheck[i];
|
||||
if (data[letter]) {
|
||||
checked++;
|
||||
if (!isNaN(data[letter])) {
|
||||
passed++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (checked === passed) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
86
src/components/color-picker/hue.vue
Normal file
86
src/components/color-picker/hue.vue
Normal file
|
@ -0,0 +1,86 @@
|
|||
<template>
|
||||
<div class="ivu-color-picker-hue">
|
||||
<div class="ivu-color-picker-hue-container" ref="container"
|
||||
@mousedown="handleMouseDown"
|
||||
@touchmove="handleChange"
|
||||
@touchstart="handleChange">
|
||||
<div class="ivu-color-picker-hue-pointer" :style="{top: 0, left: pointerLeft}">
|
||||
<div class="ivu-color-picker-hue-picker"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'Hue',
|
||||
props: {
|
||||
value: Object
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
oldHue: 0,
|
||||
pullDirection: ''
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
colors () {
|
||||
const h = this.value.hsl.h;
|
||||
if (h !== 0 && h - this.oldHue > 0) this.pullDirection = 'right';
|
||||
if (h !== 0 && h - this.oldHue < 0) this.pullDirection = 'left';
|
||||
this.oldHue = h;
|
||||
|
||||
return this.value;
|
||||
},
|
||||
pointerLeft () {
|
||||
if (this.colors.hsl.h === 0 && this.pullDirection === 'right') return '100%';
|
||||
return (this.colors.hsl.h * 100) / 360 + '%';
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleChange (e, skip) {
|
||||
!skip && e.preventDefault();
|
||||
|
||||
const container = this.$refs.container;
|
||||
const containerWidth = container.clientWidth;
|
||||
|
||||
const xOffset = container.getBoundingClientRect().left + window.pageXOffset;
|
||||
const pageX = e.pageX || (e.touches ? e.touches[0].pageX : 0);
|
||||
const left = pageX - xOffset;
|
||||
|
||||
let h;
|
||||
let percent;
|
||||
|
||||
if (left < 0) {
|
||||
h = 0;
|
||||
} else if (left > containerWidth) {
|
||||
h = 360;
|
||||
} else {
|
||||
percent = left * 100 / containerWidth;
|
||||
h = (360 * percent / 100);
|
||||
}
|
||||
|
||||
if (this.colors.hsl.h !== h) {
|
||||
this.$emit('change', {
|
||||
h: h,
|
||||
s: this.colors.hsl.s,
|
||||
l: this.colors.hsl.l,
|
||||
a: this.colors.hsl.a,
|
||||
source: 'hsl'
|
||||
});
|
||||
}
|
||||
},
|
||||
handleMouseDown (e) {
|
||||
this.handleChange(e, true);
|
||||
window.addEventListener('mousemove', this.handleChange);
|
||||
window.addEventListener('mouseup', this.handleMouseUp);
|
||||
},
|
||||
handleMouseUp () {
|
||||
this.unbindEventListeners();
|
||||
},
|
||||
unbindEventListeners () {
|
||||
window.removeEventListener('mousemove', this.handleChange);
|
||||
window.removeEventListener('mouseup', this.handleMouseUp);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
98
src/components/color-picker/saturation.vue
Normal file
98
src/components/color-picker/saturation.vue
Normal file
|
@ -0,0 +1,98 @@
|
|||
<template>
|
||||
<div class="ivu-color-picker-saturation-wrapper">
|
||||
<div
|
||||
class="ivu-color-picker-saturation"
|
||||
:style="{background: bgColor}"
|
||||
ref="container"
|
||||
@mousedown="handleMouseDown">
|
||||
<div class="ivu-color-picker-saturation--white"></div>
|
||||
<div class="ivu-color-picker-saturation--black"></div>
|
||||
<div class="ivu-color-picker-saturation-pointer" :style="{top: pointerTop, left: pointerLeft}">
|
||||
<div class="ivu-color-picker-saturation-circle"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import throttle from '../../utils/throttle';
|
||||
|
||||
export default {
|
||||
name: 'Saturation',
|
||||
props: {
|
||||
value: Object
|
||||
},
|
||||
data () {
|
||||
return {};
|
||||
},
|
||||
computed: {
|
||||
colors () {
|
||||
return this.value;
|
||||
},
|
||||
bgColor () {
|
||||
return `hsl(${this.colors.hsv.h}, 100%, 50%)`;
|
||||
},
|
||||
pointerTop () {
|
||||
return (-(this.colors.hsv.v * 100) + 1) + 100 + '%';
|
||||
},
|
||||
pointerLeft () {
|
||||
return this.colors.hsv.s * 100 + '%';
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
throttle: throttle((fn, data) => {fn(data);}, 20,
|
||||
{
|
||||
'leading': true,
|
||||
'trailing': false
|
||||
}),
|
||||
handleChange (e, skip) {
|
||||
!skip && e.preventDefault();
|
||||
const container = this.$refs.container;
|
||||
const containerWidth = container.clientWidth;
|
||||
const containerHeight = container.clientHeight;
|
||||
const xOffset = container.getBoundingClientRect().left + window.pageXOffset;
|
||||
const yOffset = container.getBoundingClientRect().top + window.pageYOffset;
|
||||
const pageX = e.pageX || (e.touches ? e.touches[0].pageX : 0);
|
||||
const pageY = e.pageY || (e.touches ? e.touches[0].pageY : 0);
|
||||
let left = pageX - xOffset;
|
||||
let top = pageY - yOffset;
|
||||
if (left < 0) {
|
||||
left = 0;
|
||||
} else if (left > containerWidth) {
|
||||
left = containerWidth;
|
||||
} else if (top < 0) {
|
||||
top = 0;
|
||||
} else if (top > containerHeight) {
|
||||
top = containerHeight;
|
||||
}
|
||||
const saturation = left / containerWidth;
|
||||
let bright = -(top / containerHeight) + 1;
|
||||
bright = bright > 0 ? bright : 0;
|
||||
bright = bright > 1 ? 1 : bright;
|
||||
this.throttle(this.onChange, {
|
||||
h: this.colors.hsv.h,
|
||||
s: saturation,
|
||||
v: bright,
|
||||
a: this.colors.hsv.a,
|
||||
source: 'hsva'
|
||||
});
|
||||
},
|
||||
onChange (param) {
|
||||
this.$emit('change', param);
|
||||
},
|
||||
handleMouseDown () {
|
||||
// this.handleChange(e, true)
|
||||
window.addEventListener('mousemove', this.handleChange);
|
||||
window.addEventListener('mouseup', this.handleChange);
|
||||
window.addEventListener('mouseup', this.handleMouseUp);
|
||||
},
|
||||
handleMouseUp () {
|
||||
this.unbindEventListeners();
|
||||
},
|
||||
unbindEventListeners () {
|
||||
window.removeEventListener('mousemove', this.handleChange);
|
||||
window.removeEventListener('mouseup', this.handleChange);
|
||||
window.removeEventListener('mouseup', this.handleMouseUp);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
Loading…
Add table
Add a link
Reference in a new issue