import {select, inputs} from "@jashkenas/inputs";

viewof dateSelect1 = Inputs.date({min: "2014-01-02", max: "2022-12-30", value: "2018-01-01"})

dateTemp1 = new Date(2014, 0, 1)
date1 = dateTemp1.toLocaleDateString()

startDateSelect = {
  if (dateSelect1 == null) {
    return d3.timeParse("%m/%d/%Y")(date1)
  } else {
    return d3.timeParse("%m/%d/%Y")(dateSelect1.toLocaleDateString())
  }
}

minDate = dateSelect1.setDate(dateSelect1.getDate() + 1);

viewof dateSelect2 = Inputs.date({min: minDate, max: "2023-01-01", value: "2023-01-01"})

dateTemp2 = new Date(2023, 0, 0)
date2 = dateTemp2.toLocaleDateString()

endDateSelect = {
  if (dateSelect2 == null) {
    return d3.timeParse("%m/%d/%Y")(date2)
  } else {
    return d3.timeParse("%m/%d/%Y")(dateSelect2.toLocaleDateString())
  }
}

lineIndicator = endDateSelect - startDateSelect;


html` 

  <div class="row">
      <div class="column-end-date" style="margin: 0px 2px 0 2px; width: 100px">
      <span style="font-weight: 700;">Currency/Asset:</span>
      ${viewof tradAssetSelect}
    </div>
     <div class="column-end-date" style="margin: 0px 2px 0 2px; width: 100px;">
      <span style="font-weight: 700;">Crypto:</span>
      ${viewof cryptoAssetSelect}
    </div>
    <div class="column-start-date" style="margin: 0px 2px 0 2px; width: 100px">
        <span style="font-weight: 700;">Start Date:</span>
      ${viewof dateSelect1}
    <span style="font-weight: 700;">End Date:</span>
      ${viewof dateSelect2}
    </div>
  </div>  
  
  <div class="row">
  <div class="column-2">  ${cryptoTraditionalChart}</div>
</div>

`
viewof tradAssetSelect = Inputs.select(["Euro", "Pound", "Real", "Ruble", "Rupee", "Yen", "Russell 2000", "S&P 500", "Gold", "Silver"], {multiple: 4, value: ["Euro", "Pound", "Yen"]});

viewof cryptoAssetSelect = Inputs.select(["Bitcoin", "Ethereum", "Binance", "Ripple", "Cardano", "Polygon", "DogeCoin", "FTX Token"], {multiple: 4, value: ["Bitcoin"]});

assetSelect = tradAssetSelect.concat(cryptoAssetSelect);
html`
<style>

.column-1 {
  float: left;
  font-size: 12px;
  width: 100px;
}

.column-2 {
  float: left;
  width: ${width}px;
}

.column-title {
    float: left;
    font-size: 18px;
    display: inline-block;
}

.column-start-date {
    font-size: 12px;
    display: inline-block;
    float: left;
}

.column-end-date {
    font-size: 12px;
    display: inline-block;
    float: left;
}

/* Clear floats after the columns */
.row:after {
  content: "";
  display: table;
  clear: both;
}

</style>
`
tempData = FileAttachment("./data/crypto_data_030723.csv").csv().then(
  function(data) {
    data.forEach(function(d) {
      d.datez = d3.timeParse("%Y-%m-%d")(d.date);
    });
  return data;
  }
)

tempData2 = aq.from(tempData)
    .params({startDateSelect: startDateSelect})
    .params({endDateSelect: endDateSelect})
    .filter((d, $) => d.datez >= $.startDateSelect)
    .filter((d, $) => d.datez <= $.endDateSelect)
    .objects()

