<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Try-on</title>
    <script src="js/data.js"></script>
    <script src="js/Observer.js"></script>
    <script src="js/Store.js"></script>
    <script src="js/DOM.js"></script>
    <script src="js/colors.js"></script>
    <script src="js/Point.js"></script>
    <script src="js/kmean.js"></script>

    <style>
        a {
            color: #395772;
            text-decoration: none;
        }
    .cmp-collapse.collapsed .cmp-collapse-content {
        display: none;
    }
    .cmp-collapse-title:before {
        content: '▼';
        margin: 0 4px 0 0;
    }

    .cmp-collapse.collapsed .cmp-collapse-title:before {
        content: '▲';
    }

    .cmp-collapse-title {
        cursor: pointer;
        font-weight: bold;
        margin: 32px 0 0 0;
    }
    .cmp-collapse-content {
        padding-left: 16px;
    }
    .slider-background {
        background: #104361;
        height: 2px;
        position: absolute;
        left: 8px;
        top: 7px;
        right: 8px;
    }
    .slider {
        position: relative;
        height: 32px;
    }
    .sw_sm.matched {
        border: 1px solid #000;
    }
    .sw_sm {
        width: 10px;
        height: 10px;
        display: inline-block;
        margin: 1px;
        border: 1px solid #fff;
        padding: 1px;
    }
    .sw_sm div {
        width: 100%;
        height: 100%;
    }
    .slider-start {
        position: absolute;
        left:0;
    }
    .slider-start:before {
        content: '';
        height: 6px;
        top: 5px;
        left: 5px;
        position: absolute;
        background: #104361;
        width: 6px;
        border-radius: 50%;
        z-index: 2;
    }
    .slider-end {
        position: absolute;
        right:0;
    }
    .slider-end:before {
        content: '';
        height: 6px;
        top: 5px;
        right: 5px;
        position: absolute;
        background: #104361;
        width: 6px;
        border-radius: 50%;
        z-index: 2;
    }
    .slider-end__label {
        position: absolute;
        text-align: center;
        left: 0;
        font-family: Tahoma;
        top: -3px;
    }
    .slider-start__label {
        position: absolute;
        text-align: center;
        right: 4px;
        font-family: Tahoma;
        top: -3px;
    }

    .slider-drag {
        width: 12px;
        height: 12px;
        margin-left: 2px;
        top: 2px;
        border: 2px solid #104361;
        box-sizing: border-box;
        cursor: pointer;
        position: absolute;
        z-index: 1;
        border-radius: 50%;
        background: #fff;
    }
    .grhm {
        width: 50%;
        left:25%;
        position: relative;
    }
    .slider-zone {
        position: absolute;
        left: 8px;
        right: 8px;
        height: 8px;
        top: 4px;
    }
    .slider-hover-val {
        position: absolute;
        top: -28px;
        transform: translate(-40%);
        font-family: Tahoma;
    }
    #colorsCount {
        margin:32px
    }
    .colorSwatch {
        width: 32px;
        height: 32px;
        float: left;
        margin: 1px 1px 0 0;
        border: 1px solid #666;
        border-radius: 4px;
    }
    .colorSwatch.active:before {
        content: '✓';
        font-size: 24px;
        text-align: center;
        margin: auto;
        display: block;
        color: #fff;
        padding-top: 4px;
        text-shadow: #000 0px -2px 2px;
    }
    .colorSwatch.active {
        position: relative;
        margin: -4px;
        width: 41px;
        height: 41px;
        border-radius: 25px;
    }
    .vendor.disabled {
        color: #aaa
    }
</style>
</head>
<body>

