Javascript 有没有办法在ThreeJs中使用dat.gui.js构建范围滑块?
我想在我的设计中有一个范围滑块,虽然我有一个数字滑块,但我想有一个我可以选择一个数字范围来传递,如下图所示。Javascript 有没有办法在ThreeJs中使用dat.gui.js构建范围滑块?,javascript,three.js,dat.gui,Javascript,Three.js,Dat.gui,我想在我的设计中有一个范围滑块,虽然我有一个数字滑块,但我想有一个我可以选择一个数字范围来传递,如下图所示。 除了在dat.gui.js文件中进行更改并为范围滑块添加功能之外,还有其他选择吗?没有,这是不可能的。控制器的创建仅基于所创建的值类型。您必须破解它,发出拉请求,或者只使用两个滑块(最小/最大)。我在React中实现了一个dat gui范围滑块,看起来很像(使用材质ui)。也许这会帮助一些人尝试创建他们自己的,所以我想我会把它贴在这里 import React,{useffect,us
除了在dat.gui.js文件中进行更改并为范围滑块添加功能之外,还有其他选择吗?没有,这是不可能的。控制器的创建仅基于所创建的值类型。您必须破解它,发出拉请求,或者只使用两个滑块(最小/最大)。我在React中实现了一个dat gui范围滑块,看起来很像(使用材质ui)。也许这会帮助一些人尝试创建他们自己的,所以我想我会把它贴在这里
import React,{useffect,useRef,useCallback}来自“React”;
从“类名称”导入cx;
从“@material ui/core”导入{makeStyles,Theme,createStyles};
从“lodash/clamp”进口夹具;
从“utils/useEventCallback”导入useEventCallback;
功能asc(a:编号,b:编号){
返回a-b;
}
函数findClosest(值:any,currentValue:number){
const{index:closestinex}=values.reduce((acc:{distance:number;}}| null,value:number,index:number)=>{
常数距离=数学绝对值(currentValue-value);
if(acc==null | |距离({left:`${percent}%`}),
闰:(百分比:数字)=>({width:`${percent}%`}),
};
const trackMouse=(event:React.MouseEvent)=>({x:event.clientX,y:event.clientY,});
const useStyles=makeStyles((主题:主题)=>
创建样式({
根目录:{
宽度:“100%”,
框大小:“边框框”,
显示:“内联块”,
光标:“ew resize”,
touchAction:'无',
边框:“3px实心#1a1a1a”,
},
滑块:{
显示:“块”,
位置:'相对',
背景颜色:“#141414”,
背景图片:`线性渐变(90度,${theme.palete.primary.light},${theme.palete.primary.light})`,//#2fa1d6,#2fa1d6)`,
背景重复:“不重复”,
高度:“14px”,
},
})
)
界面道具{
数值:数字[];
min:编号;
最大:数量;
步骤:编号;
类名?:字符串;
颜色?:字符串;
默认值?:数字[];
禁用?:布尔值;
onChange?:(事件:React.MouseEvent,值:any)=>void;
onChangeCommitted?:(事件:React.MouseEvent,值:any)=>void;
onMouseDown?:(事件:React.MouseEvent)=>void;
}
导出默认函数范围滑块({
类名,
颜色='主',
默认值,
禁用=错误,
最大值,
闵,
一旦改变,
一旦承诺,
一下楼,
步
值:valuesProp,
……其他
}:道具){
const classes=useStyles();
常量sliderRef=useRef();
const previousIndex=useRef();
let values=[…valuesProp].sort(asc);
值=值。映射((值:数字)=>钳制(值、最小值、最大值));
const getNewValue=useCallback(
({mouse,move=false,value:values2,source})=>{
const{current:slider}=sliderRef;
const{width,left}=slider.getBoundingClientRect();
常量百分比=(mouse.x-left)/宽度;
让新价值;
newValue=percentToValue(百分比、最小值、最大值);
newValue=roundValueToStep(newValue,step);
新值=夹具(新值、最小值、最大值);
设activeIndex=0;
如果(!移动){
activeIndex=findClosest(值2,新值);
}否则{
activeIndex=previousIndex.current;
}
const previousValue=newValue;
newValue=setValueIndex({
值:值2,
来源:,
新价值,
索引:activeIndex,
}).分类(asc);
activeIndex=newValue.indexOf(以前的值);
previousIndex.current=活动索引;
返回{newValue,activeIndex};
},
[最大、最小、步长]
);
const handleMouseMove=useEventCallback((事件:React.MouseEvent)=>{
const mouse=trackMouse(事件);
常量{newValue}=getNewValue({
老鼠
搬家:没错,
价值观
资料来源:valuesProp,
});
if(onChange){
onChange(事件,newValue);
}
});
康斯塔
import React, { useEffect, useRef, useCallback } from 'react';
import cx from 'classnames';
import { makeStyles, Theme, createStyles } from '@material-ui/core';
import clamp from 'lodash/clamp';
import useEventCallback from 'utils/useEventCallback';
function asc(a: number, b: number) {
return a - b;
}
function findClosest(values: any, currentValue: number) {
const { index: closestIndex } = values.reduce((acc: { distance: number; } | null, value: number, index: number) => {
const distance = Math.abs(currentValue - value);
if (acc === null || distance < acc.distance || distance === acc.distance) {
return {
distance,
index,
};
}
return acc;
}, null);
return closestIndex;
}
function valueToPercent(value: number, min: number, max: number) {
return ((value - min) * 100) / (max - min);
}
function percentToValue(percent: number, min: number, max: number) {
return (max - min) * percent + min;
}
function getDecimalPrecision(num: number) {
// This handles the case when num is very small (0.00000001), js will turn this into 1e-8.
// When num is bigger than 1 or less than -1 it won't get converted to this notation so it's fine.
if (Math.abs(num) < 1) {
const parts = num.toExponential().split('e-');
const matissaDecimalPart = parts[0].split('.')[1];
return (
(matissaDecimalPart ? matissaDecimalPart.length : 0) +
parseInt(parts[1], 10)
);
}
const decimalPart = num.toString().split('.')[1];
return decimalPart ? decimalPart.length : 0;
}
function roundValueToStep(value: number, step: number) {
const nearest = Math.round(value / step) * step;
return Number(nearest.toFixed(getDecimalPrecision(step)));
}
function setValueIndex({ values, source, newValue, index }: any) {
// Performance shortcut
if (values[index] === newValue) {
return source;
}
const output = [...values];
output[index] = newValue;
return output;
}
const axisProps = {
offset: (percent: number) => ({ left: `${percent}%` }),
leap: (percent: number) => ({ width: `${percent}%` }),
};
const trackMouse = (event: React.MouseEvent) => ({ x: event.clientX, y: event.clientY, });
const useStyles = makeStyles((theme: Theme) =>
createStyles({
root: {
width: '100%',
boxSizing: 'border-box',
display: 'inline-block',
cursor: 'ew-resize',
touchAction: 'none',
border: '3px solid #1a1a1a',
},
slider: {
display: 'block',
position: 'relative',
backgroundColor: '#141414',
backgroundImage: `linear-gradient(90deg, ${theme.palette.primary.light}, ${theme.palette.primary.light})`, //#2fa1d6, #2fa1d6)",
backgroundRepeat: 'no-repeat',
height: '14px',
},
})
)
interface Props {
values: number[];
min: number;
max: number;
step: number;
className?: string;
color?: string;
defaultValue?: number[];
disabled?: boolean;
onChange?: (event: React.MouseEvent, value: any) => void;
onChangeCommitted?: (event: React.MouseEvent, value: any) => void;
onMouseDown?: (event: React.MouseEvent) => void;
}
export default function RangeSlider({
className,
color = 'primary',
defaultValue,
disabled = false,
max,
min,
onChange,
onChangeCommitted,
onMouseDown,
step,
values: valuesProp,
...other
}: Props) {
const classes = useStyles();
const sliderRef = useRef<any>();
const previousIndex = useRef<any>();
let values = [...valuesProp].sort(asc);
values = values.map((value: number) => clamp(value, min, max));
const getNewValue = useCallback(
({ mouse, move = false, values: values2, source }) => {
const { current: slider } = sliderRef;
const { width, left } = slider.getBoundingClientRect();
const percent = (mouse.x - left) / width;
let newValue;
newValue = percentToValue(percent, min, max);
newValue = roundValueToStep(newValue, step);
newValue = clamp(newValue, min, max);
let activeIndex = 0;
if (!move) {
activeIndex = findClosest(values2, newValue);
} else {
activeIndex = previousIndex.current;
}
const previousValue = newValue;
newValue = setValueIndex({
values: values2,
source,
newValue,
index: activeIndex,
}).sort(asc);
activeIndex = newValue.indexOf(previousValue);
previousIndex.current = activeIndex;
return { newValue, activeIndex };
},
[max, min, step]
);
const handleMouseMove = useEventCallback((event: React.MouseEvent) => {
const mouse = trackMouse(event);
const { newValue } = getNewValue({
mouse,
move: true,
values,
source: valuesProp,
});
if (onChange) {
onChange(event, newValue);
}
});
const handleMouseEnter = useEventCallback((event: React.MouseEvent) => {
// If the slider was being interacted with but the mouse went off the window
// and then re-entered while unclicked then end the interaction.
if (event.buttons === 0) {
handleMouseEnd(event);
}
});
const handleMouseEnd = useEventCallback((event: React.MouseEvent) => {
const mouse = trackMouse(event);
const { newValue } = getNewValue({
mouse,
values,
source: valuesProp,
});
if (onChangeCommitted) {
onChangeCommitted(event, newValue);
}
window.removeEventListener('mousemove', handleMouseMove);
window.removeEventListener('mouseup', handleMouseEnd);
window.removeEventListener('mouseenter', handleMouseEnter);
});
useEffect(() => {
return () => {
window.removeEventListener('mousemove', handleMouseMove);
window.removeEventListener('mouseup', handleMouseEnd);
window.removeEventListener('mouseenter', handleMouseEnter);
};
}, [disabled, handleMouseEnter, handleMouseEnd, handleMouseMove]);
const handleMouseDown = useEventCallback((event: React.MouseEvent) => {
if (onMouseDown) {
onMouseDown(event);
}
if (disabled) {
return;
}
event.preventDefault();
const mouse = trackMouse(event);
const { newValue } = getNewValue({
mouse,
values,
source: valuesProp,
});
if (onChange) {
onChange(event, newValue);
}
window.addEventListener('mousemove', handleMouseMove);
window.addEventListener('mouseenter', handleMouseEnter);
window.addEventListener('mouseup', handleMouseEnd);
});
const sliderOffset = valueToPercent(values[0], min, max);
const sliderLeap = valueToPercent(values[values.length - 1], min, max) - sliderOffset;
const widthBackground = axisProps.leap(sliderLeap).width;
const sliderStyle = {
...axisProps.offset(sliderOffset),
...axisProps.leap(sliderLeap),
backgroundSize: `${widthBackground}% 100%`,
};
return (
<span
ref={sliderRef}
className={cx(classes.root, className)}
onMouseDown={handleMouseDown}
{...other}
>
<span className={classes.slider} style={sliderStyle} />
{values.map((value, index) => {
const percent = valueToPercent(value, min, max);
const style = axisProps.offset(percent);
return (
<span
key={index}
role="slider"
style={style}
data-index={index}
/>
);
})}
</span>
);
}
RangeSlider.defaultProps = {
min: 0,
max: 100,
step: 1
}