Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Labs #23

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open

Labs #23

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions components/ColorPickerInput.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable jsx-a11y/no-static-element-interactions */
/* eslint-disable jsx-a11y/click-events-have-key-events */
import { Input, useTheme } from '@geist-ui/react';
import { Input } from '@geist-ui/react';
import React from 'react';
import ColorPicker from './ColorPicker';
import InputLabel from './InputLabel';
Expand All @@ -23,7 +23,6 @@ const ColorPickerInput: React.FC<Props> = ({
const handleColor = (v: string) => {
setColor(v, type);
};
const theme = useTheme();
const [open, setOpen] = React.useState<boolean>(false);
return (
<>
Expand Down Expand Up @@ -58,14 +57,14 @@ const ColorPickerInput: React.FC<Props> = ({
.picker-box {
width: 50px;
background-color: ${color};
border: 1px solid ${theme.palette.accents_2};
border: 1px solid #333;
border-right: 0;
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
}
.picker-container {
background-color: ${theme.palette.accents_1};
border: 1px solid ${theme.palette.accents_2};
background-color: #111;
border: 1px solid #333;
padding: 20px;
z-index: 1000;
top: 125%;
Expand Down
91 changes: 91 additions & 0 deletions labs/components/LabColorPicker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/* eslint-disable jsx-a11y/no-static-element-interactions */
/* eslint-disable jsx-a11y/click-events-have-key-events */
import { Input, useClickAway } from '@geist-ui/react';
import { ChevronDown, ChevronUp, XCircle } from '@geist-ui/react-icons';
import React from 'react';
import { HexColorPicker } from 'react-colorful';

interface Props {
color: string;
index: number;
changePaletteColor: (v: string, i: number) => void;
removePalette: (i: number) => void;
handleLegendPosChange: (i: number, type: boolean) => void;
}

const LabColorPicker: React.FC<Props> = ({
color,
index,
changePaletteColor,
removePalette,
handleLegendPosChange
}) => {
const [open, setOpen] = React.useState(false);
const [p, setP] = React.useState(color);
const ref = React.useRef<React.LegacyRef<HTMLDivElement>>();
// @ts-ignore
useClickAway(ref, () => changePaletteColor(p, index));
return (
<div className="picker-ctx relative">
<div
// @ts-ignore
ref={ref}
className="absolute picker"
style={{ display: `${open ? 'block' : 'none'}` }}>
<HexColorPicker color={color} onChange={(e) => setP(e)} />
</div>
<div className="flex items-center justify-between">
<div
className="color-box "
style={{ backgroundColor: color }}
onClick={() => setOpen(!open)}
/>
<Input size="mini" className="input" type="text" value={color} />
<div className="cross-icon pointer" onClick={() => removePalette(index)}>
<XCircle />
</div>
<div className="flex-center flex-col up-down pointer">
<ChevronUp onClick={() => handleLegendPosChange(index, true)} />
<ChevronDown onClick={() => handleLegendPosChange(index, false)} />
</div>
</div>
<style jsx>{`
.color-box {
margin-right: 1rem;
width: 25px;
height: 25px;
border: 1px solid #333;
border-radius: 5px;
cursor: pointer;
}
.picker-ctx {
margin: 0.5rem 0;
}
.up-down {
opacity: 0.6;
height: 30px;
}
.up-down:hover {
opacity: 1;
}
.picker {
z-index: 100;
background-color: #111;
border: 1px solid #333;
padding: 1rem;
border-radius: 5px;
top: 40px;
left: 0px;
}
.cross-icon:hover {
opacity: 1;
}
.cross-icon {
opacity: 0.6;
}
`}</style>
</div>
);
};

export default LabColorPicker;
329 changes: 329 additions & 0 deletions labs/usa.map.tsx

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions labs/utils/createRandomData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const createRandomData = (obj : {[key: string]: string}): {[key: string]: number} => {
const data = {};
Object.keys(obj).forEach((e) => {
// @ts-ignore
data[e] = Math.floor(Math.random() * 10000);
});
return data;
}

export default createRandomData;
11 changes: 11 additions & 0 deletions labs/utils/getLegendList.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const getLegendList = (sortObj: { [key: string]: number } , count: number): number[] => {
const endVal = Object.values(sortObj)[Object.values(sortObj).length - 1];
const lastLegend = Math.pow(10, endVal.toString().length);
const legendList: number[] = [];
for (let i = 1; i <= count; i++) {
legendList.push(i * (lastLegend / count));
}
return legendList
};

export default getLegendList;
34 changes: 34 additions & 0 deletions labs/utils/getMapData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
interface Props {
sortedData: { [key: string]: number };
legendList: number[];
paletteData: string[]
}

const getMapData= ({ sortedData , legendList ,paletteData }: Props) => {
const mapData: {fill: string , code: string , hide: boolean, val: number}[] = [];
const closest = (t: number) =>
legendList.reduce((prev, curr) => Math.abs(curr - t) < Math.abs(prev - t) ? curr : prev);
Object.keys(sortedData).forEach((e) => {
const val = sortedData[e];
const closestVal = closest(val);
const idx = legendList.indexOf(closestVal);
if (val > closestVal) {
mapData.push({
fill: paletteData[idx + 1],
code: e,
hide: false,
val,
});
} else {
mapData.push({
fill: paletteData[idx],
code: e,
hide: false,
val,
});
}
});
return mapData;
}

export default getMapData
10 changes: 10 additions & 0 deletions labs/utils/getPaletteData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import Gradient from 'javascript-color-gradient';

const colorGradient = new Gradient();

const getPaletteData = (count: number , colorList: string[]) => {
const paletteData = colorGradient.setGradient(...colorList).setMidpoint(count).getArray();
return paletteData;
};

export default getPaletteData;
4 changes: 4 additions & 0 deletions labs/utils/sortObject.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
const sortObject = (d : {[key: string]: number}): {[key: string]: number}=> Object.entries(d)
.sort(([, a], [, b]) => a - b)
.reduce((r, [k, v]) => ({ ...r, [k]: v }), {})
export default sortObject;
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
"@mdx-js/loader": "^1.6.22",
"@next/mdx": "^10.2.3",
"inter-ui": "^3.18.1",
"javascript-color-gradient": "^1.3.2",
"jotai": "^0.16.0",
"jspdf": "^2.3.1",
"next-seo": "^4.23.0",
Expand Down
177 changes: 177 additions & 0 deletions pages/labs/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
import { UsaStateCodes } from '@/data/Usa/UsaStateCodes';
import LabColorPicker from '@/labs/components/LabColorPicker';
import createRandomData from '@/labs/utils/createRandomData';
import getLegendList from '@/labs/utils/getLegendList';
import getMapData from '@/labs/utils/getMapData';
import getPaletteData from '@/labs/utils/getPaletteData';
import sortObject from '@/labs/utils/sortObject';
import MainLayout from '@/layouts/MainLayout';
import { LabMapStoreType } from '@/typings/lab.store';
import { Button, Input, Spacer } from '@geist-ui/react';
import UsaMap from 'labs/usa.map';
import React from 'react';

const reOrderArrayElements = (arr: string[], val: string, oldIdx: number, newIdx: number) => {
// remove it
arr.splice(oldIdx, 1);
// add it
arr.splice(newIdx, 0, val);
return arr;
};

const Lab = () => {
const [data, setData] = React.useState<LabMapStoreType>({
mapData: [],
count: 10,
paletteArr: ['#f9d56e', '#ff1e56']
});
const changePaletteColor = (v: string, i: number) => {
const copy = data.paletteArr;
copy[i] = v;
setData((st) => ({
...st,
paletteArr: copy
}));
};
const addPalette = () => {
const el = document.getElementById('add-palette');
if (el) {
const copy = data.paletteArr;
// @ts-ignore
copy.push(el.value);
setData((st) => ({
...st,
paletteArr: copy
}));
}
};
const removePalette = (i: number) => {
const copy = data.paletteArr;
copy.splice(i, 1);
setData((st) => ({
...st,
paletteArr: copy
}));
};
const handleLegendPosChange = (idx: number, up: boolean) => {
const len = data.paletteArr.length;
const copy = data.paletteArr;
if (up) {
if (idx === 0) {
reOrderArrayElements(copy, copy[idx], idx, len - 1);
} else {
reOrderArrayElements(copy, copy[idx], idx, idx - 1);
}
} else if (!up) {
if (idx === len - 1) {
reOrderArrayElements(copy, copy[idx], idx, 0);
} else {
reOrderArrayElements(copy, copy[idx], idx, idx + 1);
}
}
// @ts-ignore
setData((prev) => ({
...prev,
paletteArr: copy
}));
};
const getRandomData = () => {
const randData = createRandomData(UsaStateCodes);
const sortedData = sortObject(randData);
const legendList = getLegendList(sortedData, data.count);
const paletteData = getPaletteData(data.count, data.paletteArr);
const mapData = getMapData({
sortedData,
legendList,
paletteData
});
mapData.forEach((e) => {
const el = document.getElementById(e.code);
if (el) {
el.style.fill = e.fill;
}
});
setData({
mapData,
count: 10,
paletteArr: data.paletteArr
});
};
data.mapData.forEach((e) => {
const el = document.getElementById(e.code);
if (el) {
el.style.fill = e.fill;
}
});
return (
<MainLayout>
<div className="flex justify-between container items-start">
<div className="flex flex-col">
<Button onClick={() => getRandomData()}>Random Data</Button>
{data.paletteArr.map((e, i) => (
<LabColorPicker
key={e}
index={i}
color={e}
changePaletteColor={changePaletteColor}
removePalette={removePalette}
handleLegendPosChange={handleLegendPosChange}
/>
))}
<div className="flex items-center my-2">
<Input size="small" id="add-palette" placeholder="Hex Code" />
<Spacer inline x={0.5} />
<Button auto size="small" onClick={() => addPalette()}>
Add
</Button>
</div>
<Input
type="number"
value={data.count.toString()}
onChange={(e) =>
setData((p) => ({
...p,
count: +e.target.value
}))
}
/>
<div className="tb-ctx my-2">
<table className="table">
<thead>
<tr>
<th>Code</th>
<th>Name</th>
<th>Value</th>
</tr>
</thead>
<tbody>
{data.mapData.map((e) => (
<tr key={e.code}>
<td>{e.code}</td>
{/* @ts-ignore */}
<td>{UsaStateCodes[e.code]}</td>
<td>{e.val}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
<UsaMap />
</div>
<style jsx>{`
.items-start {
margin: 40px 0;
align-items: flex-start;
}
.tb-ctx {
width: 300px;
overflow-y: scroll;
height: 50vh;
}
`}</style>
</MainLayout>
);
};

export default Lab;
9 changes: 9 additions & 0 deletions store/lab.store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

import { LabMapStoreType } from '@/typings/lab.store'
import { atom } from 'jotai'

export const labAtom = atom<LabMapStoreType>({
mapData: [],
count: 10,
paletteArr: ['red','blue']
})
Loading