Initiated ColorPicker

pull/146/head
cagataycivici 2020-01-13 10:46:42 +03:00
parent cd657d8add
commit d97f647988
13 changed files with 645 additions and 0 deletions

1
exports/colorpicker.d.ts vendored Normal file
View File

@ -0,0 +1 @@
export * from './components/colorpicker/ColorPicker';

3
exports/colorpicker.js Normal file
View File

@ -0,0 +1,3 @@
'use strict';
module.exports = require('./components/colorpicker/ColorPicker.vue');

View File

@ -10,6 +10,7 @@
<router-link to="/calendar">Calendar</router-link>
<router-link to="/checkbox">Checkbox</router-link>
<router-link to="/chips">Chips</router-link>
<router-link to="/colorpicker">ColorPicker</router-link>
<router-link to="/dropdown">Dropdown</router-link>
<router-link to="/editor">Editor</router-link>
<router-link to="/inputgroup">InputGroup</router-link>

View File

@ -1,6 +1,7 @@
@import '../../components/common/Common.css';
@import '../../components/button/Button.css';
@import '../../components/checkbox/Checkbox.css';
@import '../../components/colorpicker/ColorPicker.css';
@import '../../components/inputtext/InputText.css';
@import '../../components/password/Password.css';
@import '../../components/radiobutton/RadioButton.css';

View File

@ -0,0 +1,86 @@
.p-colorpicker {
display: inline-block;
}
.p-colorpicker-dragging {
cursor: pointer;
}
.p-colorpicker-overlay {
position: relative;
}
.p-colorpicker-panel {
position: relative;
width: 193px;
height: 166px;
background-color: #323232;
border-color: #191919;
}
.p-colorpicker-overlay-panel {
position: absolute;
}
.p-colorpicker-preview {
width: 2em;
cursor: pointer;
}
.p-colorpicker-panel .p-colorpicker-content {
position: relative;
}
.p-colorpicker-panel .p-colorpicker-color-selector {
width: 150px;
height: 150px;
top: 8px;
left: 8px;
position: absolute;
}
.p-colorpicker-panel .p-colorpicker-color {
width: 150px;
height: 150px;
background: transparent url("./images/color.png") no-repeat left top;
}
.p-colorpicker-panel .p-colorpicker-color-handle {
position: absolute;
top: 0px;
left: 150px;
border-radius: 100%;
width: 10px;
height: 10px;
border: 1px solid #ffffff;
margin: -5px 0 0 -5px;
cursor: pointer;
}
.p-colorpicker-panel .p-colorpicker-hue {
background: transparent url("./images/hue.png") no-repeat left top;
width: 17px;
height: 150px;
top: 8px;
left: 167px;
position: absolute;
opacity: .85;
}
.p-colorpicker-panel .p-colorpicker-hue-handle {
position: absolute;
top: 150px;
left: 0px;
width: 21px;
margin-left: -2px;
margin-top: -5px;
height: 10px;
border: 2px solid #ffffff;
opacity: .85;
cursor: pointer;
}
.p-colorpicker-panel.p-disabled .p-colorpicker-hue-handle,
.p-colorpicker-panel.p-disabled .p-colorpicker-color-handle {
opacity: .5;
}

View File

@ -0,0 +1,5 @@
import Vue, { VNode } from 'vue';
export declare class ColorPicker extends Vue {
value: any;
}

View File

