`),s=o.shift().split(" ");t.transaction(()=>o.forEach((n,c)=>{const a=n.split(" ");a.length==s.length&&a.forEach((r,u)=>{r!=""&&(z.test(r)&&(r=parseFloat(r)),t.setCell("cars",c,s[u],r))})}))},W=()=>{const[t,o]=S(!1),[s,n]=C("cars","dimensions"),[c,a]=C("cars","measures"),[r,u]=C("cars","aggregate");return f(v,{children:[f("aside",{children:[e("b",{children:"Dimensions"}),e(E,{options:F,selected:s,onOptionsChange:n}),e("hr",{}),e("b",{children:"Measures"}),e(E,{options:Y,selected:c,onOptionsChange:a}),e("hr",{}),e("b",{children:"Aggregate"}),e(E,{options:Object.keys(T),selected:[r],onOptionsChange:u,multiple:!1}),e("hr",{}),e("input",{id:"showTable",type:"checkbox",checked:t,onChange:A(({target:l})=>o(l.checked),[])}),e("label",{for:"showTable",children:"Show table"}),e("br",{}),e("small",{children:e("a",{href:"https://github.com/vega/vega-datasets/blob/next/data/cars.json",children:"Source"})})]}),t?e(X,{columns:[...s,...c]}):e(K,{dimensions:s,measures:c})]})},X=({columns:t})=>e(Q,{queryId:"cars",sortOnClick:!0,paginator:!0,limit:10,idColumn:!1,customCells:y(()=>Object.fromEntries(t.map(o=>[o,{component:J}])),[...t])}),J=({rowId:t,cellId:o})=>{const s=H("cars",t,o);return e("span",{className:o,children:Number.isFinite(s)?$(s):s})},K=({dimensions:t,measures:o})=>{const s=D(null),[{width:n=0,height:c=0},a]=S({});O(()=>{const p=new ResizeObserver(([{contentRect:i}])=>a(i));return p.observe(s.current),()=>p.disconnect()},[s]);const[r,u,l]=Z(t,o),[m,h,x,M,w]=ee(n,c,r,l);return n==0||c==0?e("main",{ref:s}):e("main",{ref:s,children:f("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:`0 0 ${n} ${c}`,children:[e("path",{d:`M${m(0)} ${h(0)}H${m(w)}`}),e(v,{children:x.map((p,i)=>{const d=m(i)-R/2,g=h(0)+b;return p&&e("text",{transform:`translate(${d} ${g}) rotate(90)`,children:p},i)})}),e(v,{children:M.map(p=>{const i=m(0)-b,d=h(p)+R/2;return e("text",{transform:`translate(${i} ${d})`,"text-anchor":"end",children:p},p)})}),u.map((p,i)=>f("g",{className:o[i],children:[e("path",{d:p.map((d,g)=>`${g==0?"M":"L"}${m(g)} ${h(d)}`).join("")}),p.map((d,g)=>f(v,{children:[e("circle",{cx:m(g),cy:h(d),r:b}),f("text",{x:m(g),y:h(d)-R,children:[r[g]," ",o[i],": ",$(d)]})]}))]},i))]})})},Z=(t,o)=>{const s=j("cars"),n=_("cars",o[0]??void 0);return y(()=>{const c=[1],a=[],r=o.map(()=>[]);return n.forEach(u=>{const l=s[u];a.push(t.map(m=>l[m]).join(", ")),o.forEach((m,h)=>{c.push(l[m]),r[h].push(l[m])})}),[a,r,Math.max(...c)]},[s,n,o,t])},ee=(t,o,s,n)=>y(()=>{const c=o/4,a=t/15,r=t-a-b,u=o-c-b,l=s.length-1,m=s.map((i,d)=>d%Math.ceil(R*l/r)==0?i:null),h=Math.pow(10,Math.floor(Math.log10(n))),x=Math.ceil(n/h)*h,M=Math.ceil(n/h),w=M<=2?5:M<=5?2:1,p=Array(w*M+1).fill().map((i,d)=>d*h/w);return[i=>a+i*r/l,i=>b+u-i*u/x,m,p,l,x]},[t,o,s,n]),E=({options:t,selected:o,onOptionsChange:s,multiple:n=!0})=>{const c=A(({target:a})=>s(n?[...a.selectedOptions].map(r=>r.value):a.value),[s]);return e("select",{multiple:n,size:t.length,onChange:c,children:t.map(a=>e("option",{value:a,selected:o.includes(a),className:a,children:a}))})};</script></html>"></iframe><p>In this demo, we build an app that showcases the query capabilities of TinyBase v2.0, grouping and sorting dimensional data for lightweight analytical usage.</p><p>We've also updated it to use parameterized queries to take advantage of TinyBase v7.2.</p><p>The data from this demo is derived from <code>cars.json</code> in the <a href="https://github.com/vega/vega-datasets">Vega datasets</a> - thank you <a href="https://idl.cs.washington.edu/">UW Interactive Data Lab</a>!</p><h3 id="an-overview-of-the-data">An Overview Of The Data</h3><p>Before looking at code, let's familiarize ourselves with the data used in this application.</p><p>The raw data is loaded from a TSV file into one single <a href="/api/store/type-aliases/store/table/"><code>Table</code></a> object: <code>cars</code>, and comprises almost 400 records of cars made in the 1970s and 1980s.</p><p>For each, the data includes the manufacturer, the car name, year, and region. These <a href="/api/store/type-aliases/store/cell/"><code>Cell</code></a> values are 'dimensions' with which the data can be grouped.</p><p>Each record also includes a number of quantitative fields, including the car's miles-per-gallon (MPG), the number of cylinders, their displacement, its horsepower, weight, and acceleration. These <a href="/api/store/type-aliases/store/cell/"><code>Cell</code></a> values are 'measures' which can be aggregated together - in this basic app, to find their average, maximum, or minimum.</p><p>The app is oriented around one single query. As the user picks different dimensions or measures in the app's sidebar, that query is re-run and the results (either in graphical or tabular form) reactively update immediately.</p><h3 id="boilerplate">Boilerplate</h3><p>First, we create the import aliases for TinyBase and React modules we'll need:</p><pre><code><span class="tag"><span class="tag"><span class="punctuation"><</span>script</span> <span class="attr-name">type</span><span class="attr-value"><span class="punctuation">=</span><span class="punctuation">"</span>importmap<span class="punctuation">"</span></span><span class="punctuation">></span></span><span class="script"><span class="language-javascript">
0 commit comments