Skip to content

Commit

Permalink
减少色彩空间转换造成的误差,优化取色拖动逻辑
Browse files Browse the repository at this point in the history
  • Loading branch information
599316527 committed Jan 22, 2019
1 parent 1227e6b commit 3c48441
Show file tree
Hide file tree
Showing 16 changed files with 163 additions and 203 deletions.
2 changes: 1 addition & 1 deletion packages/veui-theme-one/components/color-picker.less
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@

.veui-color-hue-slider {
.veui-slider-custom-track {
background: linear-gradient(to left, #F00, #FF0, #0F0, #0FF, #00F, #F0F, #F00);
background: linear-gradient(to right, #F00, #FF0, #0F0, #0FF, #00F, #F0F, #F00);
}
}

Expand Down
44 changes: 4 additions & 40 deletions packages/veui/src/components/ColorPicker/ColorPicker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,14 @@
:width="shadeFieldSize[0]"
:height="shadeFieldSize[1]"
:ui="realUi"
:hue="hsva.h"
:saturation="hsva.s"
:brightness="hsva.v"
:alpha="hsva.a"
:color="color"
:hsv="hsv"
/>
<div class="veui-color-picker-main-panel-sliders">
<veui-color-hue-slider :value="hsva.h"/>
<veui-color-hue-slider :hsl="hsl"/>
<veui-color-alpha-slider
v-if="alpha"
:hue="hsva.h"
:saturation="hsva.s"
:brightness="hsva.v"
:value="hsva.a"
:hsl="hsl"
/>
</div>
</div>
Expand All @@ -37,7 +32,6 @@
</template>

<script>
import tinycolor from 'tinycolor2'
import ColorSwatch from './ColorSwatch'
import ui from '../../mixins/ui'
import ColorHomer from './mixins/_ColorHomer'
Expand All @@ -57,42 +51,12 @@ export default {
mixins: [ui, ColorHomer],
data () {
return {
previousHsva: {},
shadeFieldSizeMap: config.get('colorpicker.shadeFieldSize')
}
},
computed: {
shadeFieldSize () {
return this.shadeFieldSizeMap[this.uiProps.size]
},
hsva () {
let prevHsva = this.previousHsva
let hsva = tinycolor(this.color).toHsv()
// fix
if (prevHsva.h % 360 === hsva.h % 360) {
// 因为色相是 360度循环的,360 被 tinycolor 转换成了 0,直接用的话会导致滑块跳变,所以这个特殊处理下
hsva.h = prevHsva.h
}
if (tinycolor.equals(hsva, prevHsva)) {
// 连续纯黑色情况下(SaturationBrightnessField底部区域),
// 传出再传入的 hsv 不一样,导致信息丢失,这里恢复一下,不然取色圈会跳变
// hsv(40, 0.001, 0.001) -> rgb(0, 0, 0) -> hsv(0, 0, 0)
hsva.h = prevHsva.h
hsva.s = prevHsva.s
}
if (hsva.s === 0 && prevHsva.s !== 0) {
hsva.h = prevHsva.h
}
if (hsva.h === undefined) {
hsva.h = prevHsva.h
}
if (!this.alpha) {
hsva.a = 1
}
return hsva
}
}
}
Expand Down
16 changes: 2 additions & 14 deletions packages/veui/src/components/ColorPicker/ColorSwatch.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,8 @@
v-bind="{
ui,
readonly,
hue: hsva.h,
saturation: hsva.s,
brightness: hsva.v,
alpha: hsva.a,
hsl,
rgb,
showTip: !!uiProps.tip,
switchable,
alphaChannel: alpha,
Expand All @@ -26,7 +24,6 @@
</template>

<script>
import tinycolor from 'tinycolor2'
import ValueAlphaGroup from './_ColorValueAlphaGroup'
import ui from '../../mixins/ui'
import ColorHomer from './mixins/_ColorHomer'
Expand All @@ -42,15 +39,6 @@ export default {
type: Boolean,
default: false
}
},
computed: {
hsva () {
let colors = tinycolor(this.color).toHsv()
return Object.keys(colors).reduce(function (obj, key) {
obj[key] = Math.round(colors[key] * 100) / 100
return obj
}, {})
}
}
}
</script>
18 changes: 10 additions & 8 deletions packages/veui/src/components/ColorPicker/_ColorAlphaSlider.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@
:min="0"
:max="1"
:step="0.01"
:value="value"
@input="updateAlphaValue"
:value="hsl.a"
@input="handleValueUpdate"
>
<div
slot="track"
class="veui-slider-custom-track"
:style="{
background: `linear-gradient(to right,
hsla(${hue}, ${saturation * 100}%,${brightness * 100}%, 0),
hsla(${hue}, ${saturation * 100}%,${brightness * 100}%, 1))`
hsla(${hsl.h}, ${hsl.s * 100}%,${hsl.l * 100}%, 0),
hsla(${hsl.h}, ${hsl.s * 100}%,${hsl.l * 100}%, 1))`
}"
/>
<div
Expand All @@ -35,10 +35,12 @@ export default {
mixins: [
ColorSlider
],
props: {
hue: Number,
saturation: Number,
brightness: Number
methods: {
handleValueUpdate (val) {
this.updateColor({
a: val
})
}
}
}
</script>
24 changes: 21 additions & 3 deletions packages/veui/src/components/ColorPicker/_ColorHueSlider.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
:min="0"
:max="360"
:step="1"
:value="value"
:value="localHue"
@input="handleValueUpdate"
>
<div
Expand All @@ -30,10 +30,28 @@ export default {
mixins: [
ColorSlider
],
data () {
return {
localHue: 0
}
},
watch: {
hsl: {
handler ({h}) {
// Hue 到了 360 时取余归零,为了避免滑块跳变,这里处理一下
if (h || this.localHue % 360) {
this.localHue = h
}
},
deep: true,
immediate: true
}
},
methods: {
handleValueUpdate (val) {
this.updateHsvValue({
h: val
this.localHue = val
this.updateColor({
h: val % 360
})
}
}
Expand Down
74 changes: 42 additions & 32 deletions packages/veui/src/components/ColorPicker/_ColorShadeField.vue
Original file line number Diff line number Diff line change
Expand Up @@ -71,39 +71,43 @@
class="veui-color-shade-field-aperture"
:style="{
'background-color': color,
transform: `translate(${aperturePosition.x - 6}px, ${aperturePosition.y - 6}px)`
transform: `translate(${dragCurrentX - 6}px, ${dragCurrentY - 6}px)`
}"
@click.stop
/>
</div>
</template>

<script>
import tinycolor from 'tinycolor2'
// import tinycolor from 'tinycolor2'
import {drag} from '../../directives'
import {clamp} from 'lodash'
import ColorUpdater from './mixins/_ColorUpdater'
import {getTypedAncestorTracker} from '../../utils/helper'
export default {
name: 'color-shade-field',
directives: {
drag
},
mixins: [
ColorUpdater
ColorUpdater,
getTypedAncestorTracker('color-homer')
],
props: {
width: Number,
height: Number,
hue: Number,
saturation: Number,
brightness: Number
color: String,
hsv: Object
},
data () {
return {
isDragging: false,
dragInitX: 0,
dragInitY: 0
dragInitY: 0,
dragCurrentX: 0,
dragCurrentY: 0
}
},
computed: {
Expand All @@ -112,41 +116,50 @@ export default {
return Math.round(Math.random() * 0xFFFFFF).toString(36)
},
aperturePosition () {
let saturation = this.saturation
let brightness = this.brightness
let {s, v} = this.hsv
return {
x: saturation * this.width,
y: (1 - brightness) * this.height
x: s * this.width,
y: (1 - v) * this.height
}
},
color () {
return tinycolor({
h: this.hue,
s: this.saturation,
v: this.brightness
}).toHslString()
},
hueColor () {
return tinycolor({
h: this.hue,
s: 1,
v: 1
}).toHexString()
return `hsl(${this.hsv.h}, 100%, 50%)`
}
},
watch: {
aperturePosition: {
handler ({x, y}) {
if (!this.isDragging) {
this.dragCurrentX = x
this.dragCurrentY = y
}
},
immediate: true
},
isDragging (val) {
// 如果拖到底下黑色那块儿,颜色出去转一圈回来 hue 变 0 了,呵呵,锁一下
this.colorHomer.lockHue(val ? this.hsv.h : null)
}
},
mounted () {
this.$on('dragstart', () => {
this.isDragging = true
this.dragInitX = this.aperturePosition.x
this.dragInitY = this.aperturePosition.y
// 一开始没拖的时候还是要从颜色反推位置
this.dragInitX = this.dragCurrentX === undefined ? this.aperturePosition.x : this.dragCurrentX
this.dragInitY = this.dragCurrentY === undefined ? this.aperturePosition.y : this.dragCurrentY
})
this.$on('dragend', () => {
this.isDragging = false
})
this.$on('drag', ({distanceX, distanceY}) => {
let x = this.dragInitX + distanceX
let y = this.dragInitY + distanceY
// 得合在一起传出去(satlig=saturation+brightness)。因为要冒泡到 ColorPicker format成字符串再传回来
// 底下黑色那一块儿颜色都糊在一起,从颜色算出来的坐标就很飘,还是用自己的位置比较稳
this.dragCurrentX = clamp(x, 0, this.width)
this.dragCurrentY = clamp(y, 0, this.height)
// 得合在一起传出去(satlig=saturation+brightness)。因为要到 ColorPicker format成字符串再传回来
// 如果分开的话,后一个到达 ColorPicker 的时候前一个还没生效,所以使用原来的值,导致前一个无法改变
this.updateSatbri(x / this.width, 1 - y / this.height)
})
Expand All @@ -157,12 +170,9 @@ export default {
this.$emit('dragend')
},
updateSatbri (saturation, brightness) {
saturation = clamp(saturation, 0, 1)
brightness = clamp(brightness, 0, 1)
this.updateHsvValue({
s: saturation,
v: brightness
})
let s = clamp(saturation, 0, 1)
let v = clamp(brightness, 0, 1)
this.updateColor({s, v})
}
}
}
Expand Down
13 changes: 10 additions & 3 deletions packages/veui/src/components/ColorPicker/_ColorValueAlpha.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
:format="formatPercentage"
:parse="parsePercentage"
nudge="percentage"
@input="updateAlphaValue"
@input="handleValueInput"
/>
</div>
</div>
Expand All @@ -19,8 +19,15 @@ import ColorValueInput from './mixins/_ColorValueInput'
export default {
name: 'color-value-alpha',
mixins: [ColorValueInput],
props: {
alpha: Number
computed: {
alpha () {
return this.hsl.a === undefined ? 1 : this.hsl.a
}
},
methods: {
handleValueInput (val) {
this.updateColor({a: val})
}
}
}
</script>
Loading

0 comments on commit 3c48441

Please sign in to comment.