<script>
  var Transform = ( function(){
    'use strict';

    var hookAndConvert = function( fn ){
      return function( hook, a ){
        var type = typeof hook;
        var notObject = type !== 'object';
        var isHook = !notObject && ( 'hook' in hook );
        if( isHook ){
          type = 'function';
          notObject = true;
        }
        if( notObject ){
          if( type === 'function' ){
            var last, val;
            if( isHook ){
              return {
                hook: function( draw ){
                  return hook.hook( function( arg ){
                    val = fn( arg, a );
                    if( last === val )
                      return;

                    return draw( last = val );
                  } );
                }
              };
            }else{
              return function( draw ){
                return hook( function( arg ){
                  val = fn( arg, a );
                  if( last === val )
                    return;

                  return draw( last = val );
                } );
              };
            }
          }
        }else{
          return hook;
        }
      }
    };
    var Transform = {
      toFixed: hookAndConvert( function( val, digits ){
        return ( val - 0 ).toFixed( digits );
      } )
    };

    return Transform;
  } )();
  window.T = Transform;
  const slice = [].slice;
  const Component = function( cfg ){

    var original = cfg;
    var _ctor = function( cfg, children ){
      if( !( this instanceof _ctor ) ){
        return new _ctor( cfg, children );
      }

      this.store = new Store();
      this._apply( cfg );
      arguments.length > 1 && this._children.call( this, slice.call( arguments, 1 ) );
      this.__un = new D.Unsubscribe();

      original.ctor && original.ctor.apply( this );
    };

    _ctor.prototype = Object.assign( Object.create( Component.prototype ), cfg );
    _ctor.constructor = _ctor;
    return _ctor;
  };

  Component.prototype = {
    prop: {},
    _children: function( children ){
      this.children = children;
    },
    _apply: function( cfg ){
      var prop = this.prop;
      for( var key in cfg ){
        var val = cfg[ key ];
        if( key in prop ){
          if( val instanceof Store.StoreBinding || val instanceof Store.HookPrototype ){
            this[ key ] = val;
          }else{
            this[ key ] = new Store.Value[ prop[ key ].type.name ]( val );
          }
        }else{
          this[ key ] = val;
        }
      }
      for( key in prop ){
        if( !( key in cfg ) ){
          var property = prop[ key ];

          if( !property.optional ){
            this[ key ] = new Store.Value[ property.type.name ]();
            if( property.default ){
              this[ key ].set( property.default );
            }
          }
        }
      }
    },
    '~destroy': function(){
      var pointer = this.dom.parentNode;
      if( !pointer ){
        pointer = this.dom;
      }
      var allHooked = [].slice.call( pointer.querySelectorAll( '[data-hooked]' ) );
      for( var i = 0, _i = allHooked.length; i < _i; i++ ){
        var un = allHooked[ i ].__un;
        if( !un )
          continue;

        var uns = allHooked[ i ].__un;
        for( var j = 0, _j = uns.length; j < _j; j++ ){
          var unSubscribe = uns[ j ];
          unSubscribe();
        }

        delete allHooked[ i ].__un;
      }

      if( this.dom.parentNode ){
        pointer.removeChild( this.dom );
      }

      this.dom = void 0;

      this.__un.un();

      for( var key in this )
        this.hasOwnProperty( key ) && delete this[ key ];
    },
    sub: function(){
      var un = this.store.sub.apply( this.store, arguments );
      this.__un.add( un );
    }
  };
  var Property = function( type ){
    this.name = type;
  };
  Property.prototype = {
    set: function( val ){
      return val;
    },
    get: function( val ){
      return val;
    },
    compare: function( val1, val2 ){
      return val1 === val2;
    }
  };
  Component.Property = {
    Any: new Property( 'Any' )
  };

  var Slider = new Component( {
    ctor: function( cfg ){
      Object.assign( this, cfg );

      this.createDOM();

      this.initBinding();

      this.initEvents();

      this.afterInit && this.afterInit();

    },
    prop: {
      from: { type: Number },
      to: { type: Number },
      value: { type: Number, default: 0 },
      step: { type: Number, optional: true },
    },
    createDOM: function(){
      this.dom = D.div( { cls: 'slider' },
        D.div( { cls: 'slider-background' } ),
        this.zoneEl = D.div( { cls: 'slider-zone' } ),
        D.div( { cls: 'slider-start' },
          D.div( { cls: 'slider-start__label' }, T.toFixed( this.from, 0 ) ),
        ),
        D.div( { cls: 'slider-end' },
          D.div( { cls: 'slider-end__label' }, T.toFixed( this.to, 0 ) )
        ),
        this.dragEl = D.div( { cls: 'slider-drag', style: { left: '0px' } } )
      );

      this._updateUI = this._updateUI.bind( this );

      this.afterDOM && this.afterDOM();
    },
    initEvents: function(){
      var _self = this;

      D.mouse.down( this.dom, function( e ){
        var pos = new Point( e.clientX, e.clientY );

        _self.getBound();
        _self.calculateValue( pos );
        _self.updateUI();

        var update = D.AnimationFrame( function( pos ){
          _self.calculateValue( pos );
          _self.updateUI();
        } );

        var un = D.mouse.move( document, function( e ){
          e.preventDefault();
          e.stopPropagation();

          pos.x = e.clientX;
          pos.y = e.clientY;

          update( pos );
        }, true );
        D.overlay.show();
        //un.add( D.mouse.up(_self.dom, un) );
        un.add( function(){
          D.overlay.hide();
        } );
        un.add( D.mouse.up( window, un ) );
      } );
    },
    getBound: function(){
      var bound = this.zoneEl.getBoundingClientRect();
      this.bound = {
        left: bound.left,
        top: bound.top,
        height: bound.height,
        width: bound.width
      };
    },
    calculateValue: function( pos ){
      var bound = this.bound;
      var val = Math.min( Math.max( 0, pos.x - bound.left ), bound.width );
      this.setValue( this.from.get() + ( val / bound.width * ( this.delta ) ) );
    },
    afterAddToDOM: function(){
      this.getBound();
      this.updateUI();
    },
    bound: null,
    _updateRequested: false,
    _updateUI: function(){
      this._updateRequested = false;
      this.dragEl.style.left = ( this.value.get() - this.from.get() ) / ( this.delta ) * this.bound.width + 'px';
    },
    updateUI: function(){
      if( this.bound ){
        if( !this._updateRequested ){
          this._updateRequested = true;
          requestAnimationFrame( this._updateUI )
        }
      }
    },
    initBinding: function(){
      var _self = this;

      this.sub( [ this.value, this.from, this.to ], function( val, from, to ){
        _self.delta = to - from;
        _self.setValue( val );
        _self.updateUI();
      } );

    },
    lastValue: null,
    setValue: function( val, silent ){
      var inVal = val;
      val = Math.min( this.to.get(), Math.max( this.from.get(), val ) );
      if( 'step' in this ){
        var step = this.step.get();
        val = Math.round( val / step ) * step;
      }
      if( val !== this.lastValue || inVal !== val ){
        this.lastValue = val;
        if( !silent ) this.value.set( val );
      }
    }
  } );
  var Radio = new Component( {
    ctor: function(){
      this.createDOM();
      this.initBinding();

      this.afterInit && this.afterInit();
    },
    prop: {
      value: { type: Component.Property.Any, default: false },
      group: { type: Component.Property.Any, default: false }
    },
    createDOM: function(){
      var val = this.value,
        group = this.group,
        el = this.dom = this.inputEl = D.h( 'input', {
          attr: { type: 'radio' },
          cls: 'picker-button__field',
          onchange: function(){
            if( el.checked ){
              group.set( val.get() )
            }
          }
        } );

      this.afterDOM && this.afterDOM();
    },
    initBinding: function(){
      var _self = this;

      this.sub( [ this.value, this.group ], function( val, group ){
        _self.inputEl.checked = val === group;
      } );
    }
  } );

  var Collapse = new Component({
    name: 'Collapse',
    ctor: function(cfg) {
      Object.assign(this, cfg);

      this.createDOM();


      this.afterInit && this.afterInit();
    },
    prop: {
      value: {type: Boolean, default: false},
      label: {type: String, default: 'Collapse'},
    },
    createDOM: function() {
      var val = this.value,
        el = this.dom = this.inputEl = D.h('div', {
            cls: D.cls('cmp-collapse', {
              collapsed: val
            })
          },
          D.div({cls: 'cmp-collapse-title', onclick: function(){ val.set(!val.get())}}, this.label),
          D.div({cls: 'cmp-collapse-content'}, this.children)
        );

      this.afterDOM && this.afterDOM();
    }
  });