@ -0,0 +1,419 @@
<template>
<div :class="containerClass">
<input ref="input" type="text" :class="inputClass" :style="inputStyle" readonly="readonly" :tabindex="tabindex" :disabled="disabled"
@click="onInputClick" @keydown="onInputKeydown" v-if="!inline"/>
<transition name="p-input-overlay" @enter="onOverlayEnter" @leave="onOverlayLeave">
<div ref="picker" :class="pickerClass" v-if="inline ? true : overlayVisible">
<div class="p-colorpicker-content">
<div ref="colorSelector" class="p-colorpicker-color-selector" @mousedown="onColorMousedown" :style="colorSelectorStyle">
<div class="p-colorpicker-color">
<div ref="colorHandle" class="p-colorpicker-color-handle" :style="colorHandleStyle"></div>
</div>
</div>
<div ref="hueView" class="p-colorpicker-hue" @mousedown="onHueMousedown">
<div ref="hueHandle" class="p-colorpicker-hue-handle" :style="hueHandleStyle"></div>
</div>
</div>
</div>
</transition>
</div>
</template>
<script>
import DomHandler from '../utils/DomHandler';
export default {
props: {
value: {
type: null,
default: null
},
defaultColor: {
type: null,
default: 'ff0000'
},
inline: {
type: Boolean,
default: false
},
format: {
type: String,
default: 'hex'
},
disabled: {
type: Boolean,
default: false
},
tabindex: {
type: String,
default: null
},
autoZIndex: {
type: Boolean,
default: true
},
baseZIndex: {
type: Number,
default: 0
}
},
data() {
return {
overlayVisible: false
};
},
outsideClickListener: null,
documentMouseMoveListener: null,
documentMouseUpListener: null,
hueDragging: null,
colorDragging: null,
beforeDestroy() {
this.unbindOutsideClickListener();
this.unbindDocumentMouseMoveListener();
this.unbindDocumentMouseUpListener();
},
methods: {
pickColor(event) {
let rect = this.$refs.colorSelector.getBoundingClientRect();
let top = rect.top + (window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0);
let left = rect.left + document.body.scrollLeft;
let saturation = Math.floor(100 * (Math.max(0, Math.min(150, (event.pageX - left)))) / 150);
let brightness = Math.floor(100 * (150 - Math.max(0, Math.min(150, (event.pageY - top)))) / 150);
let newHSBValue = this.validateHSB({
h: this.hsbValue.h,
s: saturation,
b: brightness
});
this.updateModel(newHSBValue);
},
pickHue(event) {
let top = this.$refs.hueView.getBoundingClientRect().top + (window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0);
let hsbValue = this.validateHSB({
h: Math.floor(360 * (150 - Math.max(0, Math.min(150, (event.pageY - top)))) / 150),
s: 100,
b: 100
});
this.updateModel(hsbValue);
},
updateModel(value) {
switch(this.format) {
case 'hex':
this.$emit('input', this.HSBtoHEX(value));
break;
case 'rgb':
this.$emit('input', this.HSBtoRGB(value));
break;
case 'hsb':
this.$emit('input', value);
break;
default:
//NoOp
break;
}
},
validateHSB(hsb) {
return {
h: Math.min(360, Math.max(0, hsb.h)),
s: Math.min(100, Math.max(0, hsb.s)),
b: Math.min(100, Math.max(0, hsb.b))
};
},
validateRGB(rgb) {
return {
r: Math.min(255, Math.max(0, rgb.r)),
g: Math.min(255, Math.max(0, rgb.g)),
b: Math.min(255, Math.max(0, rgb.b))
};
},
validateHEX(hex) {
var len = 6 - hex.length;
if (len > 0) {
var o = [];
for (var i=0; i<len; i++) {
o.push('0');
}
o.push(hex);
hex = o.join('');
}
return hex;
},
HEXtoRGB(hex) {
let hexValue = parseInt(((hex.indexOf('#') > -1) ? hex.substring(1) : hex), 16);
return {r: hexValue >> 16, g: (hexValue & 0x00FF00) >> 8, b: (hexValue & 0x0000FF)};
},
HEXtoHSB(hex) {
return this.RGBtoHSB(this.HEXtoRGB(hex));
},
RGBtoHSB(rgb) {
var hsb = {
h: 0,
s: 0,
b: 0
};
var min = Math.min(rgb.r, rgb.g, rgb.b);
var max = Math.max(rgb.r, rgb.g, rgb.b);
var delta = max - min;
hsb.b = max;
if (max !== 0) {
}
hsb.s = max !== 0 ? 255 * delta / max : 0;
if (hsb.s !== 0) {
if (rgb.r === max) {
hsb.h = (rgb.g - rgb.b) / delta;
} else if (rgb.g === max) {
hsb.h = 2 + (rgb.b - rgb.r) / delta;
} else {
hsb.h = 4 + (rgb.r - rgb.g) / delta;
}
} else {
hsb.h = -1;
}
hsb.h *= 60;
if (hsb.h < 0) {
hsb.h += 360;
}
hsb.s *= 100/255;
hsb.b *= 100/255;
return hsb;
},
HSBtoRGB(hsb) {
var rgb = {
r: null, g: null, b: null
};
var h = Math.round(hsb.h);
var s = Math.round(hsb.s*255/100);
var v = Math.round(hsb.b*255/100);
if (s === 0) {
rgb = {
r: v,
g: v,
b: v
}
}
else {
var t1 = v;
var t2 = (255-s)*v/255;
var t3 = (t1-t2)*(h%60)/60;
if (h===360) h = 0;
if (h<60) {rgb.r=t1; rgb.b=t2; rgb.g=t2+t3}
else if (h<120) {rgb.g=t1; rgb.b=t2; rgb.r=t1-t3}
else if (h<180) {rgb.g=t1; rgb.r=t2; rgb.b=t2+t3}
else if (h<240) {rgb.b=t1; rgb.r=t2; rgb.g=t1-t3}
else if (h<300) {rgb.b=t1; rgb.g=t2; rgb.r=t2+t3}
else if (h<360) {rgb.r=t1; rgb.g=t2; rgb.b=t1-t3}
else {rgb.r=0; rgb.g=0; rgb.b=0}
}
return {r:Math.round(rgb.r), g:Math.round(rgb.g), b:Math.round(rgb.b)};
},
RGBtoHEX(rgb) {
var hex = [
rgb.r.toString(16),
rgb.g.toString(16),
rgb.b.toString(16)
];
for (var key in hex) {
if (hex[key].length === 1) {
hex[key] = '0' + hex[key];
}
}
return hex.join('');
},
HSBtoHEX(hsb) {
return this.RGBtoHEX(this.HSBtoRGB(hsb));
},
toHSB(value) {
let hsb;
if (value) {
switch (this.format) {
case 'hex':
hsb = this.HEXtoHSB(value);
break;
case 'rgb':
hsb = this.RGBtoHSB(value);
break;
case 'hsb':
hsb = value;
break;
default:
break;
}
}
else {
hsb = this.HEXtoHSB(this.defaultColor);
}
return hsb;
},
onOverlayEnter() {
this.alignOverlay();
this.bindOutsideClickListener();
if (this.autoZIndex) {
this.$refs.picker.style.zIndex = String(this.baseZIndex + DomHandler.generateZIndex());
}
},
onOverlayLeave() {
this.unbindOutsideClickListener();
},
alignOverlay() {
DomHandler.relativePosition(this.$refs.picker, this.$refs.input);
},
onInputClick(event) {
if (this.disabled) {
return;
}
this.overlayVisible = !this.overlayVisible;
},
onInputKeydown(event) {
switch(event.which) {
//space
case 32:
this.overlayVisible = !this.overlayVisible;
event.preventDefault();
break;
//escape and tab
case 27:
case 9:
this.overlayVisible = false;
break;
default:
//NoOp
break;
}
},
onColorMousedown(event) {
if (this.disabled) {
return;
}
this.colorDragging = true;
this.bindDocumentMouseMoveListener();
this.bindDocumentMouseUpListener();
this.pickColor(event);
DomHandler.addClass(this.$el, 'p-colorpicker-dragging');
},
onHueMousedown(event) {
if (this.disabled) {
return;
}
this.hueDragging = true;
this.bindDocumentMouseMoveListener();
this.bindDocumentMouseUpListener();
this.pickHue(event);
DomHandler.addClass(this.$el, 'p-colorpicker-dragging');
},
isInputClicked(event) {
return this.$refs.input && this.$refs.input.isSameNode(event.target);
},
bindOutsideClickListener() {
if (!this.outsideClickListener) {
this.outsideClickListener = (event) => {
if (this.overlayVisible && this.$refs.picker && !this.$refs.picker.contains(event.target) && !this.isInputClicked(event)) {
this.overlayVisible = false;
}
};
document.addEventListener('click', this.outsideClickListener);
}
},
unbindOutsideClickListener() {
if (this.outsideClickListener) {
document.removeEventListener('click', this.outsideClickListener);
this.outsideClickListener = null;
}
},
bindDocumentMouseMoveListener() {
if (!this.documentMouseMoveListener) {
this.documentMouseMoveListener = (event) => {
if (this.colorDragging) {
this.pickColor(event);
}
if (this.hueDragging) {
this.pickHue(event);
}
};
document.addEventListener('mousemove', this.documentMouseMoveListener);
}
},
unbindDocumentMouseMoveListener() {
if (this.documentMouseMoveListener) {
document.removeEventListener('mousemove', this.documentMouseMoveListener);
this.documentMouseMoveListener = null;
}
},
bindDocumentMouseUpListener() {
if (!this.documentMouseUpListener) {
this.documentMouseUpListener = (event) => {
this.colorDragging = false;
this.hueDragging = false;
DomHandler.removeClass(this.$el, 'p-colorpicker-dragging');
this.unbindDocumentMouseMoveListener();
this.unbindDocumentMouseUpListener();
};
document.addEventListener('mouseup', this.documentMouseUpListener);
}
},
unbindDocumentMouseUpListener() {
if (this.documentMouseUpListener) {
document.removeEventListener('mouseup', this.documentMouseUpListener);
this.documentMouseUpListener = null;
}
}
},
computed: {
containerClass() {
return ['p-colorpicker p-component', {'p-colorpicker-overlay': !this.inline}];
},
inputClass() {
return ['p-colorpicker-preview p-inputtext', {'p-disabled': this.disabled}];
},
pickerClass() {
return ['p-colorpicker-panel', {'p-colorpicker-overlay-panel': !this.inline, 'p-disabled': this.disabled}];
},
inputStyle() {
return {backgroundColor: '#' + this.HSBtoHEX(this.hsbValue)};
},
colorHandleStyle() {
return {
left: Math.floor(150 * this.hsbValue.s / 100) + 'px',
top: Math.floor(150 * (100 - this.hsbValue.b) / 100) + 'px'
}
},
colorSelectorStyle() {
let hsbValue = this.validateHSB({
h: this.hsbValue.h,
s: 100,
b: 100
});
return {
backgroundColor: '#' + this.HSBtoHEX(hsbValue)
}
},
hueHandleStyle() {
return {
top: Math.floor(150 - (150 * this.hsbValue.h / 360)) + 'px'
}
},
hsbValue() {
return this.toHSB(this.value);
}
}
}
</script>

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 293 B

View File

@ -12,6 +12,7 @@ import Carousel from './components/carousel/Carousel';
import Chart from './components/chart/Chart';
import Checkbox from './components/checkbox/Checkbox';
import Chips from './components/chips/Chips';
import ColorPicker from './components/colorpicker/ColorPicker';
import Column from './components/column/Column';
import ColumnGroup from './components/columngroup/ColumnGroup';
import ContextMenu from './components/contextmenu/ContextMenu';
@ -98,6 +99,7 @@ Vue.component('Carousel', Carousel);
Vue.component('Chart', Chart);
Vue.component('Checkbox', Checkbox);
Vue.component('Chips', Chips);
Vue.component('ColorPicker', ColorPicker);
Vue.component('Column', Column);
Vue.component('ColumnGroup', ColumnGroup);
Vue.component('ContextMenu', ContextMenu);

View File

@ -116,6 +116,11 @@ export default new Router({
name: 'chips',
component: () => import('./views/chips/ChipsDemo.vue')
},
{
path: '/colorpicker',
name: 'colorpicker',
component: () => import('./views/colorpicker/ColorPickerDemo.vue')
},
{
path: '/contextmenu',
name: 'contextmenu',

View File

@ -0,0 +1,36 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>ColorPicker</h1>
<p>ColorPicker is an input component to select a color.</p>
</div>
</div>
<div class="content-section implementation">
<h3>Inline</h3>
<ColorPicker v-model="color1" :inline="true" />{{color1}}
<h3>Overlay</h3>
<ColorPicker v-model="color2" />{{color2}}
</div>
<ColorPickerDoc />
</div>
</template>
<script>
import ColorPickerDoc from './ColorPickerDoc';
export default {
data() {
return {
color1: null,
color2: '1976D2'
}
},
components: {
'ColorPickerDoc': ColorPickerDoc
}
}
</script>

View File

@ -0,0 +1,86 @@
<template>
<div class="content-section documentation">
<TabView>
<TabPanel header="Documentation">
<h3>Import</h3>
<CodeHighlight lang="javascript">
import ColorPicker from 'primevue/colorpicker';
</CodeHighlight>
<h3>Getting Started</h3>
<p>A model can be bound using the standard v-model directive.</p>
<CodeHighlight>
&lt;InputText type="text" v-model="value" /&gt;
</CodeHighlight>
<h3>Float Label</h3>
<p>A floating label is implemented by wrapping the input and the label inside a container having <i>.p-float-label</i> style class.</p>
<CodeHighlight>
&lt;span class="p-float-label"&gt;
&lt;InputText id="username" type="text" v-model="value" /&gt;
&lt;label for="username"&gt;Username&lt;/label&gt;
&lt;/span&gt;
</CodeHighlight>
<h3>Properties</h3>
<p>InputText passes any valid attribute to the underlying input element.</p>
<h3>Styling</h3>
<p>Following is the list of structural style classes, for theming classes visit <router-link to="/theming">theming</router-link> page.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Element</th>
</tr>
</thead>
<tbody>
<tr>
<td>p-inputtext</td>
<td>Input element</td>
</tr>
</tbody>
</table>
</div>
<h3>Dependencies</h3>
<p>None.</p>
</TabPanel>
<TabPanel header="Source">
<a href="https://github.com/primefaces/primevue/tree/master/src/views/inputtext" class="btn-viewsource" target="_blank" rel="noopener noreferrer">
<span>View on GitHub</span>
</a>
<CodeHighlight>
<template v-pre>
&lt;h3&gt;Basic&lt;/h3&gt;
&lt;InputText type="text" v-model="value1" /&gt;
&lt;span :style="{marginLeft: '.5em'}"&gt;{{value1}}&lt;/span&gt;
&lt;h3&gt;Floating Label&lt;/h3&gt;
&lt;span class="p-float-label"&gt;
&lt;InputText id="username" type="text" v-model="value2" /&gt;
&lt;label for="username"&gt;Username&lt;/label&gt;
&lt;/span&gt;
&lt;h3&gt;Disabled&lt;/h3&gt;
&lt;InputText type="text" v-model="value3" disabled /&gt;
</template>
</CodeHighlight>
<CodeHighlight lang="javascript">
export default {
data() {
return {
value1: '',
value2: '',
value3: 'PrimeVue'
}
}
}
</CodeHighlight>
</TabPanel>
</TabView>
</div>
</template>