tempData3 = aq.from(tempData2)
    .derive({"date": d => d.datez})
    .derive({"S&P 500": d => +d.GSPC})
    .derive({"VIX": d => +d.VIX})
    .derive({"Russell 2000": d => +d.RUT})
    .derive({"Crude Oil": d => +d.CL})
    .derive({"Gold": d => +d.GC})
    .derive({"Silver": d => +d.SI})
    .derive({"Euro": d => +d.EUR})
    .derive({"Pound": d => +d.GBP})
    .derive({"Ruble": d => +d.RUB})
    .derive({"Yen": d => +d.JPY})
    .derive({"Real": d => +d.BRL})
    .derive({"Rupee": d => +d.INR})
    .derive({"Bitcoin": d => +d.BTC})
    .derive({"Ethereum": d => +d.ETH})
    .derive({"Binance": d => +d.BNB})
    .derive({"Ripple": d => +d.XRP})
    .derive({"Cardano": d => +d.ADA})
    .derive({"Polygon": d => +d.MATIC})
    .derive({"DogeCoin": d => +d.DOGE})
    .derive({"Binance USD": d => +d.BUSD})
    .derive({"Tether": d => +d.USDT})
    .derive({"USD Coin": d => +d.USDC})
    .derive({"FTX Token": d => +d.FTT})
    .select("date", "S&P 500", "Russell 2000", "VIX", "Crude Oil", "Gold", "Silver", "Euro", "Pound", "Ruble", "Yen", "Real", "Rupee", "Bitcoin", "Ethereum", "Binance", "Ripple", "Cardano", "Polygon", "DogeCoin", "Binance USD", "Tether", "USD Coin", "FTX Token")
    .fold(aq.not('date'), { as: ['id', 'value'] })
    .orderby('id')
    .objects();



tempData4 = aq.from(tempData2)
    .derive({"date": d => d.datez})
    .derive({"S&P 500": d => +d["GSPC.Adjusted"]})
    .derive({"VIX": d => +d["VIX.Adjusted"]})
    .derive({"Russell 2000": d => +d["RUT.Adjusted"]})
    .derive({"Crude Oil": d => +d["CL=F.Adjusted"]})
    .derive({"Gold": d => +d["GC=F.Adjusted"]})
    .derive({"Silver": d => +d["SI=F.Adjusted"]})
    .derive({"Euro": d => +d["EURUSD=X.Adjusted"]})
    .derive({"Pound": d => +d["GBPUSD=X.Adjusted"]})
    .derive({"Ruble": d => +d["RUBUSD=X.Adjusted"]})
    .derive({"Yen": d => +d["JPYUSD=X.Adjusted"]})
    .derive({"Real": d => +d["BRLUSD=X.Adjusted"]})
    .derive({"Rupee": d => +d["INRUSD=X.Adjusted"]})
    .derive({"Bitcoin": d => +d["BTC-USD.Adjusted"]})
    .derive({"Ethereum": d => +d["ETH-USD.Adjusted"]})
    .derive({"Binance": d => +d["BNB-USD.Adjusted"]})
    .derive({"Ripple": d => +d["XRP-USD.Adjusted"]})
    .derive({"Cardano": d => +d["ADA-USD.Adjusted"]})
    .derive({"Polygon": d => +d["MATIC-USD.Adjusted"]})
    .derive({"DogeCoin": d => +d["DOGE-USD.Adjusted"]})
    .derive({"Binance USD": d => +d["BUSD-USD.Adjusted"]})
    .derive({"Tether": d => +d["USDT-USD.Adjusted"]})
    .derive({"USD Coin": d => +d["USDC-USD.Adjusted"]})
    .derive({"FTX Token": d => +d["FTT-USD.Adjusted"]})
    .select("date", "S&P 500", "Russell 2000", "VIX", "Crude Oil", "Gold", "Silver", "Euro", "Pound", "Ruble", "Yen", "Real", "Rupee", "Bitcoin", "Ethereum", "Binance", "Ripple", "Cardano", "Polygon", "DogeCoin", "Binance USD", "Tether", "USD Coin", "FTX Token")
    .fold(aq.not('date'), { as: ['id', 'price'] })
    .orderby('id')
    .objects();
    
data =  aq.from(tempData3)
    .join_left(aq.from(tempData4), [["date", "id"], ["date", "id"]])
    .objects();


dataSum = aq.from(data)
    .groupby("id")
    .rollup({"absMDC": d => op.mean(op.abs(d.value))})
    .objects();
