|
1 | | -val plotW = 800 |
| 1 | +// generate color data using templates/scala-diagram-input.template |
| 2 | +val bg = new Color("bg", "103c48", 23) |
| 3 | +val fg = new Color("fg", "adbcbc", 75) |
| 4 | +val bgColors = List(bg, fg) |
| 5 | +val fgColors = List( |
| 6 | + new Color("bg_0", "103c48", 23), |
| 7 | + new Color("bg_1", "174956", 28), |
| 8 | + new Color("bg_2", "325b66", 36), |
| 9 | + new Color("red", "fa5750", 60), |
| 10 | + new Color("orange", "ed8649", 67), |
| 11 | + new Color("yellow", "dbb32d", 75), |
| 12 | + new Color("green", "75b938", 69), |
| 13 | + new Color("cyan", "41c7b9", 73), |
| 14 | + new Color("blue", "4695f7", 60), |
| 15 | + new Color("violet", "af88eb", 64), |
| 16 | + new Color("magenta", "f275be", 66), |
| 17 | + new Color("dim_0", "72898f", 56), |
| 18 | + new Color("fg_0", "adbcbc", 75), |
| 19 | + new Color("fg_1", "cad8d9", 85) |
| 20 | +) |
| 21 | + |
| 22 | +val plotW = 1000 |
2 | 23 | val plotH = 600 |
3 | | -val squareSize = 44 |
| 24 | +val squareSize = 48 |
4 | 25 | val squareHalf = squareSize/2.0 |
5 | | -val squareBorder = 3 |
| 26 | +val lineWidth = 3 |
| 27 | +val margin = 125 |
| 28 | +val imgW = plotW + margin + lineWidth // for rightmost border |
| 29 | +val imgH = plotH + margin |
| 30 | + |
| 31 | +// some programs (e.g. Gimp) don't handle text alignment correctly |
| 32 | +val adjustAlignment = true |
| 33 | +val adjX = if (adjustAlignment) lineWidth.toString else "0" |
| 34 | +val adjY = if (adjustAlignment) squareHalf*0.4 else 0 |
6 | 35 |
|
7 | 36 | class Color(val name: String, val hexString: String, val luminance: Int) |
8 | 37 |
|
| 38 | +// choose either fg or bg, depending on provided luminance |
| 39 | +def pickContrastingShade(luminance: Int) = { |
| 40 | + if (luminance > (bg.luminance + fg.luminance) / 2) |
| 41 | + "#"+bg.hexString |
| 42 | + else |
| 43 | + "#"+fg.hexString |
| 44 | +} |
| 45 | + |
9 | 46 | def genSvg(bgColors: List[Color], fgColors: List[Color]) = { |
10 | | - <svg |
11 | | - xmlns="http://www.w3.org/2000/svg" |
12 | | - xmlns:svg="http://www.w3.org/2000/svg" |
13 | | - width={plotW.toString} |
14 | | - height={plotH.toString} |
15 | | - version="1.1" |
16 | | - font-family="Signika, sans" |
17 | | - font-size={(squareHalf).toString+"px"}> |
18 | | - <style> |
| 47 | + <svg version="1.1" |
| 48 | + xmlns="http://www.w3.org/2000/svg" |
| 49 | + xmlns:svg="http://www.w3.org/2000/svg" |
| 50 | + width={imgW.toString} |
| 51 | + height={imgH.toString} |
| 52 | + font-family="Signika, sans" |
| 53 | + font-size={(0.65*squareSize).toString+"px"} > |
| 54 | + <style> |
19 | 55 | @font-face {{ |
20 | | - font-family: 'Signika'; |
21 | | - font-style: normal; |
22 | | - font-weight: 400; |
23 | | - src: local('Signika'), local('Signika-Regular'), url(https://fonts.gstatic.com/s/signika/v6/q41y_9MUP_N8ipOH4ORRvw.woff2) format('woff2'); |
24 | | - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000; |
| 56 | + font-family: 'Signika'; |
| 57 | + font-style: normal; |
| 58 | + font-weight: 400; |
| 59 | + src: local('Signika'), local('Signika-Regular'), |
| 60 | + url(https://fonts.gstatic.com/s/signika/v6/q41y_9MUP_N8ipOH4ORRvw.woff2) format('woff2'); |
| 61 | + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, |
| 62 | + U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000; |
25 | 63 | }} |
26 | 64 | @font-face {{ |
27 | | - font-family: 'Signika'; |
28 | | - font-style: normal; |
29 | | - font-weight: 700; |
30 | | - src: local('Signika-Bold'), url(https://fonts.gstatic.com/s/signika/v6/7M5kxD4eGxuhgFaIk95pBfk_vArhqVIZ0nv9q090hN8.woff2) format('woff2'); |
31 | | - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000; |
| 65 | + font-family: 'Signika'; |
| 66 | + font-style: normal; |
| 67 | + font-weight: 700; |
| 68 | + src: local('Signika-Bold'), |
| 69 | + url(https://fonts.gstatic.com/s/signika/v6/7M5kxD4eGxuhgFaIk95pBfk_vArhqVIZ0nv9q090hN8.woff2) format('woff2'); |
| 70 | + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, |
| 71 | + U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000; |
32 | 72 | }} |
33 | | - </style>{ |
34 | | - genBgColors(bgColors.sortBy(x => x.luminance)) |
35 | | - }{ |
36 | | - genFgColors(fgColors, bgColors.head) |
37 | | - }</svg> |
| 73 | + </style> |
| 74 | + { drawAxis() } |
| 75 | + <g transform={"translate("+margin+","+margin/2+")"} > |
| 76 | + <rect x={(-lineWidth/2.0).toString} y={(-lineWidth/2.0).toString} |
| 77 | + width={(plotW+lineWidth).toString} height={(plotH+lineWidth).toString} |
| 78 | + fill="#777" /> |
| 79 | + <rect x="0" y="0" width={plotW.toString} height={plotH.toString} fill="#000" /> |
| 80 | + { drawBackground(bgColors.sortBy(x => x.luminance)) } |
| 81 | + { drawSwatches(fgColors) } |
| 82 | + </g> |
| 83 | + </svg> |
38 | 84 | } |
39 | 85 |
|
40 | | -def genBgColors(colors: List[Color]) = { |
41 | | - <g transform={"translate(0,"+plotH.toString+") scale(1,-1)"}>{ |
42 | | - for {color <- new Color("#000000", "000000", 0)::colors} yield { |
43 | | - <rect |
44 | | - style={"fill:#"+color.hexString+";fill-opacity:1;stroke:none"} |
45 | | - width={ plotW.toString } |
46 | | - height={ plotH.toString } |
47 | | - x="0" |
48 | | - y={ (color.luminance*plotH/100.0).toString } /> |
49 | | - } |
50 | | - }</g> |
| 86 | +def drawAxis() = { |
| 87 | + val axisColor = "#777" |
| 88 | + val axisX = margin-squareSize |
| 89 | + val notchHalf = squareHalf/2.0 |
| 90 | + |
| 91 | + <defs> |
| 92 | + <marker id="arrowhead" markerWidth="10" markerHeight="10" refX="0" refY="3" orient="auto" markerUnits="strokeWidth"> |
| 93 | + <path d="M0,0 L0,6 L9,3 z" fill={axisColor} /> |
| 94 | + </marker> |
| 95 | + </defs> |
| 96 | + |
| 97 | + <g stroke={axisColor} stroke-width={lineWidth.toString} > |
| 98 | + <line x1={(axisX).toString} y1={(imgH-margin/4.0).toString} |
| 99 | + x2={(axisX).toString} y2={(margin/4.0).toString} |
| 100 | + marker-end="url(#arrowhead)" /> |
| 101 | + <line x1={(axisX-notchHalf).toString} y1={(margin/2.0).toString} |
| 102 | + x2={(axisX+notchHalf).toString} y2={(margin/2.0).toString} /> |
| 103 | + <line x1={(axisX-notchHalf).toString} y1={(imgH-margin/2.0).toString} |
| 104 | + x2={(axisX+notchHalf).toString} y2={(imgH-margin/2.0).toString} /> |
| 105 | + </g> |
| 106 | + |
| 107 | + <text x={(axisX-1.5*notchHalf).toString} y={(imgH-margin/2.0 + adjY).toString} |
| 108 | + text-anchor="end" dominant-baseline="central" |
| 109 | + fill={axisColor} > 0 </text> |
| 110 | + <text x={(axisX-1.5*notchHalf).toString} y={(margin/2.0 + adjY).toString} |
| 111 | + text-anchor="end" dominant-baseline="central" |
| 112 | + fill={axisColor} > 100 </text> |
| 113 | + <g transform={"translate("+(axisX-notchHalf)+","+imgH/2.0+")"} > |
| 114 | + <text x="0" y="0" |
| 115 | + text-anchor="middle" |
| 116 | + transform="rotate(-90)" |
| 117 | + fill={axisColor} > luminance </text> |
| 118 | + </g> |
51 | 119 | } |
52 | 120 |
|
53 | | -def genFgColors(colors: List[Color], bgColor: Color) = { |
| 121 | +def drawBackground(colors: List[Color]) = { |
| 122 | + // we want the circles to have the same area as the squares |
| 123 | + val radius = scala.math.sqrt(4/scala.math.Pi) * squareHalf |
| 124 | + for {color <- colors} yield { |
| 125 | + <rect x="0" y="0" |
| 126 | + width={ plotW.toString } |
| 127 | + height={(((100-color.luminance)/100.0)*plotH).toString} |
| 128 | + fill={"#"+color.hexString} /> |
| 129 | + <circle cx="0" cy={(((100-color.luminance)/100.0)*plotH).toString} |
| 130 | + r={radius.toString} |
| 131 | + fill={"#"+color.hexString} |
| 132 | + stroke="#777" |
| 133 | + stroke-width={lineWidth.toString} /> |
| 134 | + <text x={adjX} y={(((100-color.luminance)/100.0)*plotH + adjY).toString} |
| 135 | + fill={pickContrastingShade(color.luminance)} |
| 136 | + text-anchor="middle" dominant-baseline="central" > |
| 137 | + { color.luminance.toString } |
| 138 | + </text> |
| 139 | + <text x={(radius*1.3).toString} y={(((98-color.luminance)/100.0)*plotH).toString} |
| 140 | + fill={pickContrastingShade(color.luminance)} |
| 141 | + text-anchor="begin" > |
| 142 | + { color.name } |
| 143 | + </text> |
| 144 | + |
| 145 | + } |
| 146 | +} |
| 147 | + |
| 148 | +def drawSwatches(colors: List[Color]) = { |
54 | 149 | <g>{ |
55 | 150 | for {(color, i) <- colors.zipWithIndex} yield { |
56 | | - val xcenter = (i+1)*plotW/(colors.length+1) |
| 151 | + val xcenter = (i+1.7)*plotW/(colors.length+1.5) |
57 | 152 | val ycenter = color.luminance*plotH/100.0 |
58 | | - <g transform={"scale(1,-1) translate("+xcenter.toString+","+ycenter.toString+") scale(1,-1) translate(0, "+plotH.toString+")"}> |
59 | | - <!-- group is translated to the center of square with some flipping for easier translation --> |
60 | | - <g stroke={"#"+bgColor.hexString} stroke-width={squareBorder.toString}> |
61 | | - <rect |
62 | | - fill={"#"+color.hexString} |
63 | | - stroke={"#"+bgColor.hexString} |
64 | | - stroke-width={squareBorder.toString} |
65 | | - width={squareSize.toString} |
66 | | - height={squareSize.toString} |
67 | | - x={(-squareHalf).toString} |
68 | | - y={(-squareHalf).toString}/> |
69 | | - <line x1={(-squareHalf).toString} y1="0" x2={(squareBorder-squareHalf).toString} y2="0"/> |
70 | | - <line x1={squareHalf.toString} y1="0" x2={(squareHalf-squareBorder).toString} y2="0"/> |
| 153 | + |
| 154 | + <!-- group is translated to the center of square with some flipping for easier translation --> |
| 155 | + <g transform={"scale(1,-1)" + |
| 156 | + "translate("+xcenter.toString+","+ycenter.toString+")" + |
| 157 | + "scale(1,-1)" + |
| 158 | + "translate(0, "+plotH.toString+")"} > |
| 159 | + <g stroke={"#"+bg.hexString} stroke-width={lineWidth.toString} > |
| 160 | + <rect x={(-squareHalf).toString} |
| 161 | + y={(-squareHalf).toString} |
| 162 | + width={squareSize.toString} |
| 163 | + height={squareSize.toString} |
| 164 | + fill={"#"+color.hexString} |
| 165 | + stroke={"#"+bg.hexString} |
| 166 | + stroke-width={lineWidth.toString} /> |
71 | 167 | </g> |
72 | | - <text x="0" y="0" fill={"#"+bgColor.hexString} text-anchor="middle" dominant-baseline="central">{ |
73 | | - color.luminance.toString |
74 | | - }</text> |
75 | | - <text x={(-squareSize*0.8).toString} y="0" fill={"#"+color.hexString} text-anchor="end" dominant-baseline="central" font-weight="bold" font-size={(0.8*squareSize).toString} |
76 | | - transform={"rotate(-90)"}>{ |
77 | | - color.name |
78 | | - }</text> |
| 168 | + |
| 169 | + <text x={adjX} y={adjY.toString} |
| 170 | + fill={pickContrastingShade(color.luminance)} |
| 171 | + text-anchor="middle" dominant-baseline="central" > |
| 172 | + { color.luminance.toString } |
| 173 | + </text> |
| 174 | + |
| 175 | + <text x={(-squareSize*0.8).toString} y={adjY.toString} |
| 176 | + fill={"#"+color.hexString} |
| 177 | + text-anchor="end" |
| 178 | + dominant-baseline="central" |
| 179 | + font-weight="bold" |
| 180 | + transform={"rotate(-90)"} > |
| 181 | + { color.name } |
| 182 | + </text> |
79 | 183 | </g> |
80 | 184 | } |
81 | 185 | }</g> |
82 | 186 | } |
83 | 187 |
|
84 | 188 | println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>") |
85 | | -val bgColors = List( |
86 | | - new Color("bg_0", "103c48", 23), |
87 | | - new Color("fg_0", "adbcbc", 75) |
88 | | -) |
89 | | -val fgColors = List( |
90 | | - new Color("bg_1", "184956", 28), |
91 | | - new Color("bg_2", "2d5b69", 36), |
92 | | - new Color("dim_0", "72898f", 56), |
93 | | - new Color("fg_0", "adbcbc", 75), |
94 | | - new Color("fg_1", "cad8d9", 85), |
95 | | - new Color("red", "fa5750", 60), |
96 | | - new Color("green", "75b938", 69), |
97 | | - new Color("yellow", "dbb32d", 75), |
98 | | - new Color("blue", "4695f7", 60), |
99 | | - new Color("magenta", "f275be", 66), |
100 | | - new Color("cyan", "41c7b9", 73) |
101 | | -) |
| 189 | + |
102 | 190 | println(genSvg(bgColors, fgColors)) |
103 | 191 |
|
0 commit comments