1
+ import { createApp } from "https://unpkg.com/[email protected] /dist/vue.esm-browser.prod.js" ;
1
2
import Color from "../../dist/color.js" ;
2
3
import methods from "./methods.js" ;
3
4
4
5
globalThis . Color = Color ;
5
6
6
7
const favicon = document . querySelector ( 'link[rel="shortcut icon"]' ) ;
7
8
const lch = [ "L" , "C" , "H" ] ;
9
+ let spacesToShow = [ Color . spaces . oklch , Color . spaces . p3 , Color . spaces [ "p3-linear" ] ]
8
10
9
- for ( let method in methods ) {
10
- let config = methods [ method ] ;
11
- let label = config . label ?? method [ 0 ] . toUpperCase ( ) + method . slice ( 1 ) ;
12
-
13
- gamut_mapped . insertAdjacentHTML ( "beforeend" , `
14
- <div>
15
- <dt>
16
- ${ label }
17
- ${ config . description ? `<small class="description">${ config . description } </small>` : "" }
18
- </dd>
19
- <dd>
20
- <css-color swatch="large" data-method="${ method } "></css-color>
21
- </dd>
22
- </div>` ) ;
23
- }
24
-
25
- css_color_input . addEventListener ( "input" , evt => {
26
- if ( css_color . color === null ) {
27
- // Probably typing
28
- return ;
29
- }
30
-
31
- colorUpdated ( )
32
-
33
- let inputColor = css_color . color ;
34
- let p3color = inputColor . to ( "p3" ) ;
35
- let p3Linear = inputColor . to ( "p3-linear" ) ;
36
-
37
- to_p3 . color = p3color ;
38
- to_p3linear . color = p3Linear ;
39
-
40
- let minDeltas ;
11
+ let app = createApp ( {
12
+ data ( ) {
13
+ let params = new URLSearchParams ( location . search ) ;
14
+ let defaultValue = "oklch(90% .8 250)" ;
15
+ let colorInput = params . get ( "color" ) || defaultValue ;
16
+ let color ;
41
17
42
- for ( let cssColor of gamut_mapped . querySelectorAll ( "css-color" ) ) {
43
- let method = cssColor . dataset . method ;
44
- let color = p3color . clone ( ) ;
45
-
46
- let dd = cssColor . closest ( "dd" ) ;
47
- let stats = dd . querySelector ( ".deltas" ) ;
48
-
49
- if ( ! stats ) {
50
- dd . insertAdjacentHTML ( "beforeend" , `<dl class="deltas"></dl>` ) ;
51
- stats = dd . querySelector ( ".deltas" ) ;
18
+ try {
19
+ color = new Color ( colorInput ) ;
52
20
}
53
-
54
- if ( color . inGamut ( "p3" ) ) {
55
- cssColor . color = color ;
56
- stats . innerHTML = "" ;
57
- continue ;
21
+ catch ( e ) {
22
+ color = new Color ( "transparent" ) ;
58
23
}
59
24
60
- minDeltas ??= [ ] ;
61
-
62
- let mappedColor ;
63
-
64
- let methodConfig = methods [ method ] ;
65
-
66
- if ( methodConfig . compute ) {
67
- mappedColor = methodConfig . compute ( inputColor ) ;
68
- }
69
- else {
70
- mappedColor = color . toGamut ( { method } ) ;
25
+ return {
26
+ color,
27
+ colorNullable : color ,
28
+ colorInput,
29
+ defaultValue,
30
+ methods,
31
+ params,
32
+ Color,
33
+ lch : [ "L" , "C" , "H" ] ,
71
34
}
72
-
73
- cssColor . color = mappedColor ;
74
-
75
- // Show deltas
76
- let deltas = getDeltas ( inputColor , mappedColor , minDeltas , stats ) ;
77
-
78
- stats . innerHTML = deltas . map ( ( delta , i ) => {
79
- let cl = delta < 0 ? "negative" : delta > 0 ? "positive" : "zero" ;
80
- return `<dt>Δ${ lch [ i ] } </dt><dd class="${ cl } ">${ delta } </dd>`
81
- } ) . join ( "" ) ;
82
- }
83
-
84
- // Find min deltas
85
- if ( minDeltas ) {
86
- for ( let minDelta of minDeltas ) {
87
- let index = minDelta . index * 2 + 1 ;
88
- for ( let dl of [ ] . concat ( minDelta . stats ) ) {
89
- let dd = dl . children [ minDelta . index * 2 + 1 ] ;
90
- dd . classList . add ( "min" ) ;
35
+ } ,
36
+
37
+ computed : {
38
+ colorLCH ( ) {
39
+ return this . color . to ( "oklch" ) ;
40
+ } ,
41
+
42
+ spaces ( ) {
43
+ /*
44
+ <div v-for="(c, i) of color.to(space).coords">
45
+ <dt :title="coordInfo[spaceIndex][i][1].name">{{ coordInfo[spaceIndex][i][0].toUpperCase() }}</dt>
46
+ <dd>{{ toPrecision(c, 3) }}</dd>
47
+ </div>
48
+ */
49
+ return spacesToShow . map ( space => {
50
+ let coordInfo = Object . entries ( space . coords ) ;
51
+ let coords = this . color . to ( space ) . coords . map ( c => this . toPrecision ( c , 3 ) ) ;
52
+ return {
53
+ name : space . name ,
54
+ coords : Object . fromEntries ( coordInfo . map ( ( [ c , info ] , i ) => [ c , { value : coords [ i ] , name : info . name , id : c } ] ) )
55
+ }
56
+ } ) ;
57
+ } ,
58
+
59
+ mapped ( ) {
60
+ return Object . fromEntries ( Object . entries ( this . methods ) . map ( ( [ method , config ] ) => {
61
+ let mappedColor ;
62
+ if ( config . compute ) {
63
+ mappedColor = config . compute ( this . color ) ;
64
+ }
65
+ else {
66
+ mappedColor = this . color . clone ( ) . toGamut ( { space : "p3" , method } ) ;
67
+ }
68
+
69
+ let mappedColorLCH = mappedColor . to ( "oklch" ) ;
70
+ let deltas = Object . fromEntries ( lch . map ( ( c , i ) => {
71
+ let delta = this . colorLCH . coords [ i ] - mappedColorLCH . coords [ i ] ;
72
+ delta = this . toPrecision ( delta , 2 ) ;
73
+ return [ c , delta ] ;
74
+ } ) ) ;
75
+
76
+ deltas . L *= 100 ; // L is percentage
77
+
78
+ // Hue is angular, so we need to normalize it
79
+ deltas . H = ( ( deltas . H % 360 ) + 720 ) % 360 ;
80
+ deltas . H = this . toPrecision ( Math . min ( 360 - deltas . H , deltas . H ) , 2 ) ;
81
+
82
+ return [ method , { color : mappedColor , deltas} ] ;
83
+ } ) ) ;
84
+ } ,
85
+
86
+ minDeltas ( ) {
87
+ let ret = { } ;
88
+ for ( let method in this . mapped ) {
89
+ let { deltas} = this . mapped [ method ] ;
90
+
91
+ for ( let c in deltas ) {
92
+ let delta = Math . abs ( deltas [ c ] ) ;
93
+ let minDelta = ret [ c ] ;
94
+
95
+ if ( ! minDelta || minDelta >= delta ) {
96
+ ret [ c ] = delta ;
97
+ }
98
+ }
99
+ }
100
+ return ret ;
101
+ } ,
102
+ } ,
103
+
104
+ methods : {
105
+ toPrecision : Color . util . toPrecision ,
106
+ } ,
107
+
108
+ watch : {
109
+ colorNullable ( ) {
110
+ if ( this . colorNullable === null ) {
111
+ // Probably typing
112
+ return ;
91
113
}
92
- }
93
- }
94
- } ) ;
95
-
96
- let params = new URLSearchParams ( location . search ) ;
97
- let color = params . get ( "color" ) ;
98
-
99
- if ( color ) {
100
- css_color . value = color ;
101
- }
102
-
103
- css_color_input . dispatchEvent ( new InputEvent ( "input" ) ) ;
104
-
105
-
106
-
107
- function colorUpdated ( ) {
108
- let input = css_color_input ;
109
-
110
- // Update URL to create a permalink
111
- let params = new URLSearchParams ( location . search ) ;
112
- let hadColor = params . has ( "color" ) ;
113
- let value = input . value ;
114
- let defaultValue = input . getAttribute ( "value" ) ;
115
-
116
- if ( value !== defaultValue ) {
117
- params . set ( "color" , value ) ;
118
- }
119
- else {
120
- params . delete ( "color" ) ;
121
- }
122
-
123
- history [ hadColor == params . has ( "color" ) ? "replaceState" : "pushState" ] ( null , "" , "?" + params . toString ( ) ) ;
124
-
125
- // Update favicon
126
- favicon . href = `data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%" fill="${ encodeURIComponent ( value ) } " /></svg>` ;
127
-
128
- // Update title
129
- document . title = value + " • Gamut Mapping Playground" ;
130
- }
131
-
132
- function getDeltas ( inputColor , mappedColor , minDeltas , stats ) {
133
- let mappedColorLCH = mappedColor . to ( "oklch" ) . coords ;
134
- let deltas = inputColor . to ( "oklch" ) . coords . map ( ( c , i ) => {
135
- let delta = mappedColorLCH [ i ] - c ;
136
114
137
- if ( i === 2 ) {
138
- // Hue is angular, so we need to normalize it
139
- delta = ( delta + 720 ) % 360 ;
140
- delta = delta > 180 ? 360 - delta : delta ;
141
- }
115
+ this . color = this . colorNullable ;
116
+ } ,
142
117
143
- delta = Color . util . toPrecision ( delta , 2 ) ;
118
+ colorInput ( value ) {
119
+ // Update URL to create a permalink
120
+ let hadColor = this . params . has ( "color" ) ;
144
121
145
- let minDelta = minDeltas [ i ] ;
146
- if ( ! minDelta || minDelta . value >= Math . abs ( delta ) ) {
147
- if ( minDelta && minDelta . value == Math . abs ( delta ) ) {
148
- minDelta . stats = [ ] . concat ( minDelta . stats ) ;
149
- minDelta . stats . push ( stats ) ;
122
+ if ( ! value || value !== this . defaultValue ) {
123
+ this . params . set ( "color" , value ) ;
150
124
}
151
125
else {
152
- minDeltas [ i ] = { value : Math . abs ( delta ) , stats , index : i } ;
126
+ this . params . delete ( "color" ) ;
153
127
}
154
128
129
+ history [ hadColor == this . params . has ( "color" ) ? "replaceState" : "pushState" ] ( null , "" , "?" + this . params . toString ( ) ) ;
130
+
131
+ // Update favicon
132
+ favicon . href = `data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%" fill="${ encodeURIComponent ( value ) } " /></svg>` ;
133
+
134
+ // Update title
135
+ document . title = value + " • Gamut Mapping Playground" ;
155
136
}
137
+ } ,
138
+
139
+ isCustomElement ( el ) {
140
+ return el . tagName . toLowerCase ( ) !== "css-color" ;
141
+ }
142
+ } ) . mount ( document . body ) ;
156
143
157
- return delta ;
158
- } )
159
- return deltas ;
160
- }
144
+ globalThis . app = app ;
0 commit comments