d3 = require("d3@6") // Load D3

format = ({
  date1: d3.timeFormat("%B %e, %Y"), // Timeline Tooltip Date Format
  date2: d3.timeFormat("%b %e %Y"), // Timeline Tooltip Date Format
  percent1d: d3.format(".1%"),
  percent2d: d3.format(".2%"),
  dollar:  d3.format("$,.2f"),
  cents: d3.format("$,.4f"),
  avg: d3.format("(,.1f"),
  chg: d3.format(".2%")
})

function isNum(n) {
  return !isNaN(parseFloat(n)) && isFinite(n) && n !== "";
}

chartTip = d3.select("body").append("div").attr("class", "toolTip chartTip");
dataDict = ({

    "S&P 500": {
        label: "S&P 500",
        color: "rgb(196, 41, 51)",
        absMDC: format.chg(dataSum[17].absMDC),
    },

    "VIX": {
        label: "VIX",
        color: "rgb(8, 30, 88)",
        absMDC: format.chg(dataSum[21].absMDC)
    },

  "Russell 2000": {
        label: "Russell",
        color: "#000",
        absMDC: format.chg(dataSum[16].absMDC)
  },


    "Crude Oil": {
        label: "Crude",
        color: "#3B3131",
        absMDC: format.chg(dataSum[4].absMDC)
    },

    "Gold": {
        label: "Gold",
        color: "#d4af37",
        absMDC: format.chg(dataSum[9].absMDC)
    },

    "Silver": {
        label: "Silver",
        color: "#C0C0C0",
        absMDC: format.chg(dataSum[18].absMDC)
    },

    "Euro": {
        label: "Euro",
        color: "#003399",
        absMDC: format.chg(dataSum[7].absMDC)
    },

    "Pound": {
        label: "Pound",
        color: "#012169",
        absMDC: format.chg(dataSum[11].absMDC)
    },

    "Ruble": {
        label: "Ruble",
        color: "#0033A0",
        absMDC: format.chg(dataSum[14].absMDC)
    },

    "Yen": {
        label: "Yen",
        color: "#BC002D",
        absMDC: format.chg(dataSum[22].absMDC)
    },

    "Real": {
        label: "Real",
        color: "#009c3b",
        absMDC: format.chg(dataSum[12].absMDC)
    },

    "Rupee": {
        label: "Rupee",
        color: "#FF9933",
        absMDC: format.chg(dataSum[15].absMDC)
    },

    "Bitcoin": {
        label: "Bitcoin",
        color: "rgb(233, 153, 61)",
        absMDC: format.chg(dataSum[2].absMDC)
    },

    "Ethereum": {
        label: "Ethereum",
        color: "rgb(79, 79, 80)",
        absMDC: format.chg(dataSum[6].absMDC)
    },

    "Binance": {
        label: "Binance",
        color: "rgb(231, 188, 66)",
        absMDC: format.chg(dataSum[0].absMDC)
    },

    "Ripple": {
        label: "Ripple",
        color: "rgb(36, 41, 46)",
        absMDC: format.chg(dataSum[13].absMDC)
    },

    "Cardano": {
        label: "Cardano",
        color: "rgb(25, 56, 168)",
        absMDC: format.chg(dataSum[3].absMDC)
    },

    "Polygon": {
        label: "Polygon",
        color: "rgb(122, 74, 221)",
        absMDC: format.chg(dataSum[10].absMDC)
    },

    "DogeCoin": {
        label: "DogeCoin",
        color: "rgb(183, 162, 74)",
        absMDC: format.chg(dataSum[5].absMDC)
    },

    "Binance USD": {
        label: "Binance $",
        color: "rgb(231, 188, 66)",
        absMDC: format.chg(dataSum[1].absMDC)
    },

    "Tether": {
        label: "Tether",
        color: "rgb(66, 147, 148)",
        absMDC: format.chg(dataSum[19].absMDC)
    },

    "USD Coin": {
        label: "USD Coin",
        color: "rgb(61, 114, 195)",
        absMDC: format.chg(dataSum[20].absMDC)
    },

    "FTX Token": {
        label: "FTX Token",
        color: "rgb(127, 206, 226)",
        absMDC: format.chg(dataSum[8].absMDC)
    },
})
cryptoTraditionalChart = {

  let height = 375
  let margin = {top: 40, right: 155, bottom: 60, left: 50}
  let innerHeight = height - margin.top - margin.bottom;
  let innerWidth = width - margin.left - margin.right;
  let chartid = "daily-movement"; 
  const cVar = 'color';
  const selectType = "value";
  const selectGroup = assetSelect; // array of the checkbox selections for filtering
  let filtered = data.filter(d => selectGroup.includes(d.id)); // filter data.set for extext
  let extData = d3.extent(filtered, d => d[selectType]); // filter data.set for extext
  let extDates = d3.extent(filtered, d => d.date) 
  let selectSeries = d3.groups(filtered, d => d.id);
  let selectLookup = d3.group(filtered, d => d.date.toISOString())
  let selectDates = Array.from(selectLookup).map(d => d[1][0].date);
  
  const svg = d3.create("svg")
        .attr("viewBox", [0, 0, width, height])
        .attr("id", chartid);
  
  const group = svg.append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
  
  // Source
  group.append("text")
    .attr("class", "graph-source")
    .text('Data: Market data from Yahoo Finance')
    .attr("text-anchor", "left")
    .attr("x", 0)
    .attr("y", innerHeight + margin.bottom - 18)
    .style('fill', '#999')
    .style('font-size', '.60em')
    .style('font-family', "'Open Sans', sans-serif");
  
   if (selectGroup.length === 0){
     group.append("text")
      .text('Select assets above')
      .attr("text-anchor", "middle")
      .attr("class", "notification")
      .attr("x", innerWidth/2)
      .attr("y", innerHeight/2)
      .style('fill', '#999')
      .style('font-size', '.85em');
   }

  let x = d3.scaleTime()
    .range([0, width - margin.left - margin.right])
    .domain(extDates);

  let y = d3.scaleLinear()
    .range([innerHeight, 0])
    .domain(extData);
    // .nice();
  
  let xAxis = d3.axisBottom(x);
  let yAxis = d3.axisLeft(y);
  
    // X-AXIS
      if (width > 700) {
  group.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate("+ 0 + "," + innerHeight +  ")")
      .call(xAxis)
      .call(d3.axisBottom(x)
          .tickFormat(d3.timeFormat("%b '%y"))
          .tickSize(5)
          .ticks(10)
         )
    .call(g => g.selectAll(".domain").remove())
    .style('color', 'rgb(129, 129, 129)')
    .style("font-size", "12px")
    .style("font-weight", 500)
    .style('font-family', "'Open Sans', sans-serif")
    .attr("stroke-opacity", 0.5);

      } else {

    group.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate("+ 0 + "," + innerHeight + ")")
      .call(xAxis)
      .call(d3.axisBottom(x)
          .tickFormat(d3.timeFormat("'%y"))
          .tickSize(10)
         )
    .call(g => g.selectAll(".domain").remove())
    .style('color', 'rgb(129, 129, 129)')
    .style("font-size", "14px")
    .style("font-weight", 500)
    .style('font-family', "'Open Sans', sans-serif")
    .attr("stroke-opacity", 0.5);
        
      }
  
   // Tooltip Line
  group.append("line")
    .attr("class", "y-highlight")
    .attr('x1', 0)
    .attr('x2', 0)
    .attr('y1', 0)
    .attr('y2', innerHeight)
    .style('stroke', '#d3d3d3')
    .style('stroke-width', '3px')
    .style('opacity', 0.85);


   // Y-Axis
    group.append("g")
      .attr("class", "y axis")
      .call(yAxis)
      .call(d3.axisLeft(y)
          .ticks(6)
      .tickFormat((d) => d3.format(`.0%`)(d)))
      .call(g => g.select(".domain").remove())
      .call(g => g.selectAll(".tick line").clone()
          .attr("x2", innerWidth + 50))
    .call(g => g.selectAll(".tick text")
          .style("font-size", "14px")
          .style("font-weight", 500)
          .attr("fill", "rgb(129, 129, 129)")
          .attr("transform", `translate(0, -7)`))
    .call(g => g.selectAll(".tick line")
          .attr("transform", `translate(-40, 0)`)
          .attr("stroke-opacity", 0.2))
    .call(g => g.append("text")
          .attr("text-anchor", "middle")
          .style("font-size", "16px")
          .attr("fill", "currentColor"))
        .attr('font-family', "'Open Sans', sans-serif");


  // Append Lines
  let lineGroup = group.append("g")
     .attr('class', 'line-group')
  
  let line = d3.line()
    .defined(d => !isNaN(d[selectType]))
    .x(d => x(d.date))
    .y(d => y(d[selectType]))
  
  lineGroup.append('g')
    .selectAll('path')
    .data(selectSeries)
    .join('path')
    .attr('d', (d) => line(d[1]))
    .attr("class", function(d) {
      return 'ts-line ts-line-' + d[0]; //  
    })
    .attr("fill", "none")
    .style("stroke", function(d) {
      return dataDict[d[0]].color
    })
    .attr('stroke-width', lineIndicator < 1e11 ? '1.75px' : '1.25px')

  
    // Label Object
    let labelset = Array.from(selectSeries).map(d => {
      let obj = {}
      obj.id = d[0];
      obj.label = dataDict[obj.id].label;
      obj.color = dataDict[obj.id].color;
      obj.absMDC = dataDict[obj.id].absMDC;
      obj.val = d[1][d[1].length - 1][selectType];
      return obj
    }).sort((a, b) => d3.descending(a.val, b.val))
  
    // Force Line Labels - Basic Version
    let forceLabelOffset = 8
    let forceLabelR = 20
    
    
    let forceLabels = group.append("g")
        .attr('class', 'line-force-labels')

    const forceLabelLeader = forceLabels.selectAll('line')
      .data(labelset)
      .join('line')
      .attr("class", 'lfl-leader')
      .attr('x1', innerWidth + 2)
      .attr('x2', innerWidth + forceLabelOffset)
      .attr('y1', d => y(d.val))
      .attr('y2', d => y(d.val))
      .attr('stroke', d => d.color)
    
    const forceLabel = forceLabels.selectAll('g')
      .data(labelset)
      .join('g')
      .attr('transform', function(d, i) { 
         // contrains node x,y to bounds
         d.x =  innerWidth + forceLabelOffset;
         //d.y =  y(d.val);
         d.y = innerHeight/3 + (i * 15); // initializes the labels in a stepped 
         return `translate(${d.x},${d.y})`
      })
      .on("mouseover", (event, d) => {
        d3.select(event.target).style("cursor", "pointer"); 
        d3.selectAll("#" + chartid + " .ts-line")
          .transition().style('opacity', g => { return g[0] === d.id ? 1 : 0.2; });
        d3.selectAll("#" + chartid + " .lfl-text")
          .transition().style('opacity', g => { return g.id === d.id ? 1 : 0.2; });
        d3.selectAll("#" + chartid + " .lfl-leader")
          .transition().style('opacity', g => { return g.id === d.id ? 1 : 0.2; });
        })
      .on("mouseout",  (event, d) => {
        d3.select(event.target).style("cursor", "default"); 
        d3.selectAll("#" + chartid + " .ts-line")
          .transition().style('opacity', 1 );
        d3.selectAll("#" + chartid + " .lfl-text")
          .transition().style('opacity', 1 );
        d3.selectAll("#" + chartid + " .lfl-leader")
          .transition().style('opacity', 1 );
      });

    forceLabel.append('text')
      .attr("class", 'lfl-text')
      .html(d => d.label + ` ` + d.absMDC + ` avg`)
      .attr('fill', d => d.color)
      .style('font-size', '14px')
      .style("font-weight", 700);

    const simulation = d3.forceSimulation(labelset)
      .force("charge", d3.forceManyBody().strength(-10))
      .force('y', d3.forceY().y(d => y(d.val)))
      .force('x', d3.forceX().x(innerWidth + forceLabelOffset))
      //.force("rectcollide", rectCollide())
      .force('collision', d3.forceCollide().radius(forceLabelR));
  
    simulation.on('tick', () => {
      forceLabel.attr('transform', function(d) { 
         d.x =  innerWidth + forceLabelOffset; // constrain x for all labels
         d.y =  Math.max(forceLabelR, Math.min((innerHeight+margin.bottom/2) - forceLabelR, d.y))
                
         return `translate(${d.x},${d.y})`
      });
      forceLabelLeader
        .attr("x2", d => d.x-2)
        .attr("y2", d => d.y)
    })
  
  // Chart toolTip Area (defines where hover with be active)
  let tipArea = group.append("g")
    .attr("class", "tip-area");
  
  tipArea.append('svg:rect') // append a rect to catch mouse movements on canvas
    .attr('width', innerWidth)
    .attr('height', innerHeight)
    .attr('opacity', 0)
    .attr('pointer-events', 'all')
    .on('mouseover', (event) => {
      console.log('mouseover');
    })
    .on('mousemove', (event) => {
      console.log('mousemove');
    
      // Get the date on the y axis for the mouse position
      let invert = x.invert(d3.pointer(event)[0])
      let bisect = d3.bisector(function(d) { return d; }).right;
      let hoverDate = (selectDates[bisect(selectDates, invert)]);
    
      // 1) Lookup/Get values by date 2) Filter by selection group 3) Sort by top values
      let lookup = selectLookup.get(hoverDate.toISOString()).filter(d => selectGroup.includes(d.id));

      // Display and position vertical line
      d3.select("#" + chartid + " .y-highlight")
         .attr('x1',x(hoverDate))
         .attr('x2',x(hoverDate))
         .style('opacity', 1);
      
        // Custom toolTip Content
      let tipContent = `<hr style='margin:2px; padding:0; border-top: 3px solid #333;'>`; 
      // Interate over selected categories 
      tipContent += `<table class="tip-table"><thead><tr><th></th><th>Daily % Δ</th><th>Price</th></tr></thead><tbody>`
      // Interate over selected categories 
      lookup.map( d => {
           tipContent += `<tr>
                          <td class="row-header"><div class="chip-circle" style="background-color: ${dataDict[d.id][cVar]};"></div> ${dataDict[d.id].label}</td>`
           tipContent += `<td>${format.percent2d(d.value)}</td>`
           tipContent += `<td>${d.price < 1 ? format.cents(d.price) : format.dollar(d.price)}</td></tr>`
        })
      // Close Table 
      tipContent += `</tbody></table>`
      
      chartTip.style("left", () => {
         if ((innerWidth - d3.pointer(event)[0]) < 120) {
              return event.pageX - (24+240) + "px";
            } else {
              return event.pageX + 24 + "px";
            }             
         })
        .style("top", event.pageY + 10 + "px")
        .style("display", "inline-block")
        .html(`<strong style="font-size: 14px;">${format.date1(hoverDate)}</strong><br>${tipContent}`); // toolTip Content
     })
    .on('mouseout', (event) => {
        console.log('mouseout');
        chartTip.style("display", "none"); // Hide toolTip
        d3.select("#" + chartid + " .y-highlight").style('opacity', 0); // Hide y-highlight line
        d3.selectAll("#" + chartid + " .y-highlight-point").remove(); // Remove y-highlight points 
     });
  
  return svg.node();
}
import {input} from "@jashkenas/inputs";

