Commit a0d00443 authored by zhushengjie's avatar zhushengjie

色彩转换

parent 5233fb98
......@@ -112,3 +112,15 @@
height: 200rpx;
}
}
.modal {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 400rpx;
height: 200rpx;
color: white;
border-radius: 20rpx;
background-color: #1f1f1f;
}
\ No newline at end of file
import React, { useState } from 'react';
import { utils } from '@ray-js/panel-sdk';
import { getElementById } from '@ray-js/api';
import { View, Text, Slider, Image, usePageEvent } from '@ray-js/ray';
import { hsvToDpdata, dpdataToHsv, temperatureToRgb } from '@/utils';
import { useAtomValue, useSetAtom } from 'jotai';
import { ColorData, colorDataAtom, selectColorDataAtom } from '@/atoms';
import { View, Text, Slider, Image, Modal } from '@ray-js/ray';
import styles from './index.module.less';
import { Props } from './index.type';
import imgs from '../../res';
......@@ -11,7 +14,11 @@ type colorItem = Record<string, any>;
const HubCircle: React.FC<Props> = props => {
const dpState = props.DpStateData;
const codeMap = props.DpCodesMap;
const { hsv2rgb, rgb2hex } = utils;
const setColorStateAtom = useSetAtom(colorDataAtom);
const colorStateInAtom = useAtomValue(selectColorDataAtom);
const { hsv2rgbString, rgb2hex, rgb2hsv } = utils;
// document.getElementById;
const dataSourse = {
isDrag: false,
......@@ -46,9 +53,11 @@ const HubCircle: React.FC<Props> = props => {
circle_r: 100, // 圆形外半径(容器宽度/2)
circle_b: 42, // 圆形边距
bar_r: 21, // 小球半径(圆形边距/2)
bar_c_r: 100 - 21, // 小球轨迹半径(圆形边距/2)
};
const [addFlag, setAddFlag] = useState(true);
const [modalShow, setModalShow] = useState(false);
const [colorArr, setColorArr] = useState<colorItem[]>([
{ temp_value: 100, bright_value: 100, color: '#CEEDFE', active: false },
......@@ -62,18 +71,35 @@ const HubCircle: React.FC<Props> = props => {
tempshow: (6500 - 2700) / 2 + 2700, // 色温展示
nowColor: '#FFE2A4', // 当前颜色
});
// 442
const circleLocationOrigin = (tempValue: number) => {
let rad;
let left = 79;
let top = 0;
if (tempValue >= 500) {
rad = ((tempValue - 500) * (dataSourse.angleLimit / 500) * Math.PI) / 180;
const y = dataSourse.bar_c_r * Math.cos(rad);
const x = dataSourse.bar_c_r * Math.sin(rad);
left = left - dataSourse.bar_r + x;
top = dataSourse.circle_r - y - dataSourse.bar_r;
}
if (tempValue < 500) {
rad = (tempValue * (dataSourse.angleLimit / 500) * Math.PI) / 180;
const x = dataSourse.bar_c_r * Math.cos(rad);
const y = dataSourse.bar_c_r * Math.cos(rad);
left = left + dataSourse.bar_r - x;
top = dataSourse.circle_r - y - dataSourse.bar_r;
}
return {
left,
top,
};
};
const [circleLocation, setCircleLocation] = useState({
// 小球位置
left: 79,
top: 0,
});
usePageEvent('onShow', () => {
console.log('=== home onShow');
getElementById('circleContent').then(res => {
console.log(res, 'res');
});
left: circleLocationOrigin(dpState.temp_value).left,
top: circleLocationOrigin(dpState.temp_value).top,
});
const toParseInt = (value: number): number => {
......@@ -107,19 +133,9 @@ const HubCircle: React.FC<Props> = props => {
setAddFlag(false);
return;
}
const h = 0;
const s = toParseInt(
(dpState.bright_value /
(codeMap.bright_value.property.max - codeMap.bright_value.property.min)) *
100
);
const v = toParseInt(
(dpState.bright_value /
(codeMap.bright_value.property.max - codeMap.bright_value.property.min)) *
100
);
const color = hsv2rgb(h, s, v);
const nowColor = rgb2hex(color[0], color[1], color[2]);
const colorRgb = temperatureToRgb(dataState.tempshow);
const colorHsv = rgb2hsv(colorRgb[0], colorRgb[1], colorRgb[2]);
const nowColor = hsv2rgbString(colorHsv[0], colorHsv[1], colorHsv[2], 1);
setDataState({
...dataState,
......@@ -137,7 +153,7 @@ const HubCircle: React.FC<Props> = props => {
});
if (flag) {
// setAddFlag(true);
setModalShow(true);
return;
}
......@@ -148,6 +164,7 @@ const HubCircle: React.FC<Props> = props => {
const handleBarTouch = (e: any) => {
e.origin.stopPropagation();
setColorStateAtom({ ifDrag: true });
// 移动距离:小球的坐标位置-容器的偏移位置-小球相对容器的偏移位置-小球半径
const mouse_offset_x =
e.origin.touches[0].clientX -
......@@ -198,6 +215,13 @@ const HubCircle: React.FC<Props> = props => {
});
};
const handleBarEnd = () => {
setColorStateAtom({ ifDrag: false });
const dpValue = getTempDpValue(dataState.angleValue, dataState.angleShow);
console.log(dpValue);
props.onSetDpState('temp_value', dpValue);
};
const updateContent = (radian: number) => {
let angle = radian * (180 / Math.PI); // -180 ~ 180
if (angle >= -180 && angle <= 90) {
......@@ -213,6 +237,8 @@ const HubCircle: React.FC<Props> = props => {
const { angleLimit } = dataSourse;
const tempshow = getTempshow(angleValue);
if (angleShow > angleLimit) {
dataSourse.isDrag = false;
return;
......@@ -221,6 +247,17 @@ const HubCircle: React.FC<Props> = props => {
dataSourse.isDrag = true;
}
setDataState({
...dataState,
angleValue,
angleShow,
tempshow,
});
};
const getTempshow = (angleValue: number): number => {
const { angleLimit } = dataSourse;
const angleShow = angleValue > 180 ? 360 - angleValue : angleValue;
const tempStart = dataSourse.tempValue[0];
const tempEnd = dataSourse.tempValue[1];
......@@ -234,13 +271,24 @@ const HubCircle: React.FC<Props> = props => {
}
tempshow = Math.floor(tempshow);
return tempshow;
};
setDataState({
...dataState,
angleValue,
angleShow,
tempshow,
});
const getTempDpValue = (angleValue, angleShow) => {
const { angleLimit } = dataSourse;
let tempDpshow = 500; // 中间值 角度对应0
if (angleValue < 180) {
tempDpshow += (500 / angleLimit) * angleShow;
}
if (angleValue > 180) {
tempDpshow -= (500 / angleLimit) * angleShow;
}
return Math.floor(tempDpshow);
};
const handleModalChange = (flag = false) => {
setModalShow(flag);
};
return (
......@@ -257,9 +305,11 @@ const HubCircle: React.FC<Props> = props => {
top: `${circleLocation.top}px`,
width: `${dataSourse.bar_r * 2}px`,
height: `${dataSourse.bar_r * 2}px`,
transform: `translateX(${translateX}px) translateY(${translateY}px)`,
}}
onTouchStart={handleBarTouch}
onTouchMove={handleBarMove}
onTouchEnd={handleBarEnd}
/>
</View>
</View>
......@@ -324,9 +374,27 @@ const HubCircle: React.FC<Props> = props => {
<View className={styles.addStyle}>+</View>
</View>
)}
<View className={styles.colorCircle} style={{ backgroundColor: dataState.nowColor }} />
</View>
</View>
<Modal
show={modalShow}
position="center"
overlay
onClickOverlay={() => {
handleModalChange(false);
}}
>
<View className={styles.modal}>
<View>已有相同颜色</View>
<View
onClick={() => {
handleModalChange(false);
}}
>
确定
</View>
</View>
</Modal>
</View>
);
};
......
......@@ -113,6 +113,18 @@
}
}
.modal {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 400rpx;
height: 200rpx;
color: white;
border-radius: 20rpx;
background-color: #1f1f1f;
}
// .header {
// display: flex;
// // align-items: center;
......
import React, { useState } from 'react';
import { utils } from '@ray-js/panel-sdk';
import { hsvToDpdata, dpdataToHsv } from '@/utils';
import { useAtomValue, useSetAtom } from 'jotai';
import { ColorData, colorDataAtom, selectColorDataAtom } from '@/atoms';
import { View, Text, Slider, Image } from '@ray-js/ray';
import { View, Text, Slider, Image, Modal, Button } from '@ray-js/ray';
import styles from './index.module.less';
import { Props } from './index.type';
import imgs from '../../res';
......@@ -16,6 +17,11 @@ const HubCircle: React.FC<Props> = props => {
const setColorStateAtom = useSetAtom(colorDataAtom);
const colorStateInAtom = useAtomValue(selectColorDataAtom);
const { hsv2rgb, rgb2hex, hsv2rgbString } = utils;
const Hue = dpdataToHsv(dpState.colour_data)[0];
const Temp_value = dpdataToHsv(dpState.colour_data)[1];
const Bright_value = dpdataToHsv(dpState.colour_data)[2];
// document.getElementById;
const dataSourse = {
containerWidth: 400,
......@@ -46,6 +52,7 @@ const HubCircle: React.FC<Props> = props => {
};
const [addFlag, setAddFlag] = useState(true);
const [modalShow, setModalShow] = useState(false);
const [colorArr, setColorArr] = useState<colorItem[]>([
{ hue: 0, temp_value: 1000, bright_value: 1000, color: hueToColor(0), active: false },
......@@ -54,10 +61,10 @@ const HubCircle: React.FC<Props> = props => {
]);
const [dataState, setDataState] = useState({
hue: 90, // 角度展示 0 ~ 180
hue: Hue, // 角度展示 0 ~ 180
temp_value: 500,
bright_value: 500,
nowColor: hueToColor(90), // 当前颜色
nowColor: hueToColor(Hue), // 当前颜色
});
const [circleLocation, setCircleLocation] = useState({
......@@ -72,6 +79,9 @@ const HubCircle: React.FC<Props> = props => {
const handleCirleClick = (e: any, item: colorItem): void => {
e.origin.stopPropagation();
const dpValue = hsvToDpdata(dataState.hue, dataState.temp_value, dataState.bright_value);
console.log(dpValue);
props.onSetDpState('colour_data', dpValue);
const index = colorArr.findIndex(el => {
return (
item.hue === el.hue &&
......@@ -124,7 +134,7 @@ const HubCircle: React.FC<Props> = props => {
});
if (flag) {
// setAddFlag(true);
setModalShow(true);
return;
}
......@@ -214,6 +224,8 @@ const HubCircle: React.FC<Props> = props => {
if (type === 'temp_value') {
const temp_value = e.value;
const nowColor = hueToColor(dataState.hue, temp_value / 10, dataState.bright_value / 9.9);
const dpValue = hsvToDpdata(dataState.hue, temp_value, dataState.bright_value);
props.onSetDpState('colour_data', dpValue);
setDataState({
...dataState,
temp_value,
......@@ -223,6 +235,8 @@ const HubCircle: React.FC<Props> = props => {
if (type === 'bright_value') {
const bright_value = e.value;
const nowColor = hueToColor(dataState.hue, dataState.temp_value / 10, bright_value / 9.9);
const dpValue = hsvToDpdata(dataState.hue, dataState.temp_value, bright_value);
props.onSetDpState('colour_data', dpValue);
setDataState({
...dataState,
bright_value,
......@@ -231,8 +245,14 @@ const HubCircle: React.FC<Props> = props => {
}
};
const handleModalChange = (flag = false) => {
setModalShow(flag);
};
const handleBarEnd = () => {
setColorStateAtom({ ifDrag: false });
const dpValue = hsvToDpdata(dataState.hue, dataState.temp_value, dataState.bright_value);
props.onSetDpState('colour_data', dpValue);
};
return (
......@@ -275,13 +295,11 @@ const HubCircle: React.FC<Props> = props => {
min={0}
max={1000}
step={1}
value={dataState.temp_value}
value={Temp_value}
onChange={e => handleStateChange('temp_value', e)}
/>
</View>
<Text className={styles.SliderValue}>
{toParseInt((dataState.temp_value / 1000) * 100)}%
</Text>
<Text className={styles.SliderValue}>{toParseInt((Temp_value / 1000) * 100)}%</Text>
</View>
<View className={styles.configList}>
<Image src={imgs.icon_ld} className={styles.icoImg} />
......@@ -292,13 +310,11 @@ const HubCircle: React.FC<Props> = props => {
min={10}
max={1000}
step={1}
value={dataState.bright_value}
value={Bright_value}
onChange={e => handleStateChange('bright_value', e)}
/>
</View>
<Text className={styles.SliderValue}>
{toParseInt((dataState.bright_value / 990) * 100)}%
</Text>
<Text className={styles.SliderValue}>{toParseInt((Bright_value / 990) * 100)}%</Text>
</View>
<View className={styles.configList}>
{colorArr.map(item => (
......@@ -318,6 +334,25 @@ const HubCircle: React.FC<Props> = props => {
)}
</View>
</View>
<Modal
show={modalShow}
position="center"
overlay
onClickOverlay={() => {
handleModalChange(false);
}}
>
<View className={styles.modal}>
<View>已有相同颜色</View>
<View
onClick={() => {
handleModalChange(false);
}}
>
确定
</View>
</View>
</Modal>
</View>
);
};
......
......@@ -24,6 +24,7 @@
}
.tabItemActive {
color: #43aaff;
margin: 0 50rpx;
}
}
.tabContent {
......@@ -31,6 +32,7 @@
}
}
.subtract {
position: relative;
border-radius: 20rpx 20rpx 0 0;
height: @subtractHeight;
background-color: rgba(255, 255, 255, 0.2);
......@@ -48,8 +50,8 @@
position: absolute;
border: 4px solid rgba(0, 0, 0, 0.8);
z-index: 500;
left: calc(50% - 40px);
bottom: 100rpx;
left: calc(50% - 30px);
top: -30px;
}
.switchActive {
......@@ -57,6 +59,6 @@
}
.CombinedShape {
width:40px;
width: 40px;
height: 40px;
}
......@@ -5,7 +5,7 @@ import { DpState, dpStateAtom, selectDpStateAtom } from '@/atoms';
import { getDpStateMapByDevInfo, mapDpsMapToDpStateMap, getDpCodeMapByDevInfo } from '@/utils';
import { ScrollView, View, Text, Image } from '@ray-js/components';
import HubCircle from '@/components/hubCircle';
import HubColorCircle from '@/components/hubColorCircle/index2/index1';
import HubColorCircle from '@/components/hubColorCircle/index';
import { hooks, kit } from '@ray-js/panel-sdk';
import styles from './index.module.less';
import imgs from '../../res';
......@@ -25,9 +25,9 @@ export function Home() {
const handleDpDataChange: DpDataChangeHandler = data => {
const initalDevInfo = getDevInfo();
// 转化为 dpState 格式
const newDpState = mapDpsMapToDpStateMap(data.dps, initalDevInfo) as DpState;
console.log(newDpState, '123', dpState);
// {switch: true} 输出更改的值
setDpStateAtom(newDpState);
};
......@@ -35,11 +35,10 @@ export function Home() {
useEffect(() => {
// 绑定设备
initDevInfo().then(initalDevInfo => {
// 转化为 dpState 格式
const initialDpState = getDpStateMapByDevInfo(initalDevInfo) as DpState;
// 初始化原子
setDpStateAtom(initialDpState);
// 监听设备状态变更
// 监听状态变更
onDpDataChange(handleDpDataChange);
});
return () => {
......
......@@ -42,3 +42,121 @@ export const getDpStateMapByDevInfo = (devInfo: DevInfo): Record<string, any> =>
});
return dpStateMap;
};
/**
* @desc 将16进制的hsv转换成10进制的hsv
* 范围为h(0-360) s(0-1000) v(0-1000)
* @param {String} hsvStr - encoded hsvStr (hhhhssssvvvv)
*
* @return {Array} [h, s, v]
*
*/
export const dpdataToHsv = (dpData: string): Array<any> => {
if (!dpData || dpData.length !== 12) {
return [0, 1000, 1000];
}
const b = dpData.match(/[a-z\d]{4}/gi) || [];
return b.reduce((curr: number[], hex: string) => {
curr.push(parseInt(hex, 16));
return curr;
}, []);
};
/**
* @desc 将10进制的hsv转换成16进制的hhsssvvvv
* 范围为h(0-360) s(0-1000) v(0-1000)
* @param {Array} hsvArr - [h, s, v]
*
* @return {String} 'hhhhssssvvvv'
*
*/
export const hsvToDpdata = (h: number, s: number, v: number): string => {
let hue = h % 360;
hue = hue > 0 ? hue : h;
hue = hue < 0 ? 360 + hue : hue;
return [hue, s, v].reduce((curr: string, next: number) => {
let hex = parseInt(`${next}`, 10).toString(16);
hex = format(hex, 4);
return curr + hex;
}, '');
};
// 位数填充
export const format = (value: string, len = 2) => {
let v = `${value}`;
if (v.length < len) {
v = '0'.repeat(len - v.length) + v;
} else {
v = v.slice(0, len);
}
return v;
};
/**
* @desc 将色温转化为rgb
* 范围为1000~40000
* @param {number} temperature - 5000
*
* @return {array} [r,g,b]
*
*/
export const temperatureToRgb = (temperature: number): Array<any> => {
let tempera = temperature;
if (tempera < 1000) {
tempera = 1000;
}
if (tempera > 40000) {
tempera = 40000;
}
tempera /= 100;
let red = 0;
if (tempera <= 66) {
red = 255;
} else {
red = tempera - 60;
red = 329.698727446 * Math.pow(red, -0.1332047592);
if (red < 0) {
red = 0;
} else if (red > 255) {
red = 255;
}
}
let green = 0;
if (tempera <= 66) {
green = tempera;
green = 99.4708025861 * Math.log(green) - 161.1195681661;
if (green < 0) {
green = 0;
}
if (green > 255) {
green = 255;
}
} else {
green = tempera - 60;
green = 288.1221695283 * Math.pow(green, -0.0755148492);
if (green < 0) {
green = 0;
}
if (green > 255) {
green = 255;
}
}
let blue = 0;
if (tempera >= 66) {
blue = 255;
} else if (tempera <= 19) {
blue = 0;
} else {
blue = tempera - 10;
blue = 138.5177312231 * Math.log(blue) - 305.0447927307;
if (blue < 0) {
blue = 0;
}
if (blue > 255) {
blue = 255;
}
}
return [Math.floor(red), Math.floor(green), Math.floor(blue)];
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment