1 | /**
|
---|
2 | * jscolor, JavaScript Color Picker
|
---|
3 | *
|
---|
4 | * @version 1.2.2
|
---|
5 | * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
---|
6 | * @author Honza Odvarko <honza@odvarko.cz>
|
---|
7 | * @created 2008-06-15
|
---|
8 | * @updated 2009-02-03
|
---|
9 | * @link http://jscolor.com
|
---|
10 | */
|
---|
11 |
|
---|
12 |
|
---|
13 | var jscolor = {
|
---|
14 |
|
---|
15 |
|
---|
16 | dir : '', // location of jscolor directory (leave empty to autodetect)
|
---|
17 | bindClass : 'color', // class name
|
---|
18 | binding : true, // automatic binding via <input class="...">
|
---|
19 | preloading : true, // use image preloading?
|
---|
20 |
|
---|
21 |
|
---|
22 | install : function() {
|
---|
23 | jscolor.addEvent(window, 'load', jscolor.init)
|
---|
24 | },
|
---|
25 |
|
---|
26 |
|
---|
27 | init : function() {
|
---|
28 | if(jscolor.binding) {
|
---|
29 | jscolor.bind()
|
---|
30 | }
|
---|
31 | if(jscolor.preloading) {
|
---|
32 | jscolor.preload()
|
---|
33 | }
|
---|
34 | },
|
---|
35 |
|
---|
36 |
|
---|
37 | getDir : function() {
|
---|
38 | if(!jscolor.dir) {
|
---|
39 | var detected = jscolor.detectDir()
|
---|
40 | jscolor.dir = detected!=false ? detected : 'jscolor/'
|
---|
41 | }
|
---|
42 | return jscolor.dir
|
---|
43 | },
|
---|
44 |
|
---|
45 |
|
---|
46 | detectDir : function() {
|
---|
47 | var base = location.href
|
---|
48 |
|
---|
49 | var e = document.getElementsByTagName('base')
|
---|
50 | for(var i=0; i<e.length; i++) {
|
---|
51 | if(e[i].href) base = e[i].href
|
---|
52 | }
|
---|
53 |
|
---|
54 | var e = document.getElementsByTagName('script')
|
---|
55 | for(var i=0; i<e.length; i++) {
|
---|
56 | if(e[i].src && /(^|\/)jscolor\.js([?#].*)?$/i.test(e[i].src)) {
|
---|
57 | var src = new jscolor.URI(e[i].src)
|
---|
58 | var srcAbs = src.toAbsolute(base)
|
---|
59 | srcAbs.path = srcAbs.path.replace(/[^\/]+$/, '') // remove filename
|
---|
60 | delete srcAbs.query
|
---|
61 | delete srcAbs.fragment
|
---|
62 | return srcAbs.toString()
|
---|
63 | }
|
---|
64 | }
|
---|
65 | return false
|
---|
66 | },
|
---|
67 |
|
---|
68 |
|
---|
69 | bind : function() {
|
---|
70 | var matchClass = new RegExp('(^|\\s)('+jscolor.bindClass+')\\s*(\\{[^}]*\\})?', 'i')
|
---|
71 | var e = document.getElementsByTagName('input')
|
---|
72 | for(var i=0; i<e.length; i++) {
|
---|
73 | var m
|
---|
74 | if(!e[i].color && e[i].className && (m = e[i].className.match(matchClass))) {
|
---|
75 | var prop = {}
|
---|
76 | if(m[3]) {
|
---|
77 | try {
|
---|
78 | eval('prop='+m[3])
|
---|
79 | } catch(eInvalidProp) {}
|
---|
80 | }
|
---|
81 | e[i].color = new jscolor.color(e[i], prop)
|
---|
82 | }
|
---|
83 | }
|
---|
84 | },
|
---|
85 |
|
---|
86 |
|
---|
87 | preload : function() {
|
---|
88 | for(var fn in jscolor.imgRequire) {
|
---|
89 | jscolor.loadImage(fn)
|
---|
90 | }
|
---|
91 | },
|
---|
92 |
|
---|
93 |
|
---|
94 | images : {
|
---|
95 | pad : [ 181, 101 ],
|
---|
96 | sld : [ 16, 101 ],
|
---|
97 | cross : [ 15, 15 ],
|
---|
98 | arrow : [ 7, 11 ]
|
---|
99 | },
|
---|
100 |
|
---|
101 |
|
---|
102 | imgRequire : {},
|
---|
103 | imgLoaded : {},
|
---|
104 |
|
---|
105 |
|
---|
106 | requireImage : function(filename) {
|
---|
107 | jscolor.imgRequire[filename] = true
|
---|
108 | },
|
---|
109 |
|
---|
110 |
|
---|
111 | loadImage : function(filename) {
|
---|
112 | if(!jscolor.imgLoaded[filename]) {
|
---|
113 | jscolor.imgLoaded[filename] = new Image()
|
---|
114 | jscolor.imgLoaded[filename].src = jscolor.getDir()+filename
|
---|
115 | }
|
---|
116 | },
|
---|
117 |
|
---|
118 |
|
---|
119 | fetchElement : function(mixed) {
|
---|
120 | return typeof(mixed) == 'string' ? document.getElementById(mixed) : mixed
|
---|
121 | },
|
---|
122 |
|
---|
123 |
|
---|
124 | addEvent : function(el, evnt, func) {
|
---|
125 | if(el.addEventListener) {
|
---|
126 | return el.addEventListener(evnt, func, false)
|
---|
127 | } else if(el.attachEvent) {
|
---|
128 | return el.attachEvent('on'+evnt, func)
|
---|
129 | } else {
|
---|
130 | return false
|
---|
131 | }
|
---|
132 | },
|
---|
133 |
|
---|
134 |
|
---|
135 | fireEvent : function(el, evnt) {
|
---|
136 | if(!el) {
|
---|
137 | return false
|
---|
138 | } else if(document.createEventObject) {
|
---|
139 | var ev = document.createEventObject()
|
---|
140 | return el.fireEvent('on'+evnt, ev)
|
---|
141 | } else if(document.createEvent) {
|
---|
142 | var ev = document.createEvent('HTMLEvents')
|
---|
143 | ev.initEvent(evnt, true, true)
|
---|
144 | return el.dispatchEvent(ev)
|
---|
145 | } else if(el['on'+evnt]) { // alternatively use the traditional event model (IE5)
|
---|
146 | return el['on'+evnt]()
|
---|
147 | } else {
|
---|
148 | return false
|
---|
149 | }
|
---|
150 | },
|
---|
151 |
|
---|
152 |
|
---|
153 | getElementPos : function(e) {
|
---|
154 | var e1=e, e2=e
|
---|
155 | var x=0, y=0
|
---|
156 | if(e1.offsetParent) {
|
---|
157 | do {
|
---|
158 | x += e1.offsetLeft
|
---|
159 | y += e1.offsetTop
|
---|
160 | } while(e1 = e1.offsetParent)
|
---|
161 | }
|
---|
162 | while((e2 = e2.parentNode) && e2.nodeName != 'BODY') {
|
---|
163 | x -= e2.scrollLeft
|
---|
164 | y -= e2.scrollTop
|
---|
165 | }
|
---|
166 | return [x, y]
|
---|
167 | },
|
---|
168 |
|
---|
169 |
|
---|
170 | getElementSize : function(e) {
|
---|
171 | return [e.offsetWidth, e.offsetHeight]
|
---|
172 | },
|
---|
173 |
|
---|
174 |
|
---|
175 | getMousePos : function(e) {
|
---|
176 | if(!e) e = window.event
|
---|
177 | if(typeof e.pageX == 'number') {
|
---|
178 | return [e.pageX, e.pageY]
|
---|
179 | } else if(typeof e.clientX == 'number') {
|
---|
180 | return [
|
---|
181 | e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft,
|
---|
182 | e.clientY + document.body.scrollTop + document.documentElement.scrollTop
|
---|
183 | ]
|
---|
184 | }
|
---|
185 | },
|
---|
186 |
|
---|
187 |
|
---|
188 | getViewPos : function() {
|
---|
189 | if(typeof window.pageYOffset == 'number') {
|
---|
190 | return [window.pageXOffset, window.pageYOffset]
|
---|
191 | } else if(document.body && (document.body.scrollLeft || document.body.scrollTop)) {
|
---|
192 | return [document.body.scrollLeft, document.body.scrollTop]
|
---|
193 | } else if(document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)) {
|
---|
194 | return [document.documentElement.scrollLeft, document.documentElement.scrollTop]
|
---|
195 | } else {
|
---|
196 | return [0, 0]
|
---|
197 | }
|
---|
198 | },
|
---|
199 |
|
---|
200 |
|
---|
201 | getViewSize : function() {
|
---|
202 | if(typeof window.innerWidth == 'number') {
|
---|
203 | return [window.innerWidth, window.innerHeight]
|
---|
204 | } else if(document.body && (document.body.clientWidth || document.body.clientHeight)) {
|
---|
205 | return [document.body.clientWidth, document.body.clientHeight]
|
---|
206 | } else if(document.documentElement && (document.documentElement.clientWidth || document.documentElement.clientHeight)) {
|
---|
207 | return [document.documentElement.clientWidth, document.documentElement.clientHeight]
|
---|
208 | } else {
|
---|
209 | return [0, 0]
|
---|
210 | }
|
---|
211 | },
|
---|
212 |
|
---|
213 |
|
---|
214 | URI : function(uri) { // See RFC3986
|
---|
215 |
|
---|
216 | this.scheme = null
|
---|
217 | this.authority = null
|
---|
218 | this.path = ''
|
---|
219 | this.query = null
|
---|
220 | this.fragment = null
|
---|
221 |
|
---|
222 | this.parse = function(uri) {
|
---|
223 | var m = uri.match(/^(([A-Za-z][0-9A-Za-z+.-]*)(:))?((\/\/)([^\/?#]*))?([^?#]*)((\?)([^#]*))?((#)(.*))?/)
|
---|
224 | this.scheme = m[3] ? m[2] : null
|
---|
225 | this.authority = m[5] ? m[6] : null
|
---|
226 | this.path = m[7]
|
---|
227 | this.query = m[9] ? m[10] : null
|
---|
228 | this.fragment = m[12] ? m[13] : null
|
---|
229 | return this
|
---|
230 | }
|
---|
231 |
|
---|
232 | this.toString = function() {
|
---|
233 | var result = ''
|
---|
234 | if(this.scheme != null) result = result + this.scheme + ':'
|
---|
235 | if(this.authority != null) result = result + '//' + this.authority
|
---|
236 | if(this.path != null) result = result + this.path
|
---|
237 | if(this.query != null) result = result + '?' + this.query
|
---|
238 | if(this.fragment != null) result = result + '#' + this.fragment
|
---|
239 | return result
|
---|
240 | }
|
---|
241 |
|
---|
242 | this.toAbsolute = function(base) {
|
---|
243 | var base = new jscolor.URI(base)
|
---|
244 | var r = this
|
---|
245 | var t = new jscolor.URI
|
---|
246 |
|
---|
247 | if(base.scheme == null) return false
|
---|
248 |
|
---|
249 | if(r.scheme != null && r.scheme.toLowerCase() == base.scheme.toLowerCase()) {
|
---|
250 | r.scheme = null
|
---|
251 | }
|
---|
252 |
|
---|
253 | if(r.scheme != null) {
|
---|
254 | t.scheme = r.scheme
|
---|
255 | t.authority = r.authority
|
---|
256 | t.path = removeDotSegments(r.path)
|
---|
257 | t.query = r.query
|
---|
258 | } else {
|
---|
259 | if(r.authority != null) {
|
---|
260 | t.authority = r.authority
|
---|
261 | t.path = removeDotSegments(r.path)
|
---|
262 | t.query = r.query
|
---|
263 | } else {
|
---|
264 | if(r.path == '') {
|
---|
265 | t.path = base.path
|
---|
266 | if(r.query != null) {
|
---|
267 | t.query = r.query
|
---|
268 | } else {
|
---|
269 | t.query = base.query
|
---|
270 | }
|
---|
271 | } else {
|
---|
272 | if(r.path.substr(0,1) == '/') {
|
---|
273 | t.path = removeDotSegments(r.path)
|
---|
274 | } else {
|
---|
275 | if(base.authority != null && base.path == '') {
|
---|
276 | t.path = '/'+r.path
|
---|
277 | } else {
|
---|
278 | t.path = base.path.replace(/[^\/]+$/,'')+r.path
|
---|
279 | }
|
---|
280 | t.path = removeDotSegments(t.path)
|
---|
281 | }
|
---|
282 | t.query = r.query
|
---|
283 | }
|
---|
284 | t.authority = base.authority
|
---|
285 | }
|
---|
286 | t.scheme = base.scheme
|
---|
287 | }
|
---|
288 | t.fragment = r.fragment
|
---|
289 |
|
---|
290 | return t
|
---|
291 | }
|
---|
292 |
|
---|
293 | function removeDotSegments(path) {
|
---|
294 | var out = ''
|
---|
295 | while(path) {
|
---|
296 | if(path.substr(0,3)=='../' || path.substr(0,2)=='./') {
|
---|
297 | path = path.replace(/^\.+/,'').substr(1)
|
---|
298 | } else if(path.substr(0,3)=='/./' || path=='/.') {
|
---|
299 | path = '/'+path.substr(3)
|
---|
300 | } else if(path.substr(0,4)=='/../' || path=='/..') {
|
---|
301 | path = '/'+path.substr(4)
|
---|
302 | out = out.replace(/\/?[^\/]*$/, '')
|
---|
303 | } else if(path=='.' || path=='..') {
|
---|
304 | path = ''
|
---|
305 | } else {
|
---|
306 | var rm = path.match(/^\/?[^\/]*/)[0]
|
---|
307 | path = path.substr(rm.length)
|
---|
308 | out = out + rm
|
---|
309 | }
|
---|
310 | }
|
---|
311 | return out
|
---|
312 | }
|
---|
313 |
|
---|
314 | if(uri) {
|
---|
315 | this.parse(uri)
|
---|
316 | }
|
---|
317 |
|
---|
318 | },
|
---|
319 |
|
---|
320 |
|
---|
321 | /*
|
---|
322 | * Usage example:
|
---|
323 | * var myColor = new jscolor.color(myInputElement)
|
---|
324 | */
|
---|
325 |
|
---|
326 | color : function(target, prop) {
|
---|
327 |
|
---|
328 |
|
---|
329 | this.required = true // refuse empty values?
|
---|
330 | this.adjust = true // adjust value to uniform notation?
|
---|
331 | this.hash = false // prefix color with # symbol?
|
---|
332 | this.caps = true // uppercase?
|
---|
333 | this.valueElement = target // value holder
|
---|
334 | this.styleElement = target // where to reflect current color
|
---|
335 | this.hsv = [0, 0, 1] // read-only 0-6, 0-1, 0-1
|
---|
336 | this.rgb = [1, 1, 1] // read-only 0-1, 0-1, 0-1
|
---|
337 |
|
---|
338 | this.pickerOnfocus = true // display picker on focus?
|
---|
339 | this.pickerMode = 'HSV' // HSV | HVS
|
---|
340 | this.pickerPosition = 'bottom' // left | right | top | bottom
|
---|
341 | this.pickerFace = 10 // px
|
---|
342 | this.pickerFaceColor = 'ThreeDFace' // CSS color
|
---|
343 | this.pickerBorder = 1 // px
|
---|
344 | this.pickerBorderColor = 'ThreeDHighlight ThreeDShadow ThreeDShadow ThreeDHighlight' // CSS color
|
---|
345 | this.pickerInset = 1 // px
|
---|
346 | this.pickerInsetColor = 'ThreeDShadow ThreeDHighlight ThreeDHighlight ThreeDShadow' // CSS color
|
---|
347 | this.pickerZIndex = 10000
|
---|
348 |
|
---|
349 |
|
---|
350 | for(var p in prop) this[p] = prop[p]
|
---|
351 |
|
---|
352 |
|
---|
353 | this.hidePicker = function() {
|
---|
354 | if(isPickerOwner()) {
|
---|
355 | removePicker()
|
---|
356 | }
|
---|
357 | }
|
---|
358 |
|
---|
359 |
|
---|
360 | this.showPicker = function() {
|
---|
361 | if(!isPickerOwner()) {
|
---|
362 | var tp = jscolor.getElementPos(target) // target pos
|
---|
363 | var ts = jscolor.getElementSize(target) // target size
|
---|
364 | var vp = jscolor.getViewPos() // view pos
|
---|
365 | var vs = jscolor.getViewSize() // view size
|
---|
366 | var ps = [ // picker size
|
---|
367 | 2*this.pickerBorder + 4*this.pickerInset + 2*this.pickerFace + jscolor.images.pad[0] + 2*jscolor.images.arrow[1] + jscolor.images.sld[0],
|
---|
368 | 2*this.pickerBorder + 2*this.pickerInset + 2*this.pickerFace + jscolor.images.pad[1]
|
---|
369 | ]
|
---|
370 | var a, b, c
|
---|
371 | switch(this.pickerPosition.toLowerCase()) {
|
---|
372 | case 'left': a=1; b=0; c=-1; break
|
---|
373 | case 'right':a=1; b=0; c=1; break
|
---|
374 | case 'top': a=0; b=1; c=-1; break
|
---|
375 | default: a=0; b=1; c=1; break
|
---|
376 | }
|
---|
377 | var l = (ts[b]+ps[b])/2
|
---|
378 | var pp = [ // picker pos
|
---|
379 | -vp[a]+tp[a]+ps[a] > vs[a] ?
|
---|
380 | (-vp[a]+tp[a]+ts[a]/2 > vs[a]/2 && tp[a]+ts[a]-ps[a] >= 0 ? tp[a]+ts[a]-ps[a] : tp[a]) : tp[a],
|
---|
381 | -vp[b]+tp[b]+ts[b]+ps[b]-l+l*c > vs[b] ?
|
---|
382 | (-vp[b]+tp[b]+ts[b]/2 > vs[b]/2 && tp[b]+ts[b]-l-l*c >= 0 ? tp[b]+ts[b]-l-l*c : tp[b]+ts[b]-l+l*c) :
|
---|
383 | (tp[b]+ts[b]-l+l*c >= 0 ? tp[b]+ts[b]-l+l*c : tp[b]+ts[b]-l-l*c)
|
---|
384 | ]
|
---|
385 | drawPicker(pp[a], pp[b])
|
---|
386 | }
|
---|
387 | }
|
---|
388 |
|
---|
389 |
|
---|
390 | this.importColor = function() {
|
---|
391 | if(!valueElement) {
|
---|
392 | this.exportColor()
|
---|
393 | } else {
|
---|
394 | if(!this.adjust) {
|
---|
395 | if(!this.fromString(valueElement.value, leaveValue)) {
|
---|
396 | styleElement.style.backgroundColor = styleElement.jscStyle.backgroundColor
|
---|
397 | styleElement.style.color = styleElement.jscStyle.color
|
---|
398 | this.exportColor(leaveValue | leaveStyle)
|
---|
399 | }
|
---|
400 | } else if(!this.required && /^\s*$/.test(valueElement.value)) {
|
---|
401 | valueElement.value = ''
|
---|
402 | styleElement.style.backgroundColor = styleElement.jscStyle.backgroundColor
|
---|
403 | styleElement.style.color = styleElement.jscStyle.color
|
---|
404 | this.exportColor(leaveValue | leaveStyle)
|
---|
405 |
|
---|
406 | } else if(this.fromString(valueElement.value)) {
|
---|
407 | // OK
|
---|
408 | } else {
|
---|
409 | this.exportColor()
|
---|
410 | }
|
---|
411 | }
|
---|
412 | }
|
---|
413 |
|
---|
414 |
|
---|
415 | this.exportColor = function(flags) {
|
---|
416 | if(!(flags & leaveValue) && valueElement) {
|
---|
417 | var value = this.toString()
|
---|
418 | if(this.caps) value = value.toUpperCase()
|
---|
419 | if(this.hash) value = '#'+value
|
---|
420 | valueElement.value = value
|
---|
421 | }
|
---|
422 | if(!(flags & leaveStyle) && styleElement) {
|
---|
423 | styleElement.style.backgroundColor = '#'+this.toString()
|
---|
424 | styleElement.style.color =
|
---|
425 | 0.213 * this.rgb[0] +
|
---|
426 | 0.715 * this.rgb[1] +
|
---|
427 | 0.072 * this.rgb[2]
|
---|
428 | < 0.5 ? '#FFF' : '#000'
|
---|
429 | }
|
---|
430 | if(!(flags & leavePad) && isPickerOwner()) {
|
---|
431 | redrawPad()
|
---|
432 | }
|
---|
433 | if(!(flags & leaveSld) && isPickerOwner()) {
|
---|
434 | redrawSld()
|
---|
435 | }
|
---|
436 | }
|
---|
437 |
|
---|
438 |
|
---|
439 | this.fromHSV = function(h, s, v, flags) { // null = don't change
|
---|
440 | h<0 && (h=0) || h>6 && (h=6)
|
---|
441 | s<0 && (s=0) || s>1 && (s=1)
|
---|
442 | v<0 && (v=0) || v>1 && (v=1)
|
---|
443 | this.rgb = HSV_RGB(
|
---|
444 | h==null ? this.hsv[0] : (this.hsv[0]=h),
|
---|
445 | s==null ? this.hsv[1] : (this.hsv[1]=s),
|
---|
446 | v==null ? this.hsv[2] : (this.hsv[2]=v)
|
---|
447 | )
|
---|
448 | this.exportColor(flags)
|
---|
449 | }
|
---|
450 |
|
---|
451 |
|
---|
452 | this.fromRGB = function(r, g, b, flags) { // null = don't change
|
---|
453 | r<0 && (r=0) || r>1 && (r=1)
|
---|
454 | g<0 && (g=0) || g>1 && (g=1)
|
---|
455 | b<0 && (b=0) || b>1 && (b=1)
|
---|
456 | var hsv = RGB_HSV(
|
---|
457 | r==null ? this.rgb[0] : (this.rgb[0]=r),
|
---|
458 | g==null ? this.rgb[1] : (this.rgb[1]=g),
|
---|
459 | b==null ? this.rgb[2] : (this.rgb[2]=b)
|
---|
460 | )
|
---|
461 | if(hsv[0] != null) {
|
---|
462 | this.hsv[0] = hsv[0]
|
---|
463 | }
|
---|
464 | if(hsv[2] != 0) {
|
---|
465 | this.hsv[1] = hsv[1]
|
---|
466 | }
|
---|
467 | this.hsv[2] = hsv[2]
|
---|
468 | this.exportColor(flags)
|
---|
469 | }
|
---|
470 |
|
---|
471 |
|
---|
472 | this.fromString = function(hex, flags) {
|
---|
473 | var m = hex.match(/^\W*([0-9A-F]{3}([0-9A-F]{3})?)\W*$/i)
|
---|
474 | if(!m) {
|
---|
475 | return false
|
---|
476 | } else {
|
---|
477 | if(m[1].length == 6) { // 6-char notation
|
---|
478 | this.fromRGB(
|
---|
479 | parseInt(m[1].substr(0,2),16) / 255,
|
---|
480 | parseInt(m[1].substr(2,2),16) / 255,
|
---|
481 | parseInt(m[1].substr(4,2),16) / 255,
|
---|
482 | flags
|
---|
483 | )
|
---|
484 | } else { // 3-char notation
|
---|
485 | this.fromRGB(
|
---|
486 | parseInt(m[1].charAt(0)+m[1].charAt(0),16) / 255,
|
---|
487 | parseInt(m[1].charAt(1)+m[1].charAt(1),16) / 255,
|
---|
488 | parseInt(m[1].charAt(2)+m[1].charAt(2),16) / 255,
|
---|
489 | flags
|
---|
490 | )
|
---|
491 | }
|
---|
492 | return true
|
---|
493 | }
|
---|
494 | }
|
---|
495 |
|
---|
496 |
|
---|
497 | this.toString = function() {
|
---|
498 | return (
|
---|
499 | (0x100 | Math.round(255*this.rgb[0])).toString(16).substr(1) +
|
---|
500 | (0x100 | Math.round(255*this.rgb[1])).toString(16).substr(1) +
|
---|
501 | (0x100 | Math.round(255*this.rgb[2])).toString(16).substr(1)
|
---|
502 | )
|
---|
503 | }
|
---|
504 |
|
---|
505 |
|
---|
506 | function RGB_HSV(r, g, b) {
|
---|
507 | var n = Math.min(Math.min(r,g),b)
|
---|
508 | var v = Math.max(Math.max(r,g),b)
|
---|
509 | var m = v - n
|
---|
510 | if(m == 0) return [ null, 0, v ]
|
---|
511 | var h = r==n ? 3+(b-g)/m : (g==n ? 5+(r-b)/m : 1+(g-r)/m)
|
---|
512 | return [ h==6?0:h, m/v, v ]
|
---|
513 | }
|
---|
514 |
|
---|
515 |
|
---|
516 | function HSV_RGB(h, s, v) {
|
---|
517 | if(h == null) return [ v, v, v ]
|
---|
518 | var i = Math.floor(h)
|
---|
519 | var f = i%2 ? h-i : 1-(h-i)
|
---|
520 | var m = v * (1 - s)
|
---|
521 | var n = v * (1 - s*f)
|
---|
522 | switch(i) {
|
---|
523 | case 6:
|
---|
524 | case 0: return [v,n,m]
|
---|
525 | case 1: return [n,v,m]
|
---|
526 | case 2: return [m,v,n]
|
---|
527 | case 3: return [m,n,v]
|
---|
528 | case 4: return [n,m,v]
|
---|
529 | case 5: return [v,m,n]
|
---|
530 | }
|
---|
531 | }
|
---|
532 |
|
---|
533 |
|
---|
534 | function removePicker() {
|
---|
535 | delete jscolor.picker.owner
|
---|
536 | document.getElementsByTagName('body')[0].removeChild(jscolor.picker.boxB)
|
---|
537 | }
|
---|
538 |
|
---|
539 |
|
---|
540 | function drawPicker(x, y) {
|
---|
541 | if(!jscolor.picker) {
|
---|
542 | jscolor.picker = {
|
---|
543 | box : document.createElement('div'),
|
---|
544 | boxB : document.createElement('div'),
|
---|
545 | pad : document.createElement('div'),
|
---|
546 | padB : document.createElement('div'),
|
---|
547 | padM : document.createElement('div'),
|
---|
548 | sld : document.createElement('div'),
|
---|
549 | sldB : document.createElement('div'),
|
---|
550 | sldM : document.createElement('div')
|
---|
551 | }
|
---|
552 | for(var i=0,segSize=4; i<jscolor.images.sld[1]; i+=segSize) {
|
---|
553 | var seg = document.createElement('div')
|
---|
554 | seg.style.height = segSize+'px'
|
---|
555 | seg.style.fontSize = '1px'
|
---|
556 | seg.style.lineHeight = '0'
|
---|
557 | jscolor.picker.sld.appendChild(seg)
|
---|
558 | }
|
---|
559 | jscolor.picker.sldB.appendChild(jscolor.picker.sld)
|
---|
560 | jscolor.picker.box.appendChild(jscolor.picker.sldB)
|
---|
561 | jscolor.picker.box.appendChild(jscolor.picker.sldM)
|
---|
562 | jscolor.picker.padB.appendChild(jscolor.picker.pad)
|
---|
563 | jscolor.picker.box.appendChild(jscolor.picker.padB)
|
---|
564 | jscolor.picker.box.appendChild(jscolor.picker.padM)
|
---|
565 | jscolor.picker.boxB.appendChild(jscolor.picker.box)
|
---|
566 | }
|
---|
567 |
|
---|
568 | var p = jscolor.picker
|
---|
569 |
|
---|
570 | // recompute controls positions
|
---|
571 | posPad = [
|
---|
572 | x+THIS.pickerBorder+THIS.pickerFace+THIS.pickerInset,
|
---|
573 | y+THIS.pickerBorder+THIS.pickerFace+THIS.pickerInset ]
|
---|
574 | posSld = [
|
---|
575 | null,
|
---|
576 | y+THIS.pickerBorder+THIS.pickerFace+THIS.pickerInset ]
|
---|
577 |
|
---|
578 | // controls interaction
|
---|
579 | p.box.onmouseup =
|
---|
580 | p.box.onmouseout = function() { target.focus() }
|
---|
581 | p.box.onmousedown = function() { abortBlur=true }
|
---|
582 | p.box.onmousemove = function(e) { holdPad && setPad(e); holdSld && setSld(e) }
|
---|
583 | p.padM.onmouseup =
|
---|
584 | p.padM.onmouseout = function() { if(holdPad) { holdPad=false; jscolor.fireEvent(valueElement,'change') } }
|
---|
585 | p.padM.onmousedown = function(e) { holdPad=true; setPad(e) }
|
---|
586 | p.sldM.onmouseup =
|
---|
587 | p.sldM.onmouseout = function() { if(holdSld) { holdSld=false; jscolor.fireEvent(valueElement,'change') } }
|
---|
588 | p.sldM.onmousedown = function(e) { holdSld=true; setSld(e) }
|
---|
589 |
|
---|
590 | // picker
|
---|
591 | p.box.style.width = 4*THIS.pickerInset + 2*THIS.pickerFace + jscolor.images.pad[0] + 2*jscolor.images.arrow[0] + jscolor.images.sld[0] + 'px'
|
---|
592 | p.box.style.height = 2*THIS.pickerInset + 2*THIS.pickerFace + jscolor.images.pad[1] + 'px'
|
---|
593 |
|
---|
594 | // picker border
|
---|
595 | p.boxB.style.position = 'absolute'
|
---|
596 | p.boxB.style.clear = 'both'
|
---|
597 | p.boxB.style.left = x+'px'
|
---|
598 | p.boxB.style.top = y+'px'
|
---|
599 | p.boxB.style.zIndex = THIS.pickerZIndex
|
---|
600 | p.boxB.style.border = THIS.pickerBorder+'px solid'
|
---|
601 | p.boxB.style.borderColor = THIS.pickerBorderColor
|
---|
602 | p.boxB.style.background = THIS.pickerFaceColor
|
---|
603 |
|
---|
604 | // pad image
|
---|
605 | p.pad.style.width = jscolor.images.pad[0]+'px'
|
---|
606 | p.pad.style.height = jscolor.images.pad[1]+'px'
|
---|
607 |
|
---|
608 | // pad border
|
---|
609 | p.padB.style.position = 'absolute'
|
---|
610 | p.padB.style.left = THIS.pickerFace+'px'
|
---|
611 | p.padB.style.top = THIS.pickerFace+'px'
|
---|
612 | p.padB.style.border = THIS.pickerInset+'px solid'
|
---|
613 | p.padB.style.borderColor = THIS.pickerInsetColor
|
---|
614 |
|
---|
615 | // pad mouse area
|
---|
616 | p.padM.style.position = 'absolute'
|
---|
617 | p.padM.style.left = '0'
|
---|
618 | p.padM.style.top = '0'
|
---|
619 | p.padM.style.width = THIS.pickerFace + 2*THIS.pickerInset + jscolor.images.pad[0] + jscolor.images.arrow[0] + 'px'
|
---|
620 | p.padM.style.height = p.box.style.height
|
---|
621 | p.padM.style.cursor = 'crosshair'
|
---|
622 |
|
---|
623 | // slider image
|
---|
624 | p.sld.style.overflow = 'hidden'
|
---|
625 | p.sld.style.width = jscolor.images.sld[0]+'px'
|
---|
626 | p.sld.style.height = jscolor.images.sld[1]+'px'
|
---|
627 |
|
---|
628 | // slider border
|
---|
629 | p.sldB.style.position = 'absolute'
|
---|
630 | p.sldB.style.right = THIS.pickerFace+'px'
|
---|
631 | p.sldB.style.top = THIS.pickerFace+'px'
|
---|
632 | p.sldB.style.border = THIS.pickerInset+'px solid'
|
---|
633 | p.sldB.style.borderColor = THIS.pickerInsetColor
|
---|
634 |
|
---|
635 | // slider mouse area
|
---|
636 | p.sldM.style.position = 'absolute'
|
---|
637 | p.sldM.style.right = '0'
|
---|
638 | p.sldM.style.top = '0'
|
---|
639 | p.sldM.style.width = jscolor.images.sld[0] + jscolor.images.arrow[0] + THIS.pickerFace + 2*THIS.pickerInset + 'px'
|
---|
640 | p.sldM.style.height = p.box.style.height
|
---|
641 | try {
|
---|
642 | p.sldM.style.cursor = 'pointer'
|
---|
643 | } catch(eOldIE) {
|
---|
644 | p.sldM.style.cursor = 'hand'
|
---|
645 | }
|
---|
646 |
|
---|
647 | // load images in optimal order
|
---|
648 | switch(modeID) {
|
---|
649 | case 0: var padImg = 'hs.png'; break
|
---|
650 | case 1: var padImg = 'hv.png'; break
|
---|
651 | }
|
---|
652 | p.padM.style.background = "url('"+jscolor.getDir()+"cross.gif') no-repeat"
|
---|
653 | p.sldM.style.background = "url('"+jscolor.getDir()+"arrow.gif') no-repeat"
|
---|
654 | p.pad.style.background = "url('"+jscolor.getDir()+padImg+"') 0 0 no-repeat"
|
---|
655 |
|
---|
656 | // place pointers
|
---|
657 | redrawPad()
|
---|
658 | redrawSld()
|
---|
659 |
|
---|
660 | jscolor.picker.owner = THIS
|
---|
661 | document.getElementsByTagName('body')[0].appendChild(p.boxB)
|
---|
662 | }
|
---|
663 |
|
---|
664 |
|
---|
665 | function redrawPad() {
|
---|
666 | // redraw the pad pointer
|
---|
667 | switch(modeID) {
|
---|
668 | case 0: var yComponent = 1; break
|
---|
669 | case 1: var yComponent = 2; break
|
---|
670 | }
|
---|
671 | var x = Math.round((THIS.hsv[0]/6) * (jscolor.images.pad[0]-1))
|
---|
672 | var y = Math.round((1-THIS.hsv[yComponent]) * (jscolor.images.pad[1]-1))
|
---|
673 | jscolor.picker.padM.style.backgroundPosition =
|
---|
674 | (THIS.pickerFace+THIS.pickerInset+x - Math.floor(jscolor.images.cross[0]/2)) + 'px ' +
|
---|
675 | (THIS.pickerFace+THIS.pickerInset+y - Math.floor(jscolor.images.cross[1]/2)) + 'px'
|
---|
676 |
|
---|
677 | // redraw the slider image
|
---|
678 | var seg = jscolor.picker.sld.childNodes
|
---|
679 |
|
---|
680 | switch(modeID) {
|
---|
681 | case 0:
|
---|
682 | var rgb = HSV_RGB(THIS.hsv[0], THIS.hsv[1], 1)
|
---|
683 | for(var i=0; i<seg.length; i++) {
|
---|
684 | seg[i].style.backgroundColor = 'rgb('+
|
---|
685 | (rgb[0]*(1-i/seg.length)*100)+'%,'+
|
---|
686 | (rgb[1]*(1-i/seg.length)*100)+'%,'+
|
---|
687 | (rgb[2]*(1-i/seg.length)*100)+'%)'
|
---|
688 | }
|
---|
689 | break
|
---|
690 | case 1:
|
---|
691 | var rgb, s, c = [ THIS.hsv[2], 0, 0 ]
|
---|
692 | var i = Math.floor(THIS.hsv[0])
|
---|
693 | var f = i%2 ? THIS.hsv[0]-i : 1-(THIS.hsv[0]-i)
|
---|
694 | switch(i) {
|
---|
695 | case 6:
|
---|
696 | case 0: rgb=[0,1,2]; break
|
---|
697 | case 1: rgb=[1,0,2]; break
|
---|
698 | case 2: rgb=[2,0,1]; break
|
---|
699 | case 3: rgb=[2,1,0]; break
|
---|
700 | case 4: rgb=[1,2,0]; break
|
---|
701 | case 5: rgb=[0,2,1]; break
|
---|
702 | }
|
---|
703 | for(var i=0; i<seg.length; i++) {
|
---|
704 | s = 1 - 1/(seg.length-1)*i
|
---|
705 | c[1] = c[0] * (1 - s*f)
|
---|
706 | c[2] = c[0] * (1 - s)
|
---|
707 | seg[i].style.backgroundColor = 'rgb('+
|
---|
708 | (c[rgb[0]]*100)+'%,'+
|
---|
709 | (c[rgb[1]]*100)+'%,'+
|
---|
710 | (c[rgb[2]]*100)+'%)'
|
---|
711 | }
|
---|
712 | break
|
---|
713 | }
|
---|
714 | }
|
---|
715 |
|
---|
716 |
|
---|
717 | function redrawSld() {
|
---|
718 | // redraw the slider pointer
|
---|
719 | switch(modeID) {
|
---|
720 | case 0: var yComponent = 2; break
|
---|
721 | case 1: var yComponent = 1; break
|
---|
722 | }
|
---|
723 | var y = Math.round((1-THIS.hsv[yComponent]) * (jscolor.images.sld[1]-1))
|
---|
724 | jscolor.picker.sldM.style.backgroundPosition =
|
---|
725 | '0 ' + (THIS.pickerFace+THIS.pickerInset+y - Math.floor(jscolor.images.arrow[1]/2)) + 'px'
|
---|
726 | }
|
---|
727 |
|
---|
728 |
|
---|
729 | function isPickerOwner() {
|
---|
730 | return jscolor.picker && jscolor.picker.owner == THIS
|
---|
731 | }
|
---|
732 |
|
---|
733 |
|
---|
734 | function blurTarget() {
|
---|
735 | if(valueElement == target) THIS.importColor()
|
---|
736 | if(THIS.pickerOnfocus) THIS.hidePicker()
|
---|
737 | }
|
---|
738 |
|
---|
739 |
|
---|
740 | function blurValue() {
|
---|
741 | if(valueElement != target) THIS.importColor()
|
---|
742 | }
|
---|
743 |
|
---|
744 |
|
---|
745 | function setPad(e) {
|
---|
746 | var posM = jscolor.getMousePos(e)
|
---|
747 | var x = posM[0]-posPad[0]
|
---|
748 | var y = posM[1]-posPad[1]
|
---|
749 | switch(modeID) {
|
---|
750 | case 0: THIS.fromHSV(x*(6/(jscolor.images.pad[0]-1)), 1 - y/(jscolor.images.pad[1]-1), null, leaveSld); break
|
---|
751 | case 1: THIS.fromHSV(x*(6/(jscolor.images.pad[0]-1)), null, 1 - y/(jscolor.images.pad[1]-1), leaveSld); break
|
---|
752 | }
|
---|
753 | }
|
---|
754 |
|
---|
755 |
|
---|
756 | function setSld(e) {
|
---|
757 | var posM = jscolor.getMousePos(e)
|
---|
758 | var y = posM[1]-posPad[1]
|
---|
759 | switch(modeID) {
|
---|
760 | case 0: THIS.fromHSV(null, null, 1 - y/(jscolor.images.sld[1]-1), leavePad); break
|
---|
761 | case 1: THIS.fromHSV(null, 1 - y/(jscolor.images.sld[1]-1), null, leavePad); break
|
---|
762 | }
|
---|
763 | }
|
---|
764 |
|
---|
765 |
|
---|
766 | var THIS = this
|
---|
767 | var modeID = this.pickerMode.toLowerCase()=='hvs' ? 1 : 0
|
---|
768 | var abortBlur = false
|
---|
769 | var
|
---|
770 | valueElement = jscolor.fetchElement(this.valueElement),
|
---|
771 | styleElement = jscolor.fetchElement(this.styleElement)
|
---|
772 | var
|
---|
773 | holdPad = false,
|
---|
774 | holdSld = false
|
---|
775 | var
|
---|
776 | posPad,
|
---|
777 | posSld
|
---|
778 | var
|
---|
779 | leaveValue = 1<<0,
|
---|
780 | leaveStyle = 1<<1,
|
---|
781 | leavePad = 1<<2,
|
---|
782 | leaveSld = 1<<3
|
---|
783 |
|
---|
784 | // target
|
---|
785 | jscolor.addEvent(target, 'focus', function() {
|
---|
786 | if(THIS.pickerOnfocus) THIS.showPicker()
|
---|
787 | })
|
---|
788 | jscolor.addEvent(target, 'blur', function() {
|
---|
789 | if(!abortBlur) {
|
---|
790 | setTimeout(function(){ abortBlur || blurTarget(); abortBlur=false }, 0)
|
---|
791 | } else {
|
---|
792 | abortBlur = false
|
---|
793 | }
|
---|
794 | })
|
---|
795 |
|
---|
796 | // valueElement
|
---|
797 | if(valueElement) {
|
---|
798 | var updateField = function() {
|
---|
799 | THIS.fromString(valueElement.value, leaveValue)
|
---|
800 | }
|
---|
801 | jscolor.addEvent(valueElement, 'keyup', updateField)
|
---|
802 | jscolor.addEvent(valueElement, 'input', updateField)
|
---|
803 | jscolor.addEvent(valueElement, 'blur', blurValue)
|
---|
804 | valueElement.setAttribute('autocomplete', 'off')
|
---|
805 | }
|
---|
806 |
|
---|
807 | // styleElement
|
---|
808 | if(styleElement) {
|
---|
809 | styleElement.jscStyle = {
|
---|
810 | backgroundColor : styleElement.style.backgroundColor,
|
---|
811 | color : styleElement.style.color
|
---|
812 | }
|
---|
813 | }
|
---|
814 |
|
---|
815 | // require images
|
---|
816 | switch(modeID) {
|
---|
817 | case 0: jscolor.requireImage('hs.png'); break
|
---|
818 | case 1: jscolor.requireImage('hv.png'); break
|
---|
819 | }
|
---|
820 | jscolor.requireImage('cross.gif');
|
---|
821 | jscolor.requireImage('arrow.gif');
|
---|
822 |
|
---|
823 | this.importColor()
|
---|
824 | }
|
---|
825 |
|
---|
826 | }
|
---|
827 |
|
---|
828 |
|
---|
829 | jscolor.install()
|
---|