{"id":1236,"date":"2023-04-09T19:05:06","date_gmt":"2023-04-09T16:05:06","guid":{"rendered":"https:\/\/notes.profidev.online\/?p=1236"},"modified":"2023-04-09T19:05:09","modified_gmt":"2023-04-09T16:05:09","slug":"colour-palette","status":"publish","type":"post","link":"https:\/\/notes.profidev.online\/ru\/other\/1236\/","title":{"rendered":"Colour palette"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-4-3 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe title=\"Colour palette\" width=\"640\" height=\"480\" src=\"https:\/\/www.youtube.com\/embed\/SmJRPeSN7pM?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;htmlmixed&quot;,&quot;mime&quot;:&quot;text\/html&quot;,&quot;theme&quot;:&quot;cobalt&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:true,&quot;readOnly&quot;:false,&quot;fileName&quot;:&quot;&quot;,&quot;TrpContentRestriction&quot;:{&quot;restriction_type&quot;:&quot;exclude&quot;,&quot;selected_languages&quot;:[],&quot;panel_open&quot;:true},&quot;language&quot;:&quot;HTML&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;html&quot;}\">  &lt;main v-cloak&gt;\n    &lt;div class=&quot;tools&quot;&gt;\n      &lt;div&gt;\n        &lt;input type=&quot;color&quot; v-model=&quot;color1&quot; \/&gt;\n        &lt;input type=&quot;text&quot; v-model=&quot;color1&quot; \/&gt;\n      &lt;\/div&gt;\n      &lt;div&gt;\n        &lt;div class=&quot;vertical-range&quot;&gt;&lt;input type=&quot;range&quot; :min=&quot;min&quot; :max=&quot;max&quot; v-model=&quot;steps&quot; \/&gt;&lt;\/div&gt;\n        &lt;div class=&quot;steps&quot;&gt;{{visualSteps}} {{visualStepsLabel}}&lt;\/div&gt;\n      &lt;\/div&gt;\n      &lt;div&gt;\n        &lt;input type=&quot;color&quot; v-model=&quot;color2&quot; \/&gt;\n        &lt;input type=&quot;text&quot; v-model=&quot;color2&quot; \/&gt;\n      &lt;\/div&gt;\n    &lt;\/div&gt;\n    &lt;div class=&quot;colors&quot;&gt;\n      &lt;div class=&quot;color&quot; v-for=&quot;color in colors&quot; :style=&quot;setStyles(color)&quot;&gt;&amp;nbsp;{{colorName(color)}}&lt;\/div&gt;\n    &lt;\/div&gt;\n  &lt;\/main&gt;\n\n  &lt;script src=&quot;https:\/\/unpkg.com\/vue@2&quot;&gt;&lt;\/script&gt;<\/pre><\/div>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;css&quot;,&quot;mime&quot;:&quot;text\/css&quot;,&quot;theme&quot;:&quot;cobalt&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:true,&quot;readOnly&quot;:false,&quot;fileName&quot;:&quot;&quot;,&quot;TrpContentRestriction&quot;:{&quot;restriction_type&quot;:&quot;exclude&quot;,&quot;selected_languages&quot;:[],&quot;panel_open&quot;:true},&quot;language&quot;:&quot;CSS&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;css&quot;}\">@import url(&quot;https:\/\/fonts.googleapis.com\/css?family=Work+Sans:300&quot;);\n:root {\n  --fg: #fff;\n  --bg: #343338;\n}\n\n[v-cloak] {\n  display: none;\n}\n\n.tools {\n  flex: none;\n  padding: 2rem;\n  color: #fff;\n}\n.tools div {\n  display: flex;\n  position: relative;\n}\n.tools div + div {\n  margin-top: 0.5em;\n}\n.tools .steps {\n  position: absolute;\n  top: 50%;\n  left: 15vh;\n  transform: translate(25%, -50%);\n  padding: 0;\n  margin: 0;\n}\n\n.colors {\n  flex: 1;\n  display: flex;\n  flex-direction: column;\n  font-size: 0.85em;\n  height: 100vh;\n  overflow: auto;\n}\n.colors .color {\n  flex: 1;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  padding: 0 2rem;\n  transition: 300ms linear;\n}\n\n.vertical-range {\n  display: flex;\n  align-items: center;\n  width: 30vh;\n  height: 30vh;\n  transform: rotate(-90deg);\n}\n\ninput {\n  margin: 0;\n  padding: 0 0.5em;\n  font-size: inherit;\n  font-family: inherit;\n  border: none;\n  width: 7em;\n  outline: none;\n  border-radius: 0 1em 1em 0;\n  background: var(--fg);\n  color: var(--bg);\n  flex: 1;\n}\ninput[type=color] {\n  padding: 0;\n  width: 2em;\n  height: 2em;\n  border-radius: 1em 0 0 1em;\n}\ninput[type=color]::-moz-color-swatch {\n  border: none;\n  border-radius: 1em;\n  transform: scale(0.75);\n}\ninput[type=color]::-webkit-color-swatch {\n  border: none;\n  border-radius: 1em;\n}\ninput[type=color]::-webkit-color-swatch-wrapper {\n  padding: 0.25em;\n  border-radius: 1em;\n}\ninput[type=range] {\n  -webkit-appearance: none;\n     -moz-appearance: none;\n          appearance: none;\n  outline: none;\n  display: inline-block;\n  padding: 0;\n  margin: 0;\n  border: 0;\n  width: 100%;\n  height: 0.25em;\n  border-radius: 1em;\n  cursor: pointer;\n  font-size: inherit;\n  background: var(--fg);\n}\ninput[type=range]::-moz-range-track {\n  -moz-appearance: none;\n       appearance: none;\n  background: var(--fg);\n  outline: none;\n}\ninput[type=range]::-moz-focus-outer {\n  border: 0;\n}\ninput[type=range]::-moz-range-thumb {\n  -moz-appearance: none;\n       appearance: none;\n  width: 1em;\n  height: 1em;\n  border: none;\n  border-radius: 1em;\n  box-shadow: 0 0 0 0.3em var(--bg);\n  background: var(--fg);\n  transform: scale(1);\n  -moz-transition: transform 0.3s ease-out;\n  transition: transform 0.3s ease-out;\n}\ninput[type=range]::-moz-range-thumb:focus, input[type=range]::-moz-range-thumb:active {\n  -moz-appearance: none;\n       appearance: none;\n  transform: scale(0.85);\n}\ninput[type=range]::-webkit-slider-thumb {\n  -webkit-appearance: none;\n          appearance: none;\n  width: 1em;\n  height: 1em;\n  border: none;\n  border-radius: 1em;\n  box-shadow: 0 0 0 0.3em var(--bg);\n  background: var(--fg);\n  transform: scale(1);\n  -webkit-transition: transform 0.3s ease-out;\n  transition: transform 0.3s ease-out;\n}\ninput[type=range]::-webkit-slider-thumb:focus, input[type=range]::-webkit-slider-thumb:active {\n  -webkit-appearance: none;\n          appearance: none;\n  transform: scale(0.85);\n}\n\n*, *::before, *::after {\n  box-sizing: border-box;\n}\n\nbody {\n  margin: 0;\n  min-height: 100vh;\n  display: flex;\n  background: var(--bg);\n  font-family: &quot;Work Sans&quot;, sans-serif;\n}\n\nmain {\n  flex: 1;\n  display: flex;\n  font-size: calc(1em + 1vmin);\n}\n\n@supports (-webkit-backdrop-filter: blur(2em)) {\n  input[type=color] {\n    display: none;\n  }\n\n  input {\n    border-radius: 1em;\n    padding: 0.25em 0.5em;\n    width: 9em;\n  }\n}<\/pre><\/div>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;javascript&quot;,&quot;mime&quot;:&quot;text\/javascript&quot;,&quot;theme&quot;:&quot;cobalt&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:true,&quot;readOnly&quot;:false,&quot;fileName&quot;:&quot;&quot;,&quot;TrpContentRestriction&quot;:{&quot;restriction_type&quot;:&quot;exclude&quot;,&quot;selected_languages&quot;:[],&quot;panel_open&quot;:true},&quot;language&quot;:&quot;JavaScript&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;js&quot;}\">const vueMixinColorFunctions = {\n  created() {\n    \/\/ console.log('color mixin called')\n  },\n  methods: {\n    randomHex() {\n      return '#' + ( '00' + Math.floor( Math.random() * 16777216 ).toString(16) ).substr(-6)\n    },\n    hexArray(hex) {\n      return \/^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$\/i.exec(hex)\n    },\n    rgbObjectFromHex(hex) {\n      const result = this.hexArray(hex)\n      return result ? {\n          r: parseInt(result[1], 16),\n          g: parseInt(result[2], 16),\n          b: parseInt(result[3], 16),\n      } : null;\n    },\n    rgbArrayFromHex(hex) {\n      const rgb = this.rgbObjectFromHex(hex)\n      return [rgb.r, rgb.g, rgb.b]\n    },\n    hslObjectFromHex(hex) {\n      const hsl = {}\n      const rgb = this.rgbObjectFromHex(hex)\n\n      rgb.r \/= 255, rgb.g \/= 255, rgb.b \/= 255\n      let max = Math.max(rgb.r, rgb.g, rgb.b)\n      let min = Math.min(rgb.r, rgb.g, rgb.b)\n      \n      hsl.l = (max + min) \/ 2\n\n      if ( max == min ) {\n        hsl.h = hsl.s = 0 \/\/ achromatic\n      } else {\n        let d = max - min\n        \n        hsl.s = hsl.l &gt; 0.5 ? (d \/ (2 - max - min)) : (d \/ (max + min))\n\n        switch(max) {\n          case rgb.r: \n            hsl.h = (rgb.g - rgb.b) \/ d + (rgb.g &lt; rgb.b ? 6 : 0)\n            break\n          case rgb.g: \n            hsl.h = (rgb.b - rgb.r) \/ d + 2\n            break\n          case rgb.b:\n            hsl.h = (rgb.r - rgb.g) \/ d + 4\n            break\n        }\n        \n        hsl.h \/= 6;\n      }\n      \n      return {\n        h: Math.round(hsl.h * 360),\n        s: Math.round(hsl.s * 100),\n        l: Math.round(hsl.l * 100),\n      }\n    },\n    hslArrayFromHex(hex) {\n      const hsl = this.hslObjectFromHex(hex)\n      return [hsl.h, hsl.s, hsl.l]\n    },\n    hexToRgb(hex) {\n      const rgb = this.rgbObjectFromHex(hex)\n      return `rgb(${rgb.r},${rgb.g},${rgb.b})`\n    },\n    hexToRgbArray(hex) {\n      const rgb = this.rgbObjectFromHex(hex)\n      return `${rgb.r}, ${rgb.g}, ${rgb.b}`\n    },\n    hexToHsl(hex) {\n      const hsl = this.hslObjectFromHex(hex)\n      return `hsl(${hsl.h},${hsl.s}%,${hsl.l}%)`\n    },\n    rgbChannelToHex(channel) {\n      return channel.toString(16).padStart(2, '0');\n    },\n    rgbToHex(r, g, b) {\n      return &quot;#&quot; + [r,g,b].map(x=&gt;Math.round(x).toString(16).padStart(2,0) ).join('');\n    },\n    rgbArrayToHex (color) {\n      return this.rgbToHex(color[0], color[1], color[2]) \n    },\n    hslToRgbObject(h, s, l) {\n      let r, g, b;\n\n      if(s == 0){\n        r = g = b = l; \/\/ achromatic\n      } else {\n        const hue2rgb = function hue2rgb(p, q, t) {\n          if(t &lt; 0) t += 1;\n          if(t &gt; 1) t -= 1;\n          if(t &lt; 1\/6) return p + (q - p) * 6 * t;\n          if(t &lt; 1\/2) return q;\n          if(t &lt; 2\/3) return p + (q - p) * (2\/3 - t) * 6;\n          \n          return p;\n        }\n\n        const q = l &lt; 0.5 ? l * (1 + s) : l + s - l * s;\n        const p = 2 * l - q;\n\n        \n        r = hue2rgb(p, q, h + 1\/3);\n        g = hue2rgb(p, q, h);\n        b = hue2rgb(p, q, h - 1\/3);\n      }\n\n      console.log(r, g, b);\n\n      return {\n        r: Math.round(r * 255),\n        g: Math.round(g * 255),\n        b: Math.round(b * 255)\n      }\n    },\n    hslToRgb(h, s, l) {\n      let a = s*Math.min(l,1-l);\n      let f = (n,k=(n+h\/30)%12) =&gt; l - a*Math.max(Math.min(k-3,9-k,1),-1);\n      return [f(0),f(8),f(4)];\n    },\n    hslToHex(h, s, l) {\n      l \/= 100;\n      \n      const a = s * Math.min(l, 1 - l) \/ 100;\n      \n      const hex = n =&gt; {\n        const k = (n + h \/ 30) % 12;\n        const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);\n        \n        return Math.round(255 * color).toString(16).padStart(2, '0');\n      }\n      \n      return `#${hex(0)}${hex(8)}${hex(4)}`;\n    },\n    brightness(hex) {\n      const rgb = this.rgbObjectFromHex(hex)\n      return (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) \/ 1000\n    },\n    foregroundAdjust(hex, test, lightHex, darkHex) {\n      test = test || 154\n      lightHex = lightHex || '#fff'\n      darkHex = darkHex || '#000'\n      return this.brightness(hex) &lt; test ? lightHex : darkHex\n    },\n    interpolateColor(color1, color2, factor) {\n      if (arguments.length &lt; 3) { \n        factor = 0.5\n      }\n      const result = color1.slice()\n      \n      for (var i = 0; i &lt; 3; i++) {\n        result[i] = Math.round(result[i] + factor * (color2[i] - color1[i]))\n      }\n      return result\n    },\n    interpolateColors(color1, color2, steps) {\n      let stepFactor = 1 \/ (steps - 1)\n      let interpolatedColorArray = []\n\n      color1 = this.rgbArrayFromHex(color1).map(Number)\n      color2 = this.rgbArrayFromHex(color2).map(Number)\n\n      for (var i = 0; i &lt; steps; i++) {\n        interpolatedColorArray.push(this.interpolateColor(color1, color2, stepFactor * i))\n      }\n\n      return interpolatedColorArray\n    }\n  },\n}\n\nlet vm = new Vue({\n  el: 'main',\n  mixins: [vueMixinColorFunctions],\n  data: {\n    min: 3,\n    max: 27,\n    delta: 10,\n    steps: 11,\n    color1: '#0ebeff',\n    color2: '#ff42b3',\n  },\n  computed: {\n    colors () {\n      return this.interpolateColors(this.color1, this.color2, this.steps)\n    },\n    visualSteps () {\n      return (this.steps - 2)\n    },\n    visualStepsLabel () {\n      return (this.visualSteps === 1 ? 'step' : 'steps')\n    },\n  },\n  methods: {\n    adjust (color) {\n      const hex = this.rgbToHex(color[0], color[1], color[2])\n      return this.foregroundAdjust(hex)\n    },\n    setStyles(color) {\n      return `background: rgb(${color}); color: ${this.adjust(color)}`\n    },\n    colorName (color) {\n      return this.rgbArrayToHex(color)\n    },\n  }\n})<\/pre><\/div>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":1237,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[67],"tags":[],"class_list":["post-1236","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-other"],"_links":{"self":[{"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/posts\/1236","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/comments?post=1236"}],"version-history":[{"count":1,"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/posts\/1236\/revisions"}],"predecessor-version":[{"id":1238,"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/posts\/1236\/revisions\/1238"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/media\/1237"}],"wp:attachment":[{"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/media?parent=1236"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/categories?post=1236"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/tags?post=1236"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}