Browse Source

塔吊样式

master
巴林闲侠 2 years ago
parent
commit
cddd3fb55d
  1. 2
      console/client/src/index.js
  2. 2
      console/client/src/layout/components/header/index.js
  3. 4
      console/client/src/sections/auth/containers/login.js
  4. 417
      console/client/src/sections/console/containers/index.js
  5. 74
      console/client/src/sections/console/style.less

2
console/client/src/index.js

@ -5,6 +5,6 @@ import { render } from 'react-dom';
import App from './app';
render(
<App projectName="政务数据资源中心" />,
<App projectName="吊机防碰撞" />,
document.getElementById('App')
);

2
console/client/src/layout/components/header/index.js

@ -39,7 +39,7 @@ const Header = props => {
}
</span>
<div className={styles['header-title']} style={{}}>
<img src='/assets/images/logo.png' style={{ margin: '0 12px 4px 12px', height: 42, borderRadius: 4 }} />政务数据资源中心
<img src='/assets/images/logo.png' style={{ margin: '0 12px 4px 12px', height: 42, borderRadius: 4 }} />吊机防碰撞
</div>
</div>
<div id="nav" className={styles['header-nav']}>

4
console/client/src/sections/auth/containers/login.js

@ -116,7 +116,7 @@ const Login = props => {
justifyContent: 'space-around'
}}>
<p style={{ fontSize: 30, fontWeight: 'bold', textAlign: 'center' }}>
政务数据资源中心
吊机防碰撞
</p>
<Tabs defaultActiveKey="1" animated={true} onChange={(k) => {
setCurTabKey(k)
@ -248,7 +248,7 @@ const Login = props => {
);
}
function mapStateToProps(state) {
function mapStateToProps (state) {
const { auth } = state;
return {
user: auth.user,

417
console/client/src/sections/console/containers/index.js

@ -2,7 +2,7 @@ import React, { useEffect, useState, useRef } from 'react'
import { Col, Row } from 'antd';
import '../style.less'
function calculateIntersection (cx, cy, d, angle, x00, y00) {
function calculateIntersection (cx, cy, d, angle) {
// 将角度转换为弧度
const theta = angle * Math.PI / 180;
// 计算圆半径
@ -11,8 +11,8 @@ function calculateIntersection (cx, cy, d, angle, x00, y00) {
const dx = Math.cos(theta);
const dy = Math.sin(theta);
// 射线起点坐标,可以根据实际情况设定
const x0 = x00;
const y0 = y00;
const x0 = cx;
const y0 = cy;
// 计算向量 OC
const OCx = cx - x0;
const OCy = cy - y0;
@ -34,49 +34,388 @@ function calculateIntersection (cx, cy, d, angle, x00, y00) {
function Index (props) {
const xyCvs = useRef()
const xzCvs = useRef()
useEffect(() => {
const canvasArea = document.getElementById('canvasArea')
const canvasHeight = canvasArea.clientHeight - 12 * 2 - 6
const canvasWidth = canvasArea.clientWidth - 12 * 2
const mainColor = "rgb(249,179,45)"
// xy 视图
console.log(xyCvs, xyCvs.current, canvasHeight);
const ctx = xyCvs.current.getContext("2d");
const xyCtx = xyCvs.current.getContext("2d");
xyCvs.current.height = canvasHeight
xyCvs.current.width = canvasWidth
const center = [canvasWidth / 2, canvasHeight / 2]
const diameter = Math.min(canvasWidth, canvasHeight)
// 画圆
ctx.beginPath();
ctx.arc(...center, diameter / 2, 0, 2 * Math.PI);
ctx.stroke();
// 臂
ctx.moveTo(...center);
ctx.lineTo(...calculateIntersection(...center, diameter, 0, ...center));
ctx.moveTo(...center);
ctx.lineTo(...calculateIntersection(...center, diameter / 10, 0 + 140, ...center));
ctx.fillStyle = "red";
ctx.stroke();
xyCtx.beginPath();
xyCtx.arc(...center, diameter / 2, 0, 2 * Math.PI);
xyCtx.stroke();
// 圆心圆
xyCtx.beginPath();
xyCtx.arc(...center, diameter / 48, 0, 2 * Math.PI);
xyCtx.fillStyle = mainColor;
xyCtx.fill();
xyCtx.stroke();
// 吊臂
xyCtx.moveTo(...center);
xyCtx.lineTo(...calculateIntersection(...center, diameter, 42));
// 配重臂
xyCtx.moveTo(...center);
xyCtx.lineTo(...calculateIntersection(...center, diameter / 8, 42 + 180));
xyCtx.strokeStyle = mainColor;
xyCtx.stroke();
// 索
xyCtx.beginPath();
xyCtx.arc(...calculateIntersection(...center, 168, 42), diameter / 48, 0, 2 * Math.PI);
xyCtx.fillStyle = mainColor;
xyCtx.fill();
xyCtx.stroke();
// xz 视图
const xzCtx = xzCvs.current.getContext("2d");
xzCvs.current.height = canvasHeight
xzCvs.current.width = canvasWidth
/**
* 1绘制矩形(主要分为:绘制填充矩形和绘制边框矩形和清除矩形区域(利用isClear标记是否绘制清除矩形,实际上就是绘制一个与画布背景色一致的矩形区域),利用isFill变量来标记)
* 主要使用canvas原生的API:FillRect(x,y,width,height),StrokeRect(x,y,width,height),ClearRect(x,y,width,height)
* 自己封装的参数:drawRect(x,y,width,height,isClear,isFill,bgColor)
* x:矩形起点的X坐标(注意:相对坐标系是以画布的左上角为原点,向右为X坐标正方向,向下为Y坐标的正方向)
* y:矩形终点的Y坐标
* width:矩形的宽度
* height:矩形的高度
* isClear:是否绘制清除画布的矩形区域,true则就是绘制一个清除画布矩形区域,false就是绘制其他两种矩形
* isFill:是否是填充,false为绘制边框,true为绘制填充
* bgColor:矩形的颜色,若为填充则为整个矩形背景色,边框则为边框色
* */
function drawRect (x, y, width, height, isClear, isFill, bgColor) {
if (isClear) { //为true表示绘制清除画布的矩形区域,那么传入的isFill, bgColor值可以为任意值
xzCtx.clearRect(x, y, width, height);
} else { //false
if (isFill) { //为true,则绘制填充矩形
xzCtx.fillStyle = bgColor;
xzCtx.fillRect(x, y, width, height);
} else { //为false,则绘制边框矩形
xzCtx.strokeStyle = bgColor;
xzCtx.strokeRect(x, y, width, height);
}
}
}
/**
* 2绘制圆弧(主要分为:绘制填充圆弧和绘制圆弧边框利用isFill变量来标记,注意:在绘制圆弧边框的时候还有一种特殊情况就是,只需要仅仅绘制弧边,不需要绘制圆弧开始起点和终点之间的连线,这个就是调用了beginPath()不需要调用closePath(),这里也使用一个isOnlyArc变量来标记true为仅仅绘制弧边
*其他的正常)
* 主要是使用的是canvas原生的API:
* arc(x,y,radius,startAngle,endAngle,anticlockwise);
* x:圆心X坐标
* y:圆心Y坐标
* startAngle:开始的弧度
* endAngle:结束的弧度
* anticlockwise:true为逆时针,false为顺时针
* 自己封装的参数:drawCircle(x,y,radius,startAngle,endAngle,anticlockwise,isFill,bgColor)
* x:圆心X坐标
* y:圆心Y坐标
* startAngle:开始的角度(通过getAngle方法将传入的角度转换成相应角度的弧度,
* 因为在原生的绘制圆弧的API它是根据弧度大小来绘制的,例如如果你想绘制一个30度的圆弧,如果直接传入30是不行的,要传入Math.PI/6
* 所以在这里个人做了一个优化,直接传入30就通过getAngle方法转换成Math.PI/6,这样就很方便的绘制自己传入的角度大小的圆弧.
* )
* endAngle:结束的角度
* 注意:如果要绘制圆形那么只需要调用该方法,传入的startAngle和endAngle是0度和360度即可.
* anticlockwise:true为逆时针,false为顺时针
* isFill:是否是填充,false为绘制边框,true为绘制填充
* bgColor:圆弧的颜色
* */
function drawArc (x, y, radius, startAngle, endAngle, anticlockwise, isOnlyArc, isFill, bgColor) {
if (isFill) { //为true绘制填充圆弧
xzCtx.fillStyle = bgColor;
xzCtx.beginPath();
xzCtx.arc(x, y, radius, getAngle(startAngle), getAngle(endAngle), anticlockwise);
xzCtx.closePath();
xzCtx.fill();
} else { //为false绘制边框圆弧
xzCtx.strokeStyle = bgColor;
xzCtx.beginPath();
xzCtx.arc(x, y, radius, getAngle(startAngle), getAngle(endAngle), anticlockwise);
if (isOnlyArc) { //绘制边框的另一种情况就是仅仅绘制弧边不需要调用closePath()
} else { //否则就是不仅绘制边框还得绘制起点和终点的连线,需要调用了closePath();
xzCtx.closePath();
}
xzCtx.stroke();
}
}
/**
* 3绘制扇形(主要分为:绘制填充扇形和绘制扇形边框利用isFill变量来标记)
*主要是使用的是canvas原生的API:
* arc(x,y,radius,startAngle,endAngle,anticlockwise);
* x:圆心X坐标
* y:圆心Y坐标
* startAngle:开始的弧度
* endAngle:结束的弧度
* anticlockwise:true为逆时针,false为顺时针
* 自己封装参数API:drawSector(x,y,radius,startAngle,endAngle,anticlockwise,isFill,bgColor);
* x:圆心X坐标
* y:圆心Y坐标
* startAngle:开始的角度(通过getAngle方法将传入的角度转换成相应角度的弧度,
* 因为在原生的绘制圆弧的API它是根据弧度大小来绘制的,例如如果你想绘制一个30度的圆弧,如果直接传入30是不行的,要传入Math.PI/6
* 所以在这里个人做了一个优化,直接传入30就通过getAngle方法转换成Math.PI/6,这样就很方便的绘制自己传入的角度大小的圆弧.
* )
* endAngle:结束的角度
* anticlockwise:true为逆时针,false为顺时针
* isFill:是否是填充,false为绘制边框,true为绘制填充
* bgColor:扇形的颜色
* */
function drawSector (x, y, radius, startAngle, endAngle, anticlockwise, isFill, bgColor) {
if (isFill) {
xzCtx.fillStyle = bgColor;
xzCtx.beginPath();
xzCtx.moveTo(x, y); //把路径移动到画布中的指定点,不创建线条,注意:绘制扇形唯一与绘制弧的区别在于,紧跟着beginPath()后面调用,首先将路径移动到圆心位置
xzCtx.arc(x, y, radius, getAngle(startAngle), getAngle(endAngle), false);
xzCtx.closePath();
xzCtx.fill();
} else {
xzCtx.strokeStyle = bgColor;
xzCtx.beginPath();
xzCtx.moveTo(x, y);
xzCtx.arc(x, y, radius, getAngle(startAngle), getAngle(endAngle), false);
xzCtx.closePath();
xzCtx.stroke();
}
}
/**
* @description 4绘制线段(主要分为:绘制填充线段和绘制空心线段利用isFill变量来标记)
* 主要是使用的是canvas原生的API:
* lineTo(x,y):表示从某点连线到该坐标点
*moveTo(x,y):表示将路径移动到画布中的该坐标点
* x:画布中某点的X坐标
* y:画布中某点的Y坐标
* 注意:如果开始没有调用moveTo,那么第一个lineTo的功能就相当于一个moveTo
* 自己封装的API:drawLine(startX,startY,endX,endY,lineWidth,bgcolor)
*
* startX:表示线的起点的X坐标
* startY:表示起点的Y坐标
* endX:表示线的终点的X坐标
* endY:表示线的终点的Y坐标
* lineWidth:表示线段的宽度
* bgColor:线的颜色
* */
function drawLine (startX, startY, endX, endY, lineWidth, bgColor) {
xzCtx.beginPath();
xzCtx.lineWidth = lineWidth;
xzCtx.strokeStyle = bgColor;
xzCtx.moveTo(startX, startY);
xzCtx.lineTo(endX, endY);
xzCtx.stroke();
xzCtx.fill();
}
/**
* @description 5绘制贝塞尔曲线
* drawBezierCurve
* */
//将角度转换成弧度函数,
function getAngle (arc) {
return Math.PI * (arc / 180);
}
/**
* @description 6吊钩
* variousHooks
* x原点横坐标,
* y原点纵坐标,
* X变量值左右,
* Y变量值上下,
* bgColor颜色
* */
function variousHooks (x, y, X, Y, bgColor) {
xzCtx.beginPath();
xzCtx.strokeStyle = bgColor;
//钩子头部分
xzCtx.moveTo(x + 5 + X, y);
xzCtx.lineTo(x + 35 + X, y);
xzCtx.moveTo(x + 5 + X, y + 10);
xzCtx.lineTo(x + 35 + X, y + 10)
xzCtx.moveTo(x + 10 + X, y);
xzCtx.lineTo(x + 10 + X, y + 10);
xzCtx.moveTo(x + 30 + X, y);
xzCtx.lineTo(x + 30 + X, y + 10);
xzCtx.moveTo(x + 11 + X, y + 10);
xzCtx.lineTo(x + 11 + X, y + 10 + Y);
xzCtx.moveTo(x + 29 + X, y + 10);
xzCtx.lineTo(x + 29 + X, y + 10 + Y);
//半圆
xzCtx.moveTo(x + 20 + X, y + 10 + Y);
xzCtx.arc(x + 20 + X, y + 10 + Y, 10, 0, 180 * Math.PI / 180, false);
xzCtx.moveTo(x + 20 + X, y + 10 + Y + 5);
xzCtx.lineTo(x + 10 + X, y + 10 + Y + 15);
xzCtx.moveTo(x + 20 + X, y + 10 + Y + 5);
xzCtx.lineTo(x + 30 + X, y + 10 + Y + 15);
xzCtx.moveTo(x + 30 + X, y + 10 + Y + 15);
xzCtx.lineTo(x + 30 + X, y + 10 + Y + 35);
xzCtx.lineTo(x + 10 + X, y + 10 + Y + 35);
xzCtx.lineTo(x + 10 + X, y + 10 + Y + 35);
xzCtx.lineTo(x + 10 + X, y + 10 + Y + 15);
xzCtx.lineTo(x + 30 + X, y + 10 + Y + 15);
xzCtx.stroke();
xzCtx.fill();
}
/**
* @description 7叉线
* wiredCables
* */
function wiredCables (x, y, lineWidth, bgColor) {
xzCtx.beginPath();
xzCtx.lineWidth = lineWidth;
xzCtx.strokeStyle = bgColor;
xzCtx.moveTo(x - 10, y + 15);
xzCtx.lineTo(x + 10, y - 15);
xzCtx.moveTo(x - 10, y - 15);
xzCtx.lineTo(x + 10, y + 15);
xzCtx.stroke();
xzCtx.fill();
}
/**
* @description 8文字
* wiredCables
* */
function drawText (text, x, y, color, font, textAlign) {
xzCtx.font = font;
xzCtx.textAlign = textAlign;
xzCtx.fillStyle = color;
xzCtx.fillText(text, x, y);
}
function initCanvas () { //onload事件加载该方法,当HTML5页面加载的时候就会回调该方法
// 适应塔吊的高的高度
// 150 是驾驶舱底部的开始高度 180是预留的底座的高度
const autoHeight = canvasHeight - 150 - 60
const autoWidth = canvasWidth - 170 - 60
let maxHeightAutoI = 0
for (let i = 0; i * 30 < autoHeight; i++) {
/** 画矩形 */
drawRect(150, 160 + i * 30, 20, 30, false, false, mainColor);
/** 画点 */
drawArc(150, 160 + i * 30, 2, 0, 360, false, false, true, mainColor);
drawArc(170, 160 + i * 30, 2, 0, 360, false, false, true, mainColor);
/** 话叉线 */
wiredCables(160, 175 + i * 30, 1, mainColor)
maxHeightAutoI = i
}
maxHeightAutoI += 1
// 底座
drawLine(110, 160 + maxHeightAutoI * 30, 210, 160 + maxHeightAutoI * 30, 1, mainColor);
drawLine(135, 160 + maxHeightAutoI * 30, 150, 160 + (maxHeightAutoI - 2) * 30, 1, mainColor);
drawLine(185, 160 + maxHeightAutoI * 30, 170, 160 + (maxHeightAutoI - 2) * 30, 1, mainColor);
// 右臂斜线
let maxWidthAutoI = 0
for (let i = 0; i * 20 < autoWidth; i++) {
drawLine(170 + i * 20, 110, 180 + i * 20, 90, 1, mainColor);
drawLine(190 + i * 20, 110, 180 + i * 20, 90, 1, mainColor);
maxWidthAutoI = i
}
// 右臂上下线条
maxWidthAutoI += 1
drawLine(170, 110, 170 + maxWidthAutoI * 20, 110, 1, mainColor);
drawLine(180, 90, 180 + maxWidthAutoI * 20 - 20, 90, 1, mainColor);
// 驾驶舱左
drawRect(150, 115, 10, 40, false, true, mainColor);
//左小重物
drawRect(57, 113, 9, 15, false, true, mainColor);
drawRect(67, 113, 9, 15, false, true, mainColor);
drawRect(77, 113, 9, 15, false, true, mainColor);
//驾驶室
drawLine(160, 115, 170, 115, 1, mainColor);
drawLine(170, 115, 180, 135, 1, mainColor);
drawLine(180, 135, 160, 135, 1, mainColor);
drawLine(180, 135, 170, 155, 1, mainColor);
drawLine(170, 155, 160, 155, 1, mainColor);
//塔吊尖
drawLine(150, 110, 170, 110, 1, mainColor);
drawLine(150, 110, 160, 20, 1, mainColor);
drawLine(170, 110, 160, 20, 1, mainColor);
drawLine(152, 90, 168, 90, 1, mainColor);
drawLine(155, 70, 165, 70, 1, mainColor);
drawLine(158, 50, 162, 50, 1, mainColor);
drawLine(160, 45, 85, 80, 1, mainColor);
drawLine(160, 45, 88, 80, 1, mainColor);
drawLine(160, 45, 91, 80, 1, mainColor);
drawLine(160, 45, 240, 90, 1, mainColor);
drawLine(160, 45, 243, 90, 1, mainColor);
drawLine(160, 45, 246, 90, 1, mainColor);
drawLine(160, 45, 350, 90, 1, mainColor);
drawLine(160, 45, 353, 90, 1, mainColor);
drawLine(160, 45, 356, 90, 1, mainColor);
//左吊臂
drawLine(55, 110, 150, 110, 1, mainColor);
drawLine(55, 110, 55, 80, 1, mainColor);
drawLine(85, 110, 85, 80, 1, mainColor);
drawLine(115, 110, 115, 80, 1, mainColor);
drawLine(145, 110, 145, 80, 1, mainColor);
drawLine(55, 100, 145, 100, 1, mainColor);
drawLine(55, 90, 145, 90, 1, mainColor);
drawLine(55, 80, 145, 80, 1, mainColor);
//左小重物竖线
drawLine(62, 110, 62, 130, 1, mainColor);
drawLine(72, 110, 72, 130, 1, mainColor);
drawLine(82, 110, 82, 130, 1, mainColor);
//6.控制吊钩的运动 以(165,110)为原点 X~(0--180),Y~(0--240)
variousHooks(110, 110, 180, 444, mainColor)
//8 吊钩区域文字
// drawText('尾臂: ', 20, 35, "#01adec", '18px 微软雅黑', "left")
// drawText('12.5米', 65, 35, "#01adec", '18px 微软雅黑', "left")
// drawText('倾角: ', 20, 240, "#01adec", '18px 微软雅黑', "left")
// drawText('0°', 65, 240, "#01adec", '18px 微软雅黑', "left")
// drawText('更新时间: ', 75, 430, "#01adec", '18px 微软雅黑', "left")
// drawText('2018-11-12', 160, 430, "#01adec", '18px 微软雅黑', "left")
// drawText('14:57:30', 275, 430, "#01adec", '18px 微软雅黑', "left")
// drawText('长臂: ', 280, 35, "#01adec", '18px 微软雅黑', "left")
// drawText('30.26米', 325, 35, "#01adec", '18px 微软雅黑', "left")
}
initCanvas()
}, [])
return (
<div style={{ height: '100vh', padding: 24 }}>
<div style={{ height: '75%' }}>
<div style={{ height: '100vh', padding: 8 }}>
<div style={{ height: '80%', padding: 8 }}>
<Row style={{ height: '100%' }}>
<Col span={12} id="canvasArea" style={{ padding: 12, border: '1px solid black' }}>
<Col span={12} id="canvasArea" style={{ paddingRight: 8, }}>
<div className='card'>
<canvas ref={xzCvs} id='xzCvs' height={120} width={120} style={{}}>
您的浏览器不支持canvas,请更换浏览器.
</canvas>
</div>
</Col>
<Col span={12} style={{ padding: 12, border: '1px solid black' }}>
<canvas ref={xyCvs} id='xyCvs' height={120} width={120} style={{
// height: '100%', width: '100%'
}}>
您的浏览器不支持canvas,请更换浏览器.
</canvas>
<Col span={12} style={{ paddingLeft: 8,}}>
<div className='card'>
<canvas ref={xyCvs} id='xyCvs' height={120} width={120} style={{}}>
您的浏览器不支持canvas,请更换浏览器.
</canvas>
</div>
</Col>
</Row>
</div>
<div style={{ height: '25%' }}>
<Row>
<div style={{ height: '20%' }}>
<Row style={{ height: '100%' }}>
{
[{
k: '高度',
@ -112,22 +451,24 @@ function Index (props) {
s: '',
},].map(s => {
return (
<Col span={3} style={{ padding: 16, border: '1px solid black' }}>
<div>{s.k}</div>
<div>{s.v}</div>
<div>{s.s}</div>
<Col span={3} style={{ padding: 8, height: '100%' }}>
<div class="card">
{
s.k ?
<>
<h2>{s.k}</h2>
<p>{s.v}</p>
<span class="status">{s.s}</span>
</>
: ''
}
</div>
</Col>
)
})
}
</Row>
<div class="card">
<h2 class="card-title">商品库存</h2>
<div class="card-content">
<div class="card-number">1000</div>
<div class="card-status">正常</div>
</div>
</div>
</div>
</div>

74
console/client/src/sections/console/style.less

@ -1,53 +1,31 @@
.card {
border: 1px solid #dcdcdc;
border-radius: 5px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
padding: 20px;
margin: 10px;
width: 300px;
transition: all 0.2s ease-in-out;
background-color: #ffffff;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
padding: 16px;
height: 100%;
display: flex;
justify-content: space-between;
flex-direction: column;
justify-content: center;
align-items: center;
}
.card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
}
.card-title {
}
.card h2 {
font-size: 24px;
margin: 0;
padding-bottom: 10px;
color: #333333;
text-align: center;
text-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}
.card-content {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100%;
margin-top: 20px;
}
.card-number {
font-size: 36px;
font-weight: bold;
color: #ff5500;
text-shadow: 0 2px 5px rgba(255, 85, 0, 0.2);
margin-bottom: 10px;
}
.card-status {
font-size: 18px;
font-weight: bold;
color: #008000;
text-shadow: 0 2px 5px rgba(0, 128, 0, 0.2);
}
margin-bottom: 8px;
}
.card p {
font-size: 16px;
color: #777777;
margin-bottom: 16px;
}
.card .status {
background-color: #00cc66;
color: #ffffff;
padding: 4px 8px;
border-radius: 4px;
font-size: 14px;
text-transform: uppercase;
text-align: right;
}
Loading…
Cancel
Save