diff --git a/demo/index.html b/demo/index.html index 19cf421..7c4ee72 100644 --- a/demo/index.html +++ b/demo/index.html @@ -12,6 +12,7 @@ + @@ -19,12 +20,15 @@ - + \ No newline at end of file diff --git a/demo/src/color-thief.mjs b/demo/src/color-thief.mjs new file mode 100644 index 0000000..2e7cf26 --- /dev/null +++ b/demo/src/color-thief.mjs @@ -0,0 +1 @@ +if(!t)var t={map:function(t,r){var n={};return r?t.map(function(t,o){return n.index=o,r.call(n,t)}):t.slice()},naturalOrder:function(t,r){return tr?1:0},sum:function(t,r){var n={};return t.reduce(r?function(t,o,e){return n.index=e,t+r.call(n,o)}:function(t,r){return t+r},0)},max:function(r,n){return Math.max.apply(null,n?t.map(r,n):r)}};var r=function(){var r=5,n=8-r,o=1e3;function e(t,n,o){return(t<<2*r)+(n<h/2){for(e=n.copy(),u=n.copy(),a=(r=i-n[c])<=(o=n[f]-i)?Math.min(n[f]-1,~~(i+o/2)):Math.max(n[c],~~(i-1-r/2));!v[a];)a++;for(s=l[a];!s&&v[a-1];)s=l[--a];return e[f]=a,u[c]=e[f]+1,[e,u]}}(a==o?"r":a==u?"g":"b")}}return a.prototype={volume:function(t){var r=this;return r._volume&&!t||(r._volume=(r.r2-r.r1+1)*(r.g2-r.g1+1)*(r.b2-r.b1+1)),r._volume},count:function(t){var r=this,n=r.histo;if(!r._count_set||t){var o,u,a,i=0;for(o=r.r1;o<=r.r2;o++)for(u=r.g1;u<=r.g2;u++)for(a=r.b1;a<=r.b2;a++)i+=n[e(o,u,a)]||0;r._count=i,r._count_set=!0}return r._count},copy:function(){var t=this;return new a(t.r1,t.r2,t.g1,t.g2,t.b1,t.b2,t.histo)},avg:function(t){var n=this,o=n.histo;if(!n._avg||t){var u,a,i,c,f=0,s=1<<8-r,h=0,v=0,l=0;for(a=n.r1;a<=n.r2;a++)for(i=n.g1;i<=n.g2;i++)for(c=n.b1;c<=n.b2;c++)f+=u=o[e(a,i,c)]||0,h+=u*(a+.5)*s,v+=u*(i+.5)*s,l+=u*(c+.5)*s;n._avg=f?[~~(h/f),~~(v/f),~~(l/f)]:[~~(s*(n.r1+n.r2+1)/2),~~(s*(n.g1+n.g2+1)/2),~~(s*(n.b1+n.b2+1)/2)]}return n._avg},contains:function(t){var r=this,o=t[0]>>n;return gval=t[1]>>n,bval=t[2]>>n,o>=r.r1&&o<=r.r2&&gval>=r.g1&&gval<=r.g2&&bval>=r.b1&&bval<=r.b2}},i.prototype={push:function(t){this.vboxes.push({vbox:t,color:t.avg()})},palette:function(){return this.vboxes.map(function(t){return t.color})},size:function(){return this.vboxes.size()},map:function(t){for(var r=this.vboxes,n=0;n251&&e[1]>251&&e[2]>251&&(r[o].color=[255,255,255])}},{quantize:function(f,s){if(!f.length||s<2||s>256)return!1;var h=function(t){var o,u=new Array(1<<3*r);return t.forEach(function(t){o=e(t[0]>>n,t[1]>>n,t[2]>>n),u[o]=(u[o]||0)+1}),u}(f);h.forEach(function(){});var v=function(t,r){var o,e,u,i=1e6,c=0,f=1e6,s=0,h=1e6,v=0;return t.forEach(function(t){(o=t[0]>>n)c&&(c=o),(e=t[1]>>n)s&&(s=e),(u=t[2]>>n)v&&(v=u)}),new a(i,c,f,s,h,v,r)}(f,h),l=new u(function(r,n){return t.naturalOrder(r.count(),n.count())});function g(t,r){for(var n,e=t.size(),u=0;u=r)return;if(u++>o)return;if((n=t.pop()).count()){var a=c(h,n),i=a[0],f=a[1];if(!i)return;t.push(i),f&&(t.push(f),e++)}else t.push(n),u++}}l.push(v),g(l,.75*s);for(var p=new u(function(r,n){return t.naturalOrder(r.count()*r.volume(),n.count()*n.volume())});l.size();)p.push(l.pop());g(p,s);for(var b=new i;p.size();)b.push(p.pop());return b}}}().quantize,n=function(t){this.canvas=document.createElement("canvas"),this.context=this.canvas.getContext("2d"),this.width=this.canvas.width=t.naturalWidth,this.height=this.canvas.height=t.naturalHeight,this.context.drawImage(t,0,0,this.width,this.height)};n.prototype.getImageData=function(){return this.context.getImageData(0,0,this.width,this.height)};var o=function(){};o.prototype.getColor=function(t,r){return void 0===r&&(r=10),this.getPalette(t,5,r)[0]},o.prototype.getPalette=function(t,o,e){var u=function(t){var r=t.colorCount,n=t.quality;if(void 0!==r&&Number.isInteger(r)){if(1===r)throw new Error("colorCount should be between 2 and 20. To get one color, call getColor() instead of getPalette()");r=Math.max(r,2),r=Math.min(r,20)}else r=10;return(void 0===n||!Number.isInteger(n)||n<1)&&(n=10),{colorCount:r,quality:n}}({colorCount:o,quality:e}),a=new n(t),i=function(t,r,n){for(var o,e,u,a,i,c=t,f=[],s=0;s=125)&&(e>250&&u>250&&a>250||f.push([e,u,a]));return f}(a.getImageData().data,a.width*a.height,u.quality),c=r(i,u.colorCount);return c?c.palette():null},o.prototype.getColorFromUrl=function(t,r,n){var o=this,e=document.createElement("img");e.addEventListener("load",function(){var u=o.getPalette(e,5,n);r(u[0],t)}),e.src=t},o.prototype.getImageData=function(t,r){var n=new XMLHttpRequest;n.open("GET",t,!0),n.responseType="arraybuffer",n.onload=function(){if(200==this.status){var t=new Uint8Array(this.response);i=t.length;for(var n=new Array(i),o=0;o { + const elem = document.createElement('div'); + elem.className = className; + return elem; +}; + +const colorBlock = (palette: Scheme): HTMLElement => { + const block = div(`palette-block ${palette.theme}`); + block.style.backgroundColor = palette.background; + + const colors = div(`colors col-${palette.colors.length}`); + palette.colors.forEach((color) => { + const colDiv = div('color'); + colDiv.style.backgroundColor = color; + colDiv.style.border = `${Math.round(Math.random() * 8)}px solid ${ + palette.stroke + }`; + colors.appendChild(colDiv); + }); + const meta = div('palette-meta'); + meta.innerHTML = ` +

${palette.meta.artist}

+

${palette.meta.title}

+ `; + + block.appendChild(colors); + block.appendChild(meta); + block.addEventListener('click', function () { + navigator.clipboard.writeText(JSON.stringify(palette)); + }); + return block; +}; + +export { div, colorBlock }; diff --git a/demo/src/index.ts b/demo/src/index.ts index e3e9638..0618987 100644 --- a/demo/src/index.ts +++ b/demo/src/index.ts @@ -1,65 +1,32 @@ import { Scheme } from './../../src/index'; import { palettes, getPalette } from '../../src/index'; - -const div = (className: string): HTMLElement => { - const elem = document.createElement('div'); - elem.className = className; - return elem; -}; +import { div, colorBlock } from './colorBlock'; +import { sampler } from './sampler'; const app = document.getElementById('app'), - form = document.createElement('form'), - input = document.createElement('input'), - paletteGrid = div('palette-grid'); - -const colorBlock = (palette: Scheme): HTMLElement => { - const block = div(`palette-block ${palette.theme}`); - block.style.backgroundColor = palette.background; - - const colors = div(`colors col-${palette.colors.length}`); - palette.colors.forEach((color) => { - const colDiv = div('color'); - colDiv.style.backgroundColor = color; - colDiv.style.border = `${Math.round(Math.random() * 8)}px solid ${ - palette.stroke - }`; - colors.appendChild(colDiv); - }); - const meta = div('palette-meta'); - meta.innerHTML = ` -

${palette.meta.artist}

-

${palette.meta.title}

- `; + form = document.createElement('form'), + inputSearch = document.createElement('input'), + paletteGrid = div('palette-grid'); - block.appendChild(colors); - block.appendChild(meta); - block.addEventListener('click', function () { - navigator.clipboard.writeText(JSON.stringify(palette)); +const filteredPalette = (input: string) => { + if (input == '') return palettes; + const reg = new RegExp(input.toLowerCase()); + return palettes.filter(function (p: Scheme) { + if (p.meta.artist.toLowerCase().match(reg)) return p; }); - return block; }; -const filteredPalette = (input: string) => { - if (input == '') return palettes - const reg = new RegExp(input.toLowerCase()) - return palettes.filter(function(p: Scheme) { - if (p.meta.artist.toLowerCase().match(reg)) return p - }) -} - if (app !== null) { - form.autocomplete = 'off' - form.appendChild(input) - app.appendChild(form) - app.appendChild(paletteGrid) + form.autocomplete = 'off'; + form.appendChild(inputSearch); + app.appendChild(form); + app.appendChild(paletteGrid); + app.appendChild(sampler.ui()); palettes.forEach((palette) => paletteGrid.appendChild(colorBlock(palette))); - input.placeholder = 'type an artist name' - input.onkeyup = function(e: KeyboardEvent): void { - paletteGrid.innerHTML = '' - const results = filteredPalette((e.target as HTMLInputElement).value) - results.forEach((palette) => paletteGrid.appendChild(colorBlock(palette))); - } + inputSearch.placeholder = 'type an artist name'; + inputSearch.onkeyup = function (e: KeyboardEvent): void { + paletteGrid.innerHTML = ''; + const results = filteredPalette((e.target as HTMLInputElement).value); + results.forEach((palette) => paletteGrid.appendChild(colorBlock(palette))); + }; } diff --git a/demo/src/sampler.ts b/demo/src/sampler.ts new file mode 100644 index 0000000..b4b1519 --- /dev/null +++ b/demo/src/sampler.ts @@ -0,0 +1,78 @@ +import ColorThief from './color-thief.mjs'; +import { Scheme } from './../../src/index'; +import { div, colorBlock } from './colorBlock'; + +type TGenericEvent = Event & { target: T }; + +const rgbToHex = (rgb: number[]): string => + '#' + + rgb + .map((x) => { + const hex = x.toString(16); + return hex.length === 1 ? '0' + hex : hex; + }) + .join(''); + +const parsePalette = (colArray: number[][], filename: string): Scheme => { + const colHex = colArray.map((col) => rgbToHex(col)); + const background = colHex[0]; + const stroke = colHex[colHex.length - 1]; + const colors = colHex.splice(1, colHex.length - 3); + return { + meta: { + title: filename, + artist: '', + year: '', + techniques: '', + }, + background, + colors, + stroke, + temp: 'neutral', + theme: 'bright', + } as Scheme; +}; + +const sampler = { + colorThief: new ColorThief(), + img: document.createElement('img'), + inputFile: document.createElement('input'), + paletteBlock: div('palette-out'), + codeOut: document.createElement('pre'), + createPalette: (filename: string) => { + const sampledColor = sampler.colorThief.getPalette(sampler.img); + const palette = parsePalette(sampledColor, filename); + sampler.paletteBlock.innerHTML = ''; + sampler.paletteBlock.appendChild(colorBlock(palette)); + sampler.codeOut.innerHTML = JSON.stringify(palette); + }, + ui(): HTMLElement { + const createPaletteBlock = document.createElement('div'); + createPaletteBlock.classList.add('create-palette'); + createPaletteBlock.innerHTML = '

Sample a palette from an image

'; + sampler.inputFile.type = 'file'; + createPaletteBlock.appendChild(sampler.img); + createPaletteBlock.appendChild(sampler.inputFile); + createPaletteBlock.appendChild(sampler.paletteBlock); + createPaletteBlock.appendChild(sampler.codeOut); + + sampler.inputFile.addEventListener('change', (e: Event) => { + if (e.target !== null) { + const files = (e.target).files, + reader = new FileReader(); + console.log(files); + let url = window.URL.createObjectURL(files[0]); + sampler.img.src = url; + + if (sampler.img.complete) { + sampler.createPalette(files[0].name); + } else { + sampler.img.onload = () => sampler.createPalette(files[0].name); + } + } + }); + return createPaletteBlock; + }, +}; + +export { sampler }; diff --git a/demo/style.css b/demo/style.css index 647cb9b..20c2f9e 100644 --- a/demo/style.css +++ b/demo/style.css @@ -12,33 +12,33 @@ body, } body { - background: linear-gradient(to bottom, #ffffff, #d9d6d6); - min-height: 100vh; + background: linear-gradient(to bottom, #ffffff, #d9d6d6); + min-height: 100vh; } -#app{ - width: 84%; - margin: 1em 8%; +#app { + width: 84%; + margin: 1em 8%; } #app form, footer { - display: flex; - flex-flow: row nowrap; - width: 100%; - justify-content: space-evenly; + display: flex; + flex-flow: row nowrap; + width: 100%; + justify-content: space-evenly; } #app form input, footer p { - text-align: center; + text-align: center; } #app form input { - font-size: 1.4em; - padding: 0.4em; - margin: 1em 0 2em; - border: 2px solid #ccc; + font-size: 1.4em; + padding: 0.4em; + margin: 1em 0 2em; + border: 2px solid #ccc; } #app .palette-grid { @@ -47,6 +47,42 @@ footer p { grid-gap: 2em; } +#app .create-palette { + padding: 1em; + width: 600px; + display: flex; + flex-flow: column; + align-items: center; + margin: 2em auto; + background: #fefefe; +} + +#app .create-palette img, +#app .create-palette pre, +#app .create-palette .palette-out { + position: relative; + width: 90%; + margin: 0 5%; + height: auto; +} + +#app .create-palette input[type='file'] { + margin: 1em 0; + padding: 0.4em; + border: none; + background: linear-gradient(to bottom, #333, #111); + color: #fff; +} + +#app .create-palette pre { + margin-top: 2em; + word-break: break-word; + white-space: break-spaces; + border: 1px solid #ccc; + background: #f2f2f2; + border-radius: 4px; +} + .palette-block { display: flex; text-align: center;