aq = {
  const aq = await require(`arquero@${aq_version}`);

  // load and install any additional packages
  (await Promise.all(aq_packages.map(pkg => require(pkg))))
    .forEach(pkg => aq.addPackage(pkg));

  // Add HTML table view method to tables
  aq.addTableMethod('view', toView, { override: true });

  return aq;
};
aq_version = "5.1.0";
aq_packages = [];

op = aq.op;
toView = {
  const DEFAULT_LIMIT = 100;
  const DEFAULT_NULL = value => `<span style="color: #999;">${value}</span>`;
  const tableStyle = 'margin: 0; border-collapse: collapse; width: initial;';
  const cellStyle = 'padding: 1px 5px; white-space: nowrap; overflow-x: hidden; text-overflow: ellipsis; font-variant-numeric: tabular-nums;';

  // extend table prototype to provide an HTML table view
  return function(dt, opt = {}) {
    // permit shorthand for limit
    if (typeof opt === 'number') opt = { limit: opt };
    
    // marshal cell color options
    const color = { ...opt.color };
    if (typeof opt.color === 'function') {
      // if function, apply to all columns
      dt.columnNames().forEach(name => color[name] = opt.color);
    } else {
      // otherwise, gather per-column color options
      for (const key in color) {
        const value = color[key];
        color[key] = typeof value === 'function' ? value : () => value;
      }
    }

    // marshal CSS styles as toHTML() options
    const table = `${tableStyle}`;
    const td = (name, index, row) => {
      return `${cellStyle} max-width: ${+opt.maxCellWidth || 300}px;`
        + (color[name] ? ` background-color: ${color[name](index, row)};` : '');
    };

    opt = {
      limit: DEFAULT_LIMIT,
      null: DEFAULT_NULL,
      ...opt,
      style: { table, td, th: td }
    };

    // return container div, bind table value to support viewof operator
    const size = `max-height: ${+opt.height || 270}px`;
    const style = `${size}; overflow-x: auto; overflow-y: auto;`;
    const view = html`<div style="${style}">${dt.toHTML(opt)}</div>`;
    view.value = dt;
    return view;
  };
};
mobileTest = {  if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(navigator.userAgent) 
      || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(navigator.userAgent.substr(0,4))) { return true; } else { return false; }
};
style_sheet = html`<style>
@import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;400;500;600;700;800&display=swap');

body {
  font-family: 'Open Sans', sans-serif;
}

select {
  font-family: 'Open Sans', sans-serif;
  // border-radius: 20px;
  background-color: #fff;
}

.chip-circle {
    border-radius: 50%;
    display: inline-block;
    position: relative;
    width: 10px;
    height: 10px;
  }



label {
  margin-top: 20px;
  padding: 10px;
  padding-right:15px;
  text-align: center;
  cursor: pointer;
  background-color: #fff;
    color: #2e3745;
  font-weight: 600;
}




input[type="range"] {
    -webkit-appearance: none;
    border: none;
    margin: 18px 0;
    width: 100%;
    box-shadow: -2px -2px 8px white, 2px 2px 8px rgba(black, 0.5);
}
input[type="range"]:focus {
    outline: none;
}
input[type="range"]::-webkit-slider-runnable-track {
    border: none;
    width: 100%;
    height: 5px;
    cursor: pointer;
    background: #fff;
    border-radius: 10px;
    box-shadow: rgb(204, 219, 232) 3px 3px 6px 0px inset, rgba(255, 255, 255, 0.5) -3px -3px 6px 1px inset;
}


input[type="range"]::-webkit-slider-thumb {
    height: 15px;
    width: 15px;
    border-radius: 30px;
    box-shadow: 0px 0px 4px 1px rgba(0,0,0,0.37);
    /* border: 1px solid #333; */
    background: #fff;
    cursor: pointer;
    -webkit-appearance: none;
    margin-top: -5px;
}
input[type="range"]:focus::-webkit-slider-runnable-track {
    background: #fff;
    border: none;
}
input[type="range"]::-moz-range-track {
    border: none;
    width: 100%;
    height: 5px;
    cursor: pointer;
    background: #fff;
    border-radius: 10px;
    box-shadow: rgb(204, 219, 232) 3px 3px 6px 0px inset, rgba(255, 255, 255, 0.5) -3px -3px 6px 1px inset;
}
input[type="range"]::-moz-range-thumb {
    height: 15px;
    width: 15px;
    border-radius: 30px;
    box-shadow: 0px 0px 4px 1px rgba(0,0,0,0.37);
    /* border: 1px solid #333; */
    background: #fff;
    cursor: pointer;
    -webkit-appearance: none;
    margin-top: -5px;
}
input[type="range"]::-ms-track {
    border: none;
    width: 100%;
    height: 5px;
    cursor: pointer;
    background: transparent;
    border-color: transparent;
    border-width: 16px 0;
    color: transparent;
}
input[type="range"]::-ms-fill-lower {
    background: #e0e0e0;
    border-radius: 2.6px;
}
input[type="range"]::-ms-fill-upper {
    background: #e0e0e0;
    border-radius: 2.6px;
}
input[type="range"]::-ms-thumb {
    border: none;
    height: 20px;
    width: 16px;
    border-radius: 3px;
    background: #ffffff;
    cursor: pointer;
}
input[type="range"]:focus::-ms-fill-lower {
    background: #fff;
}
input[type="range"]:focus::-ms-fill-upper {
    background: #fff;
}

/* clears the ‘X’ from Chrome */
input[type="search"]::-webkit-search-decoration,
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-results-button,
input[type="search"]::-webkit-search-results-decoration { display: none; }

input[type="time"]::-webkit-clear-button {
    -webkit-appearance: none; 
    -moz-appearance: none;
    appearance: none;
}


#grid-3 {
  display: grid;
  grid-template-columns: auto auto auto;
  background-color: #fff;
}

#grid-4 {
  display: grid;
  grid-template-columns: auto auto auto auto;
  background-color: #fff;
}

#grid-4-full {
  display: grid;
  grid-template-columns: auto auto auto auto;
  background-color: #fff;
  border-top: 1px solid #d3d3d3;
  border-right: 1px solid #d3d3d3;
  border-bottom: 1px solid #d3d3d3;
  border-left: 1px solid #d3d3d3;
}


#grid-4-top {
  display: grid;
  grid-template-columns: auto auto auto auto;
  background-color: #fff;
  border-top: 1px solid #d3d3d3;
  border-right: 1px solid #d3d3d3;
  border-left: 1px solid #d3d3d3;
}

#grid-4-bottom {
  display: grid;
  grid-template-columns: auto auto auto auto;
  background-color: #fff;
  border-bottom: 1px solid #d3d3d3;
  border-right: 1px solid #d3d3d3;
  border-left: 1px solid #d3d3d3;
}

.grid-item {
  background-color: rgba(255, 255, 255, 0.8);
  border: 1px solid #d3d3d3;
  padding: 20px;
  font-size: 16px;
  text-align: left;
}

</style>`
tooltipStyle = html`
<style> 
.toolTip {
  position: absolute;
  display: none;
  min-width: 30px;
  border-radius: 0;
  height: auto;
  background: #fff;
  border: 1px solid #d3d3d3;
  padding: 4px 4px;
  font-size: .85rem;
  text-align: left;
  z-index: 1000;
}

.eventTip {  max-width: 140px;}
.chartTip {  max-width: 240px;}

.tip-values {  
font-weight: bold;
color: #787878;
}
.tip-values .secondary{   
font-weight: normal;
}

.tip-table {
   font-size: 13px;
   text-align: right;
   color: #787878;
}

.tip-table td, .tip-table th {
  padding-right: 4px;
  padding-left: 4px;
}

.tip-table th {
  font-size: 13px;
  text-align: right;
  color: #AAA;
  vertical-align: bottom;
}

.tip-table .row-header {
  text-align: left;
}

.tip-table .primary {
  font-weight: bold;
}


</style>
`
html`<style>

.info-title {
     margin-bottom: 32px;
     text-align: center;
  }

.info-title h1 {
     max-width: 10000px;
}
  .info-box {
     padding: 24px;
  }
  .info-wrapper {
     display: flex;
     justify-content: center;
  }

.wrapper-2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
}

.wrapper-3 {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
}

.box-title {
    padding: 20px;
    text-align: center;
    font-weight: 500;
}

.wrapper-4 {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr 1fr;
}
</style>
`