|
|
/**
|
|
|
* @交互说明
|
|
|
* 1. 初始化选中目标的设备对象 【设备名称、使用图标】
|
|
|
*/
|
|
|
// https://t7.baidu.com/it/u=2757924858,1404466263&fm=193
|
|
|
import video_type_1 from "@/assets/modelSetting/video_type_1.png";
|
|
|
import video_type_2 from "@/assets/modelSetting/video_type_2.png";
|
|
|
import video_type_3 from "@/assets/modelSetting/video_type_3.png";
|
|
|
import device_video_bg from "@/assets/modelSetting/device_video_bg.png";
|
|
|
import device_video_bg_gray from "@/assets/modelSetting/device_video_bg_gray.png";
|
|
|
import notInVisableIcon from "@/assets/modelSetting/notInVisableIcon.png";
|
|
|
import { workspaceIDConf } from "@/config/attribute/viewType";
|
|
|
import { v4 as uuid } from "uuid";
|
|
|
|
|
|
const deviceInfoKey = "deviceInfo";
|
|
|
// TODO 设计实现点位绑定设备实体的位置偏移问题
|
|
|
/**
|
|
|
* @交互说明
|
|
|
* 1. 基于画布中心点建立坐标系。画布中心点坐标为(0,0)
|
|
|
*/
|
|
|
export const useDeviceObject = () => {
|
|
|
// 拖拽新增获取设备对象在画布上的坐标
|
|
|
function getDragDeviceObjectOrdinate(event, viewObj, deviceObj) {
|
|
|
// 移动到画布上的设备对象的相对坐标,使用相对图片的坐标系,而不是画布的坐标系
|
|
|
const currWorkSpaceData = document
|
|
|
.getElementById(workspaceIDConf)
|
|
|
.getBoundingClientRect();
|
|
|
|
|
|
const cvsObjects = viewObj.getObjects()[0]; // 获取画布对象
|
|
|
const imgObjects = viewObj.getObjects()[1]; // 获取图片对象
|
|
|
const { left, top, width, height } = currWorkSpaceData;
|
|
|
// .getSelectionElement()
|
|
|
// .getBoundingClientRect();
|
|
|
// 该设备基于当前画布的坐标信息
|
|
|
const currPointView = {
|
|
|
x: event.clientX - left,
|
|
|
y: event.clientY - top
|
|
|
};
|
|
|
// const pointerVpt = viewObj.restorePointerVpt(currPointView);
|
|
|
const x_ordinate =
|
|
|
currPointView.x - width / 2 - (deviceObj.width * deviceObj.scaleX) / 2;
|
|
|
const y_ordinate =
|
|
|
height / 2 - currPointView.y + (deviceObj.height * deviceObj.scaleY) / 2;
|
|
|
console.log(
|
|
|
"currWorkSpace:",
|
|
|
currWorkSpaceData,
|
|
|
"cvsObjects:",
|
|
|
cvsObjects,
|
|
|
"event:",
|
|
|
event,
|
|
|
"getDragDeviceObjectOrdinate",
|
|
|
"imgObjects:",
|
|
|
imgObjects.getCenterPoint(),
|
|
|
x_ordinate,
|
|
|
y_ordinate
|
|
|
);
|
|
|
return {
|
|
|
x_ordinate,
|
|
|
y_ordinate
|
|
|
};
|
|
|
}
|
|
|
// 在画布上移动后设备对象坐标
|
|
|
function fetchMoveDeviceObjectOrdinate(viewObj, activeObject) {
|
|
|
const cvsObjects = viewObj.getObjects()[0]; // 获取画布对象
|
|
|
const x_ordinate = activeObject.get("left") - cvsObjects.width / 2;
|
|
|
const y_ordinate = cvsObjects.height / 2 - activeObject.get("top");
|
|
|
return {
|
|
|
x_ordinate,
|
|
|
y_ordinate
|
|
|
};
|
|
|
}
|
|
|
|
|
|
// 使用相对坐标换实际位置的方法
|
|
|
function fetchOrdinateByView(viewObj, deviceItem) {
|
|
|
const cvsObjects = viewObj.getObjects()[0]; // 获取画布对象
|
|
|
const { x_ordinate, y_ordinate } = deviceItem;
|
|
|
const left = cvsObjects.width / 2 + parseFloat(x_ordinate);
|
|
|
const top = cvsObjects.height / 2 - parseFloat(y_ordinate);
|
|
|
console.log(cvsObjects, "fetchOrdinateByView", left, top);
|
|
|
return {
|
|
|
left,
|
|
|
top
|
|
|
};
|
|
|
}
|
|
|
|
|
|
// 可操作区域的各点位相对坐标【限定可操作区域边界】
|
|
|
function fetchViewsBoundaries(viewObj, activeObj) {
|
|
|
// 图片原点为中心图标
|
|
|
const cvsObjects = viewObj.getObjects()[0]; // 获取画布对象
|
|
|
const imgObjects = viewObj.getObjects()[1]; // 获取图片对象
|
|
|
const y_mistake = -8 * activeObj?.scaleY; // 上下边界误差
|
|
|
const currIconWidth = activeObj?.width * activeObj?.scaleX;
|
|
|
const currIconHeight = activeObj?.height * activeObj?.scaleY;
|
|
|
const startLeft =
|
|
|
(cvsObjects.width * cvsObjects.scaleX -
|
|
|
imgObjects.width * imgObjects.scaleX) /
|
|
|
2 -
|
|
|
currIconWidth / 2;
|
|
|
const startTop =
|
|
|
(cvsObjects.height * cvsObjects.scaleY -
|
|
|
imgObjects.height * imgObjects.scaleY) /
|
|
|
2 -
|
|
|
currIconHeight -
|
|
|
y_mistake;
|
|
|
const endLeft = startLeft + imgObjects.width * imgObjects.scaleX;
|
|
|
const endTop = startTop + imgObjects.height * imgObjects.scaleY;
|
|
|
const currImgWidth = imgObjects.width * imgObjects.scaleX;
|
|
|
const currImgHeight = imgObjects.height * imgObjects.scaleY;
|
|
|
return {
|
|
|
x_min: -currImgWidth / 2 - currIconWidth / 2,
|
|
|
y_min: -currImgHeight / 2 - currIconHeight,
|
|
|
x_max: currImgWidth / 2 + currIconWidth / 2,
|
|
|
y_max: currImgHeight / 2,
|
|
|
startLeft,
|
|
|
startTop,
|
|
|
endLeft,
|
|
|
endTop
|
|
|
};
|
|
|
}
|
|
|
|
|
|
// 操作区判断设备是否在可视区域内
|
|
|
function isInViewBoundaries(viewObj, deviceObj): boolean {
|
|
|
const { x_min, x_max, y_min, y_max } = fetchViewsBoundaries(
|
|
|
viewObj,
|
|
|
deviceObj
|
|
|
);
|
|
|
const { x_ordinate, y_ordinate } = deviceObj;
|
|
|
// 限制对象在画布内移动
|
|
|
if (x_ordinate < x_min) {
|
|
|
return false;
|
|
|
}
|
|
|
if (y_ordinate < y_min) {
|
|
|
return false;
|
|
|
}
|
|
|
if (x_ordinate > x_max) {
|
|
|
return false;
|
|
|
}
|
|
|
if (y_ordinate > y_max) {
|
|
|
return false;
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
// 预览判断当前的图片图层内
|
|
|
function isInCurrViewBoundaries(viewObj, deviceObj): boolean {
|
|
|
const objLeft = deviceObj.left;
|
|
|
const objTop = deviceObj.top;
|
|
|
const canvasObject = viewObj;
|
|
|
const { backgroundImage } = canvasObject; // backgroundImage 背景图片
|
|
|
const currIconWidth = deviceObj?.width * deviceObj?.scaleX;
|
|
|
const currIconHeight = deviceObj?.height * deviceObj?.scaleY;
|
|
|
const y_mistake = -8 * deviceObj?.scaleY; // 上下边界误差
|
|
|
const x_mistake = 1; // 左右边界误差
|
|
|
const startLeft =
|
|
|
(canvasObject.width - backgroundImage.width * backgroundImage.scaleX) /
|
|
|
2 -
|
|
|
currIconWidth / 2;
|
|
|
const startTop =
|
|
|
(canvasObject.height - backgroundImage.height * backgroundImage.scaleY) /
|
|
|
2 -
|
|
|
currIconHeight -
|
|
|
y_mistake;
|
|
|
const endLeft = startLeft + backgroundImage.width * backgroundImage.scaleX;
|
|
|
const endTop = startTop + backgroundImage.height * backgroundImage.scaleY;
|
|
|
|
|
|
console.log(
|
|
|
backgroundImage.getBoundingClientRect(),
|
|
|
canvasObject.width,
|
|
|
canvasObject.scaleX,
|
|
|
backgroundImage.width,
|
|
|
backgroundImage.scaleX,
|
|
|
currIconWidth,
|
|
|
"isInCurrViewBoundaries",
|
|
|
backgroundImage.scaleX,
|
|
|
deviceObj,
|
|
|
"startLeft",
|
|
|
startLeft,
|
|
|
"startTop",
|
|
|
startTop,
|
|
|
"endLeft",
|
|
|
endLeft,
|
|
|
"endTop",
|
|
|
endTop
|
|
|
);
|
|
|
if (
|
|
|
objLeft < startLeft - x_mistake ||
|
|
|
objTop < startTop ||
|
|
|
objLeft > endLeft + x_mistake ||
|
|
|
objTop > endTop
|
|
|
) {
|
|
|
return true;
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
// function isInView() {
|
|
|
// // TODO 用三角函数判断
|
|
|
// return;
|
|
|
// }
|
|
|
|
|
|
// 设备对象是否移动
|
|
|
function isMoveDevice(activeObject, viewObj) {
|
|
|
const x_ordinate_history = activeObject.get(deviceInfoKey)?.x_ordinate;
|
|
|
const y_ordinate_history = activeObject.get(deviceInfoKey)?.y_ordinate;
|
|
|
const { x_ordinate, y_ordinate } = fetchMoveDeviceObjectOrdinate(
|
|
|
viewObj,
|
|
|
activeObject
|
|
|
);
|
|
|
// 误差设置为 0.1
|
|
|
const errorValue = [1, 1];
|
|
|
let x_move = true;
|
|
|
let y_move = true;
|
|
|
const x_move_value = Math.abs(
|
|
|
Number(x_ordinate_history) - Number(x_ordinate)
|
|
|
);
|
|
|
const y_move_value = Math.abs(
|
|
|
Number(y_ordinate_history) - Number(y_ordinate)
|
|
|
);
|
|
|
|
|
|
// 重新绑定车间的设备没有坐标信息,暂时不判断设备是否移动【默认没有移动】
|
|
|
// if (Number.isNaN(x_move_value) || Number.isNaN(y_move_value)) {
|
|
|
// return false;
|
|
|
// }
|
|
|
if (x_move_value < errorValue[0]) {
|
|
|
x_move = false;
|
|
|
}
|
|
|
if (y_move_value < errorValue[1]) {
|
|
|
y_move = false;
|
|
|
}
|
|
|
console.log(
|
|
|
"isMoveDevice:" + (x_move || y_move),
|
|
|
"x_move_value" + x_move_value,
|
|
|
"y_move_value" + y_move_value
|
|
|
);
|
|
|
return x_move || y_move;
|
|
|
}
|
|
|
|
|
|
// 初始化设备对象
|
|
|
const initDeviceGroupObjects: Record<string, any> = (
|
|
|
record,
|
|
|
restDeviceItem = {}
|
|
|
) => {
|
|
|
console.log(record, "initDeviceGroupObjects");
|
|
|
// const { value } = record;
|
|
|
let iconObjectSrc = video_type_1;
|
|
|
switch (record?.icon) {
|
|
|
case "3":
|
|
|
iconObjectSrc = video_type_3;
|
|
|
break;
|
|
|
case "2":
|
|
|
iconObjectSrc = video_type_2;
|
|
|
break;
|
|
|
case "1":
|
|
|
default:
|
|
|
iconObjectSrc = video_type_1;
|
|
|
break;
|
|
|
}
|
|
|
let bgDeviceImage;
|
|
|
const fontStyle = { fill: "#333333" };
|
|
|
// 不在可视区域内的设备
|
|
|
if (record?.notInVisable) {
|
|
|
bgDeviceImage = device_video_bg_gray;
|
|
|
fontStyle.fill = "gray";
|
|
|
} else {
|
|
|
bgDeviceImage = device_video_bg;
|
|
|
}
|
|
|
return {
|
|
|
name: "device",
|
|
|
id: uuid(),
|
|
|
deviceInfo: record, // 设备信息
|
|
|
left: record?.left ? Number(record?.left) : 0,
|
|
|
top: record?.top ? Number(record?.top) : 0,
|
|
|
selectable: true,
|
|
|
hasControls: true,
|
|
|
lockUniScaling: true, // 当设置为true,Object将无法被锁定比例进行缩放。默认值为false。
|
|
|
lockScalingX: true, // 当设置为true,Object水平方向将无法被缩放。默认值为false。
|
|
|
lockScalingY: true, // 当设置为true,Object垂直方向将无法被缩放。默认值为false。
|
|
|
lockRotation: true, // 当设置为true,Object的旋转将被锁定。默认值为false。
|
|
|
type: "group",
|
|
|
version: "5.3.0",
|
|
|
originX: "left",
|
|
|
originY: "top",
|
|
|
width: 132,
|
|
|
height: 62,
|
|
|
fill: "rgb(0,0,0)",
|
|
|
stroke: null,
|
|
|
strokeWidth: 0,
|
|
|
strokeDashArray: null,
|
|
|
strokeLineCap: "butt",
|
|
|
strokeDashOffset: 0,
|
|
|
strokeLineJoin: "miter",
|
|
|
strokeUniform: false,
|
|
|
strokeMiterLimit: 4,
|
|
|
scaleX: 1,
|
|
|
scaleY: 1,
|
|
|
angle: 0,
|
|
|
flipX: false,
|
|
|
flipY: false,
|
|
|
opacity: 1,
|
|
|
shadow: null,
|
|
|
visible: true,
|
|
|
backgroundColor: "",
|
|
|
fillRule: "nonzero",
|
|
|
paintFirst: "fill",
|
|
|
globalCompositeOperation: "source-over",
|
|
|
skewX: 0,
|
|
|
skewY: 0,
|
|
|
objects: [
|
|
|
{
|
|
|
type: "image",
|
|
|
version: "5.3.0",
|
|
|
originX: "left",
|
|
|
originY: "top",
|
|
|
left: -66,
|
|
|
top: -33,
|
|
|
width: 264,
|
|
|
height: 132,
|
|
|
fill: "rgb(0,0,0)",
|
|
|
stroke: null,
|
|
|
strokeWidth: 0,
|
|
|
strokeDashArray: null,
|
|
|
strokeLineCap: "butt",
|
|
|
strokeDashOffset: 0,
|
|
|
strokeLineJoin: "miter",
|
|
|
strokeUniform: false,
|
|
|
strokeMiterLimit: 4,
|
|
|
scaleX: 0.5,
|
|
|
scaleY: 0.5,
|
|
|
angle: 0,
|
|
|
flipX: false,
|
|
|
flipY: false,
|
|
|
opacity: 1,
|
|
|
shadow: null,
|
|
|
visible: true,
|
|
|
backgroundColor: "",
|
|
|
fillRule: "nonzero",
|
|
|
paintFirst: "fill",
|
|
|
globalCompositeOperation: "source-over",
|
|
|
skewX: 0,
|
|
|
skewY: 0,
|
|
|
cropX: 0,
|
|
|
cropY: 0,
|
|
|
selectable: false,
|
|
|
hasControls: false,
|
|
|
src: bgDeviceImage,
|
|
|
crossOrigin: null,
|
|
|
filters: []
|
|
|
},
|
|
|
{
|
|
|
type: "image",
|
|
|
version: "5.3.0",
|
|
|
originX: "left",
|
|
|
originY: "top",
|
|
|
left: -50.6281,
|
|
|
top: -22.9893,
|
|
|
width: 48,
|
|
|
height: 48,
|
|
|
fill: "rgb(0,0,0)",
|
|
|
stroke: null,
|
|
|
strokeWidth: 0,
|
|
|
strokeDashArray: null,
|
|
|
strokeLineCap: "butt",
|
|
|
strokeDashOffset: 0,
|
|
|
strokeLineJoin: "miter",
|
|
|
strokeUniform: false,
|
|
|
strokeMiterLimit: 4,
|
|
|
scaleX: 0.6174,
|
|
|
scaleY: 0.6174,
|
|
|
angle: 0,
|
|
|
flipX: false,
|
|
|
flipY: false,
|
|
|
opacity: 1,
|
|
|
shadow: null,
|
|
|
visible: true,
|
|
|
backgroundColor: "",
|
|
|
fillRule: "nonzero",
|
|
|
paintFirst: "fill",
|
|
|
globalCompositeOperation: "source-over",
|
|
|
skewX: 0,
|
|
|
skewY: 0,
|
|
|
cropX: 0,
|
|
|
cropY: 0,
|
|
|
selectable: false,
|
|
|
hasControls: false,
|
|
|
src: iconObjectSrc,
|
|
|
crossOrigin: null,
|
|
|
filters: []
|
|
|
},
|
|
|
{
|
|
|
type: "textbox",
|
|
|
version: "5.3.0",
|
|
|
originX: "left",
|
|
|
originY: "top",
|
|
|
left: -14.3377,
|
|
|
top: -15.4904,
|
|
|
width: 320,
|
|
|
height: 90.4,
|
|
|
fill: fontStyle.fill,
|
|
|
stroke: null,
|
|
|
strokeWidth: 1,
|
|
|
strokeDashArray: null,
|
|
|
strokeLineCap: "butt",
|
|
|
strokeDashOffset: 0,
|
|
|
strokeLineJoin: "miter",
|
|
|
strokeUniform: false,
|
|
|
strokeMiterLimit: 4,
|
|
|
scaleX: 0.1681,
|
|
|
scaleY: 0.1681,
|
|
|
angle: 0,
|
|
|
flipX: false,
|
|
|
flipY: false,
|
|
|
opacity: 1,
|
|
|
shadow: "",
|
|
|
visible: true,
|
|
|
backgroundColor: "",
|
|
|
fillRule: "nonzero",
|
|
|
paintFirst: "fill",
|
|
|
globalCompositeOperation: "source-over",
|
|
|
skewX: 0,
|
|
|
skewY: 0,
|
|
|
fontFamily: "arial",
|
|
|
fontWeight: "normal",
|
|
|
fontSize: 80,
|
|
|
text: record?.name,
|
|
|
underline: false,
|
|
|
overline: false,
|
|
|
linethrough: false,
|
|
|
textAlign: "left",
|
|
|
fontStyle: "normal",
|
|
|
lineHeight: 1.16,
|
|
|
textBackgroundColor: "",
|
|
|
charSpacing: 0,
|
|
|
styles: [],
|
|
|
direction: "ltr",
|
|
|
path: null,
|
|
|
pathStartOffset: 0,
|
|
|
pathSide: "left",
|
|
|
pathAlign: "baseline",
|
|
|
selectable: false,
|
|
|
hasControls: false
|
|
|
},
|
|
|
{
|
|
|
type: "image",
|
|
|
version: "5.3.0",
|
|
|
originX: "left",
|
|
|
originY: "top",
|
|
|
left: -47.6281,
|
|
|
top: -19.9893,
|
|
|
width: 40,
|
|
|
height: 40,
|
|
|
fill: "rgb(0,0,0)",
|
|
|
stroke: null,
|
|
|
strokeWidth: 0,
|
|
|
strokeDashArray: null,
|
|
|
strokeLineCap: "butt",
|
|
|
strokeDashOffset: 0,
|
|
|
strokeLineJoin: "miter",
|
|
|
strokeUniform: false,
|
|
|
strokeMiterLimit: 4,
|
|
|
scaleX: 0.6174,
|
|
|
scaleY: 0.6174,
|
|
|
angle: 0,
|
|
|
flipX: false,
|
|
|
flipY: false,
|
|
|
opacity: 1,
|
|
|
shadow: null,
|
|
|
visible: false,
|
|
|
backgroundColor: "",
|
|
|
fillRule: "nonzero",
|
|
|
paintFirst: "fill",
|
|
|
globalCompositeOperation: "source-over",
|
|
|
skewX: 0,
|
|
|
skewY: 0,
|
|
|
cropX: 0,
|
|
|
cropY: 0,
|
|
|
selectable: false,
|
|
|
hasControls: false,
|
|
|
src: notInVisableIcon,
|
|
|
crossOrigin: null,
|
|
|
filters: []
|
|
|
}
|
|
|
],
|
|
|
...restDeviceItem
|
|
|
};
|
|
|
};
|
|
|
return {
|
|
|
initDeviceGroupObjects,
|
|
|
isInViewBoundaries,
|
|
|
getDragDeviceObjectOrdinate,
|
|
|
isMoveDevice,
|
|
|
fetchViewsBoundaries,
|
|
|
fetchOrdinateByView,
|
|
|
fetchMoveDeviceObjectOrdinate,
|
|
|
isInCurrViewBoundaries
|
|
|
};
|
|
|
};
|