<div id="root">
</div>
.CircleSelect
{
border-radius: 50%;
background-color: #F8E600;
display: flex;
justify-content: center;
align-items: center;
float: left;
border-color: black;
border: thick solid;
}
.CircleSelectItem
{
font-size: 20pt;
font-weight: 800;
}
.CircleSelectItem:hover
{
color: #F8E600;
}
function CircleSelectItem(params) {
let angle = params.index * (360 / params.N);
let x = params.x0 + Math.floor(2 * params.radius * Math.sin(Math.PI * 2 * angle / 360));
let y = params.y0 + Math.floor(2 * params.radius * Math.cos(Math.PI * 2 * angle / 360));
let xSideCoefficient = 0;
let ySideCoefficient = 0;
if (Math.abs(params.x0 - x) > 1 || Math.abs(params.y0 - y) > 1) {
if (x < params.x0)
xSideCoefficient = -1;
if (x > params.x0)
xSideCoefficient = 0;
ySideCoefficient = -1;
}
if (Math.abs(params.x0 - x) < 5) {
if (params.y0 < y)
ySideCoefficient = 5;
xSideCoefficient = -1 / 3;
}
return (
<>
<div style={{ left: x + xSideCoefficient * 100, top: y + ySideCoefficient * 5, position: 'absolute' }} className="CircleSelectItem" onClick={(e) => { params.handleSelect(e) }}>
{params.value}
</div>
</>
);
}
function Lines(params) {
let angle = params.index * (360 / params.N);
let x1 = params.x0 + Math.floor(params.radius * Math.sin(Math.PI * 2 * angle / 360));
let y1 = params.y0 + Math.floor(params.radius * Math.cos(Math.PI * 2 * angle / 360));
let x2 = params.x0 + Math.floor(2 * params.radius * Math.sin(Math.PI * 2 * angle / 360));
let y2 = params.y0 + Math.floor(2 * params.radius * Math.cos(Math.PI * 2 * angle / 360));
let sideCoefficient = 0;
if (params.x0 !== x1 || params.y0 !== y1) {
if (x1 < params.x0)
sideCoefficient = -1;
if (x1 > params.x0)
sideCoefficient = 1;
}
return (
<>
<line x1={params.x0} y1={params.y0} x2={x2} y2={y2} stroke="black" stroke-width="5" />
<line x1={x2} y1={y2} x2={x2 + sideCoefficient * 100} y2={y2} stroke="black" stroke-width="5" />
</>
);
}
function CircleSelect(params) {
let radius = Math.floor(params.size / 2);
let x0 = params.x0 + radius;
let y0 = params.y0 + radius;
const [selectedItems, setSelectedItems] = React.useState([]);
const handleSelect = (e) => {
let newArray = selectedItems.slice();
let value = e.target.innerHTML
if (newArray.includes(value)) {
const index = newArray.indexOf(value);
if (index > -1) {
newArray.splice(index, 1);
}
}
else { newArray.push(value); }
setSelectedItems(newArray)
}
return (
<>
<div className="CircleSelect" style={{ width: params.size, height: params.size, left: params.x0, top: params.y0, position: 'absolute' }}>
<h1 className="Centroid-title">Select</h1>
</div>
{params.data.map((value, index) => <CircleSelectItem handleSelect={handleSelect} x0={x0} y0={y0} radius={radius} index={index} value={value} N={params.data.length} />)}
<svg width="1920" height="250">
{params.data.map((value, index) => <Lines x0={x0} y0={y0} radius={radius} index={index} value={value} N={params.data.length} />)}
</svg>
Выбраны следующие элементы:
<ul>
{selectedItems.map((value) => <li>{value}</li>)}
</ul>
</>
);
}
function Content() {
const [data, setData] = React.useState(Array.from(new Array(6), (val, index) => "Option " + index));
return (
<>
<input type="number" placeholder="Количество опций" onChange={(e) => { setData(Array.from(new Array(Number.parseInt(e.target.value)), (val, index) => "Option " + index)) }} />
<CircleSelect data={data} size={100} x0={350} y0={60} />
</>
)
}
ReactDOM.render(
<Content />,
document.getElementById('root')
);
View Compiled
This Pen doesn't use any external CSS resources.