</script>
<script src="js/prs.js"></script>

<base href="https://www.mirrormirror.love/">

<div id="tags" style="display: none"></div>
<div style="display:flex">
    <div style="width:320px; flex:none">
        <div id="cooltags"></div>
        <div id="colorsCount"></div>
        <div id="BrandCollapse"></div>

        <div id="yep"></div>
        <div style="clear:both"></div>
        <div id="yep2" style="padding-top: 32px;display: none"></div>
        <div style="clear:both"></div>

        <!-- style="display: none"-->
        <div id="yep3" style="padding-top: 32px"></div>
        <div style="clear:both"></div>
    </div>
    <div style="margin: 0 32px;width:100%">
        <div id="colorogrammaSwitches"></div>
        <canvas id="c0" width="580" height="580"></canvas>
        <div id="productList" style="display: flex;flex-wrap: wrap;"></div>
    </div>
</div>
<script>
  function matchingProductsFormat(p, index) {
    var product = p.product;

    // If the variants doesn't have Image src
    if (product.variants[index].featured_image == null) {
      product.variants[index].featured_image = {};
      product.variants[index].featured_image.src =
        "https://cdn.shopify.com/s/files/1/0275/8036/6900/files/2_Main_Vertical_Transparent.png?v=1575867010";
    }
    var out_put = "";
    out_put = `<div style="width:240px">
          <div class="grid-product__content">
            <a class="grid-product__link " href="/products/${product.handle}" target="_blank">
              <div class="grid-product__image-mask">
                <img width="160" src="${product.variants[index].featured_image.src});">
              </div>
              <div class="grid-product__meta">
                <div class="grid-product__title grid-product__title--body">${product.title}</div>
                <div class="grid-product__vendor">${product.vendor}</div>
                <div class="grid-product__price">$${product.variants[index].price}
                </div>
              </div>
            </a>
            <!--  ============= add custom button ( quick view, love, add to cart ) =============-->
    <div class="quick-product__menus quick-product__btn cssgrid w-100">

    <div aria-expanded class="quick-product__btn js-modal-open-quick-modal-${product.id} d-flex quick-product__icon-bg quick-product__view" data-product-id="${product.id}">
    <a href="/products/${product.handle}" target="_blank" class="w-100 h-100">
    <span class="quick-product__label d-flex align-self-center quick-try-on w-100 h-100"></span>
    </a>
    </div>

    </div>
      <!-- =============  end of custom button  =============-->
    </div>
    <div class="grid-product__colors grid-product__colors--${product.id}">
    <div id="color_squares_container-${product.id}" class="d-flex">
    ${p.variants.map(v=>`<div class="sw_sm${v.matched?' matched':''}"><div style="background:${v.v.option2}"></div></div>`).join('')}
    </div>
    </div>
    </div>
    </div>`;

    return out_put;
    }
  var colors = [];
  var coolTags = ['Lips', 'Lipstick', 'Blush', 'Eyes', 'Eyeliner'];


  var tags = prs.products.reduce( function( store, p ){

    p.tags.forEach( t => {
      if( t[ 0 ].toUpperCase() === t[ 0 ] )
        store[ t ] = true
    } );

    return store;
  }, {} );

  var s = new Store({
    colorCount: 24, possibleCollapse: true, BrandCollapse: false,
    brand: [],
    colors: []
  });


  D.div( {
    renderTo: document.getElementById( 'tags' )
  }, Object.keys( tags ).map( a => D.span( { style: { padding: '10px' } }, a ) ) );

  D.appendChild(document.getElementById('colorsCount'),new Slider({
    from: 16,
    to: 36,
    value: s.bind('colorCount'),
    step: 1,
    afterInit: function(){
      //console.log(this.value)
      D.div( { renderTo: this.dragEl, cls: 'slider-hover-val' }, T.toFixed( this.value, 0 ) );
    }
  }));

  D.div( {
    renderTo: document.getElementById( 'cooltags' )
  }, coolTags.map( tag =>
    D.div( { style: { display: 'inline-block' } },
      D.h( 'label', { cls: 'field' },
        new Radio( {
          value: tag,
          group: s.bind( 'tag' )
        } ),
        tag
      )
  ) ) );


  D.div( {
    renderTo: document.getElementById( 'colorogrammaSwitches' )
  }, ['PRODUCTS', 'COLOROGRAMMA'].map( tag =>
    D.div( { style: { display: 'inline-block' } },
      D.h( 'label', { cls: 'field' },
        new Radio( {
          value: tag,
          group: s.bind( 'colorogramma' )
        } ),
        tag
      )
    ) ) );
  s.sub(['colorogramma'], function(colorogramma) {
    var pl = document.getElementById('productList').style,
        cl = document.getElementById('c0').style;
    if(colorogramma==='PRODUCTS'){
      cl.display = 'none';
      pl.display = 'flex';
    }else{
      pl.display = 'none';
      cl.display = 'block';
    }
  });
  var toggle = function(key, val) {
    var arr = s.get(key);
    if(arr.indexOf(val) > -1){
      var spliced = arr.slice(0);
      spliced.splice(arr.indexOf(val), 1);
      s.set(key, spliced);
    }else{
      s.set(key, arr.slice(0).concat(val));
    }
  }
  s.sub(['tag', 'colorCount', 'brand', 'colors'], Store.debounce(function(tag, maxColors, brand, selectedColors) {

    colors = [];
    var vendors = prs.products.reduce((s,p)=>{
      if(p.tags.indexOf( tag ) === -1)
        return s;
      if(p.variants.filter(v=>{
        if( v.option2 ){
          var r = HEX2RGB( v.option2 );
          if( !isNaN( r[ 0 ] ) ){

            return true;
          }
        }
        return false
      }).length>0)
      p.vendor && (s[p.vendor] || (s[p.vendor] = [])).push(p);
      return s;
    }, {})

    var allVendors = Object.keys(vendors);

    var allBrandsDeselected = allVendors.filter(v=>brand.indexOf(v)===-1).length === allVendors.length;


    var products = prs.products
        .filter( function( pr ){
          return (pr.tags.indexOf( tag ) > -1) && (
            allBrandsDeselected ? true : brand.indexOf(pr.vendor)>-1
          );
          return pr.tags.indexOf( 'Eyes' ) > -1
          return pr.tags.indexOf( 'Lips' ) > -1
          return true;
        } )
        .map( function( pr ){
          pr.variants.forEach( function( v ){
            if( v.option2 ){
              var r = HEX2RGB( v.option2 )[ 0 ];
              if( !isNaN( r ) ){
                colors.push( v.option2 )
              }
            }
          } )
          return pr;
        } );


      D.replaceChildren(document.getElementById( 'yep' ), new Collapse({
        label: 'All possible colors (debug)',
        value: s.bind('possibleCollapse')
      }, D.div( {},
        colors.map( function( c ){
          return D.div( {
            style: {
              background: c,
              width: '16px',
              height: '16px',
              float: 'left',
              margin: '0',
              border: '1px inset'
            }
          } )
        } )
      )));



      var t = +new Date();
      var means = new KMeans();
      var result = {
        means: means,
        clusters: means.cluster( colors.map( c =>
          rgbToLab.apply( null, HEX2RGB( c ) )
        ), 10, labDistance )
      };
      console.log( +new Date() - t )

    D.replaceChildren(document.getElementById( 'yep2' ), D.div( {},
        result.clusters.map( function( c ){
          c = { color: c }

          var l = 0, a = 0, b = 0;
          for( var i = 0, _i = c.color.length; i < _i; i++ ){
            var colorElement = c.color[ i ];
            l += colorElement[ 0 ];
            a += colorElement[ 1 ];
            b += colorElement[ 2 ];
          }
          return [
            l / c.color.length,
            a / c.color.length,
            b / c.color.length
          ];
          //c.color.sort( colorSort )[ 0 ];//result.means.centroids.slice().sort(distanceToHSV(c.color[0]))[0];
        } ).map( function( c ){
          var rgb = labToRgb.apply( null, c );
          return D.div( {
            style: {
              background: 'rgb(' + rgb + ')',
              width: '48px',
              height: '48px',
              float: 'left',
              margin: '1px 1px 0 0',
              border: '1px solid #666',
              borderRadius: '4px'
            }
          } )
        } )
      ));

      var c = document.getElementById( 'c0' ),
        ctx = c.getContext( '2d' );
    ctx.clearRect(0,0,c.clientWidth, c.clientHeight);
      var testItems = [];
      for( var j = 0.05; j < 0.95; j += 0.1 ){
        var dots = 300 * 2 * 3.141592 / 100 * j * 3, step = 6.28 / dots;
        for( var i = 0; i < 6; i += step ){

          var p = new Point( 250 * j, 0 ).rotate( i ).add( 250, 250 );
          var clr = hsvToRgb( i / 6.28, j < 0.5 ? j * 2 : 1, j > 0.5 ? ( ( 1 - j ) ) * 2 : 1 );

          var item = {
            rgb: clr,
            lab: rgbToLab.apply( null, clr ),
            p: p,
            matched: 0,
            colors: []
          };
          testItems.push( item );


        }
      }
      for(var i = 0; i <= 256; i+=256/6){
        var clr = [i,i,i];
        var p = new Point( 290 , 0 ).rotate( i/256*6.28/4 ).add( 250, 250 );

        testItems.push( {
          rgb: clr,
          lab: rgbToLab.apply( null, clr ),
          p: p,
          matched: 0,
          colors: []
        } );
      }


      var labColors = colors.map( c =>
        ( { lab: rgbToLab.apply( null, HEX2RGB( c ) ), used: [] } )
      );
      //debugger
      for( var i = 0, _i = labColors.length; i < _i; i++ ){
        var labColor = labColors[ i ];
        var closest = 100, closestItem = false;
        for( var j = 0, _j = testItems.length; j < _j; j++ ){
          var testItem = testItems[ j ];
          var distance = labDistance( labColor.lab, testItem.lab );
          if( distance < closest ){
            /*if( distance < 5 && closestItem ){
              closestItem.matched += 4
              labColor.used.push( closestItem );
              closestItem.colors.push( labColor );
            }*/
            closest = distance;
            closestItem = testItem;

          }
        }
        if( closestItem ){
          closestItem.matched++;
          labColor.used.push( closestItem );
          closestItem.colors.push( labColor );
        }
      }


      var filteredItems = []
      for( var j = 0, _j = testItems.length; j < _j; j++ ){
        var testItem = testItems[ j ];
        if( testItem.matched === 0 )
          continue;
        filteredItems.push( testItem );

      }
      ctx.strokeStyle = '#777';
      for( var j = 0, _j = filteredItems.length; j < _j; j++ ){
        var testItem = filteredItems[ j ];

        var clr = testItem.rgb,
          p = testItem.p;
        ctx.fillStyle = 'rgb(' + clr.map( a => a | 0 ) + ')'
        ctx.beginPath();
        ctx.arc( p.x, p.y, Math.min( Math.max( testItem.matched, 2 ), 8 ) * 2.5, 0, 6.28 )
        ctx.fill();
        ctx.beginPath();
        ctx.arc( p.x, p.y, Math.min( Math.max( testItem.matched, 2 ), 8 ) * 2.2, 0, 6.28 )
        ctx.stroke();
      }


      console.log( filteredItems.length )


    //debugger


      var ff /*= filteredItems.filter( function( item ){
        return !item.colors.every( ( clr ) => clr.used.length > 1 )
      } )*/

      var removed = {};

      var sectors = [],  angle = 15, thresh = 10;


      ff = filteredItems.filter((f,m)=>{
        var uniq = filteredItems.filter((f2, k)=>{

          if(k in removed)
            return 0;

          var uniq = (labDistance(f2.lab,f.lab)|0)<thresh?1:0

          return uniq;
        }).length === 1

        if(!uniq){
          removed[m] = true;

        }

        return uniq;
      })



      var megaFilter = [],
            other = [];

      for(var i = 0; i < 360; i+=angle){
        sectors.push([]);
      }
      for( var i = 0, _i = ff.length; i < _i; i++ ){
        var filteredItem = ff[ i ],
          hsv = rgbToHsv.apply(null, filteredItem.rgb);
        filteredItem.hsv = hsv;

        sectors[(hsv[0]*360/angle)|0].push(filteredItem);
      }
      sectors.forEach(function(sector) {
        if(sector.length === 1){
            megaFilter.push(sector[0]);
        }else if(sector.length === 2){
            if(labDistance(sector[0].lab,sector[1].lab)<14){
              var middle = {hsv: [
                  (sector[0].hsv[0]+sector[1].hsv[0])/2,
                  (sector[0].hsv[1]+sector[1].hsv[1])/2,
                  (sector[0].hsv[2]+sector[1].hsv[2])/2
                ]
              };
              middle.rgb = hsvToRgb.apply(null, middle.hsv);
              middle.p = sector[0].p.middle(sector[1].p);
              middle.matched = 3;

              megaFilter.push(middle);
            }else{
              other.push(sector);
            }
        }else{
          other.push(sector);
        }
      });


      var means2 = new KMeans();

      if(other.length){
        var otherPoints = [].concat.apply([], other);
        var result = {
          means: means2,
          clusters: means2.cluster( otherPoints.map( c =>c.lab),
            Math.min(maxColors - megaFilter.length, otherPoints.length), labDistance )
        };
        result.clusters.map( function( c ){
          var l = 0, a = 0, b = 0;
          for( var i = 0, _i = c.length; i < _i; i++ ){
            var colorElement = c[ i ];
            l+=colorElement[0];
            a+=colorElement[1];
            b+=colorElement[2];
          }
          return [
            l/c.length,
            a/c.length,
            b/c.length
          ];
          //c.color.sort( colorSort )[ 0 ];//result.means.centroids.slice().sort(distanceToHSV(c.color[0]))[0];
        } ).forEach(function(lab) {
          megaFilter.push({
            lab: lab,
            rgb: labToRgb.apply(null, lab),
            hsv: rgbToHsv.apply(null,labToRgb.apply(null, lab))
          })
        });


      }
      megaFilter.sort((a,b)=>{
        return ( a.hsv[ 0 ] - b.hsv[ 0 ] ) * 50 + ( b.hsv[ 2 ] - a.hsv[ 2 ] ) * 35 + ( a.hsv[ 1 ] - b.hsv[ 1 ] ) * 2;
      })
    var somethingSelected = false;
      D.replaceChildren(document.getElementById( 'yep3' ),D.div( {},
        megaFilter.map( function( c ){
          var txt = c.rgb.map(c=>c|0).join(',');

          var isSelected = selectedColors.indexOf(txt)>-1;
          somethingSelected = somethingSelected || isSelected;
          return D.div( {
            cls: 'colorSwatch'+(isSelected ? ' active': ''),
            onclick: ()=>{
              console.log(txt)
              toggle('colors', txt)
            },
            style: {
              background: 'rgb(' + txt + ')',
              
            }
          } )
        } )
      ));

    /*
      ctx.strokeStyle = '#fff';
      for( var j = 0, _j = megaFilter.length; j < _j; j++ ){
        var testItem = megaFilter[ j ];

        var clr = testItem.rgb,
          p = testItem.p;
        ctx.fillStyle = 'rgb(' + clr.map( a => a | 0 ) + ')'

        ctx.fillRect( p.x-4, p.y-4, 8,8 )
      }*/
    var searchResults = [];
    D.replaceChildren(document.getElementById( 'BrandCollapse' ), new Collapse({
      label: 'Brand',
      value: s.bind('BrandCollapse')
    }, D.div( {},
      Object.keys(vendors).map(v=>{
        var variantExist = true;
        if(somethingSelected){
          variantExist = false
          var products = vendors[v];
          //outer:
          for( var i = 0, _i = products.length; i < _i; i++ ){
            var product = products[ i ],
                variants = product.variants;

            var subM = false;
            var matchHash = {};
            for( var j = 0, _j = variants.length; j < _j; j++ ){
              var variant = variants[ j ];
              var clr = variant.option2;
              var r = HEX2RGB( clr );
              if( isNaN( r[ 0 ] ) ){
                continue;
              }
              for( var k = 0, _k = selectedColors.length; k < _k; k++ ){
                const selected = selectedColors[ k ].split(',').map(Number);
                if(labDistance(rgbToLab.apply(null, r), rgbToLab.apply(null, selected))<15){
                  variantExist = true
                  matchHash[variant.id] = true;
                  subM = true;
                  break;
                }
              }


            }
            if(subM){
              searchResults.push( {
                product: product,
                variants: product.variants.map( v => ( {
                  matched: v.id in matchHash,
                  v: v
                } ) )
              } )
            }
          }
        }else{
          vendors[v].forEach(p=>{
            searchResults.push({product: p, variants: p.variants.map(v=>({matched: false, v: v}))})
          });

        }
        return D.div(
            {cls: 'vendor'+(variantExist?'': ' disabled')},
            D.h( 'label', { cls: 'field' },
              D.h('input', {
                prop: {
                  type: 'checkbox',
                  checked: brand.indexOf(v)>-1,
                  disabled: !variantExist
                },
                onchange: (e)=>{
                  toggle('brand', v)
                }
              } ),
              v
            )
          );
      })
    )));

    searchResults.sort((a,b)=>a.product.title<b.product.title?-1:1);
    document.getElementById('productList').innerHTML = searchResults.map((p)=>{
      return matchingProductsFormat(p,0)
    }).join('');
    /*D.replaceChildren(document.getElementById('productList'),

    )*/
      console.log( ff.length )
      console.log( megaFilter.length )
  }, 100));
  s.set('tag', 'Lips')

  s.set('colorogramma', 'PRODUCTS')
  //debugger

</script>
</body>
</html>