init: 路桥一把手孪生 大屏看板 项目首次入库

This commit is contained in:
XingCheng3
2026-05-29 14:50:51 +08:00
commit 6aa246f110
365 changed files with 89222 additions and 0 deletions

23
src/App.vue Normal file
View File

@@ -0,0 +1,23 @@
<template>
<div id="app">
<keep-alive>
<router-view v-if="this.$route.meta.keepAlive"/>
</keep-alive>
<router-view v-if="!this.$route.meta.keepAlive"/>
</div>
</template>
<style>
#app {
font-family: MiSans Bold, serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
}
.el-dialog__wrapper {
pointer-events: none;
}
.el-dialog {
pointer-events: auto;
}
</style>

View File

@@ -0,0 +1,31 @@
import request from '@/utils/request'
import state from '@/store'
import router from '@/router'
// 初始化日历
export function initClendar(year, month) {
return request({
url: '',
method: 'post',
data: {
UserID: state.state.user.id,
ModularID: router.currentRoute.path,
type: '1',
name: '车间生产管理工艺_基础表_工作日历_获得状态',
param: '工作年=' + year + '&工作月=' + month
}
})
}
// 修改工作状态
export function changeState(time, code) {
return request({
url: '',
method: 'post',
data: {
UserID: state.state.user.id,
ModularID: router.currentRoute.path,
type: '2',
name: '车间生产管理工艺_基础表_工作日历_设置状态',
param: '工作日期=' + time + '&工作日状态=' + code
}
})
}

View File

@@ -0,0 +1,70 @@
@font-face {
font-family: MiSans Demibold;
src: url("MiSans-Demibold.ttf");
font-weight: normal;
font-style: normal;
font-display: block;
}
@font-face {
font-family: MiSans Bold;
src: url("MiSans-Bold.ttf");
font-weight: normal;
font-style: normal;
font-display: block;
}
@font-face {
font-family: MiSans ExtraLight;
src: url("MiSans-ExtraLight.ttf");
font-weight: normal;
font-style: normal;
font-display: block;
}
@font-face {
font-family: MiSans Heavy;
src: url("MiSans-Heavy.ttf");
font-weight: normal;
font-style: normal;
font-display: block;
}
@font-face {
font-family: MiSans Light;
src: url("MiSans-Light.ttf");
font-weight: normal;
font-style: normal;
font-display: block;
}
@font-face {
font-family: MiSans Medium;
src: url("MiSans-Medium.ttf");
font-weight: normal;
font-style: normal;
font-display: block;
}
@font-face {
font-family: MiSans Normal;
src: url("MiSans-Normal.ttf");
font-weight: normal;
font-style: normal;
font-display: block;
}
@font-face {
font-family: MiSans Regular;
src: url("MiSans-Regular.ttf");
font-weight: normal;
font-style: normal;
font-display: block;
}
@font-face {
font-family: MiSans Semibold;
src: url("MiSans-Semibold.ttf");
font-weight: normal;
font-style: normal;
font-display: block;
}
@font-face {
font-family: MiSans Thin;
src: url("MiSans-Thin.ttf");
font-weight: normal;
font-style: normal;
font-display: block;
}

BIN
src/assets/gray.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
src/assets/green.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
src/assets/green.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
src/assets/image/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
src/assets/image/2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 481 KiB

BIN
src/assets/image/3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
src/assets/image/GQlogo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

BIN
src/assets/image/MSlogo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
src/assets/image/MT.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

BIN
src/assets/image/OP1010.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 MiB

BIN
src/assets/image/OP1010.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

BIN
src/assets/image/OP1020.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

BIN
src/assets/image/OP1030.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 MiB

BIN
src/assets/image/OP6010.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

BIN
src/assets/image/OP6010.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

BIN
src/assets/image/OP6020.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 566 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 765 KiB

BIN
src/assets/image/OP6030.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

BIN
src/assets/image/OP6040.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 413 KiB

BIN
src/assets/image/OP6050.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 KiB

BIN
src/assets/image/OP6060.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 KiB

BIN
src/assets/image/OP6070.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 524 KiB

BIN
src/assets/image/OP6080.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 483 KiB

BIN
src/assets/image/OP6090.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 360 KiB

BIN
src/assets/image/OP6100.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 490 KiB

BIN
src/assets/image/OP6110.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 439 KiB

BIN
src/assets/image/OP6120.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 383 KiB

BIN
src/assets/image/OP6130.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 400 KiB

BIN
src/assets/image/OP6140.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 511 KiB

BIN
src/assets/image/OP6150.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 352 KiB

BIN
src/assets/image/OP6160.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 460 KiB

BIN
src/assets/image/OP6170.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 388 KiB

BIN
src/assets/image/OP6180.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 651 KiB

BIN
src/assets/image/OP6190.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 769 KiB

BIN
src/assets/image/OP6200.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 KiB

BIN
src/assets/image/OP6210.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 KiB

BIN
src/assets/image/TZ.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
src/assets/image/TZlogo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
src/assets/image/WCLOGO.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
src/assets/image/bg.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 704 KiB

BIN
src/assets/image/call.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

BIN
src/assets/image/left1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

BIN
src/assets/image/left2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
src/assets/image/left3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

BIN
src/assets/image/left4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
src/assets/image/left5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
src/assets/image/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
src/assets/image/logo1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

BIN
src/assets/image/logo2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

BIN
src/assets/image/reset.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
src/assets/image/s1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
src/assets/image/s2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

BIN
src/assets/jy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 307 KiB

BIN
src/assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

BIN
src/assets/purple.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

BIN
src/assets/red.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
src/assets/red.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
src/assets/sad.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
src/assets/smile.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
src/assets/usual.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
src/assets/yellow.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

BIN
src/assets/yellow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
src/assets/哭脸.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
src/components/DMT.zip Normal file

Binary file not shown.

View File

@@ -0,0 +1,890 @@
<template>
<div style="height: 100%">
<div
id="viewPort"
:style="{height: containerHeight,width: containerWidth}"
style="display: flex;align-items: center;justify-content: center;"></div>
<div ref="modelProcess" style="position: absolute;top: 10px;left: 2px;color: white">正在加载模型0%</div>
<div style="display: none">
<audio id="alarm" controls loop>
<source src="../../../public/alarm.mp3" type="audio/mpeg">
</audio>
<audio id="clash" controls>
<source src="../../../public/alarm.mp3" type="audio/mpeg">
</audio>
</div>
</div>
</template>
<script>
import * as THREE from './build/three.module'
import axios from 'axios'
import { EXRLoader } from './jsm/loaders/EXRLoader.js'
import { GLTFLoader } from './jsm/loaders/GLTFLoader.js'
import { DRACOLoader } from './jsm/loaders/DRACOLoader.js'
import * as TWEEN from './jsm/libs/tween.module.js'
import { DmtControl } from './js/DmtControl.js'
import { connect } from './js/websocketConnect.js'
import { connectMqtt } from './js/MqttConnect.js'
import { PlaySoundCommand } from './js/PlaySoundCommand.js'
import SpriteText from './js/three-spritetext.module.js'
import { acceleratedRaycast, computeBoundsTree, disposeBoundsTree } from './libs/bvh'
THREE.Mesh.prototype.raycast = acceleratedRaycast
THREE.BufferGeometry.prototype.computeBoundsTree = computeBoundsTree
THREE.BufferGeometry.prototype.disposeBoundsTree = disposeBoundsTree
let container, scene, camera, axesHelper, renderer
let modelCount = 0
const editor = {
cameraStateZoom: 25,
addEventListener: THREE.EventDispatcher.prototype.addEventListener,
removeEventListener: THREE.EventDispatcher.prototype.removeEventListener,
dispatchEvent: THREE.EventDispatcher.prototype.dispatchEvent,
hasEventListener: THREE.EventDispatcher.prototype.hasEventListener,
ip: '',
scene: null,
objectIdUUidMap: new Map(),
opname: '',
connectType: 2,
BSport: '',
IsAllowConnect: true,
service: axios.create({
baseURL: './submit/MESCommonBase.ashx',
timeout: 1500000 // 请求超时时间
}),
selected: null,
socket: null,
mqttClient: {
connected: false
},
ProjectCode: null,
sceneConfig: null,
resourcesTree: null,
attachments: null,
resources: null,
cameraState: null,
cameraStateAll: [],
isOk: false,
objectIdSet: new Map(),
animOperations: null,
CraftList: {},
moveTrigger: null,
camera: null,
cameraPosition: 10,
currentButton: 1,
cameraControls: null,
TagActList: {}, // 存放tag对应的类型
worker: {}, // 播放工艺的线程
RotationWorker: {}, // 自传工艺的线程
ModelRotateWorker: {}, // 自传工艺的的状态数据
rotateSpeed: 5 * Math.PI / 180,
getObjectById: null, // 方法 根据ModelId获取模型
solveAttachModel: null, // 方法 处理attach问题
removeObject: null, // 方法 移除模型
setModelWireFrame: null, // 方法 设置线框
setTransparent: null, // 方法 设置透明
showMessage: null, // 方法 显示消息
drawPartTextInfo: null, // 方法 模型上显示文字
ModelLabelList: new Map(), // 模型上显示列表
playSoundCommand: new PlaySoundCommand(), // 方法 警告
attachList: new Map(), // 记录attach列表
objMaterial: new Map(),
WareHouseList: [],
WareHouse: new Map(), // 立库库存表
WareHouseBasicModel: new Map(), // 立库库存基础 零件模型需要命名为warehousepart1-100 立库定位模型需要命名为warehouse1000-1009
ProtocolIdentifiers: {
Robot_7: 'Robot_7',
Device_3: 'Device_3',
Agv_3: 'Agv_3',
Device_1: 'Device_1',
FirstPosition: 'FirstPosition',
WareHousePart: 'WareHousePart',
Robot_6: 'Robot_6',
RobotTcp: 'RobotTcp',
DrawPath: 'DrawPath',
ReLoadData: 'ReLoadData',
PlayAct: 'PlayAct',
CraftCurrOperation: 'CraftCurrOperation',
Position: 'Position',
Select: 'Select',
DragMove: 'DragMove',
ModelTransparent: 'ModelTransparent',
Visible: 'Visible',
Frames: 'Frames',
ModelRotation: 'ModelRotation',
GoHome: 'GoHome',
GetJointAxisInfo: 'GetJointAxisInfo',
GetDeviceBaseTool: 'GetDeviceBaseTool',
GetJointValue: 'GetJointValue',
C_B_ImportModel: 'C_B_ImportModel',
SendURDF: 'SendURDF',
SendDeviceJson: 'SendDeviceJson',
GetDeviceJson: 'GetDeviceJson',
SendMotionInfo: 'SendMotionInfo',
C_B_ImportLayout: 'C_B_ImportLayout',
GetPoseLocation: 'GetPoseLocation',
C_B_SetProjectCode: 'C_B_SetProjectCode',
C_B_TagIDTrigger: 'C_B_TagIDTrigger',
C_B_ReLoad_TagIDHandler: 'C_B_ReLoad_TagIDHandler',
C_B_SetCurrSignalList: 'C_B_SetCurrSignalList',
SendClearModelInfo: 'SendClearModelInfo',
C_B_SaveProjectSimulationData: 'C_B_SaveProjectSimulationData',
C_B_GetProjectSimulationData: 'C_B_GetProjectSimulationData',
C_B_KinematicsEditing: 'C_B_KinematicsEditing',
C_B_SaveModel: 'C_B_SaveModel',
C_B_ObjectAlarm: 'C_B_ObjectAlarm',
C_B_JointMoveTo: 'C_B_JointMoveTo',
JointMoveTo: 'JointMoveTo' // DT|JointMoveTo|modelCode|{"J1":"1","J2":"2","J3":"3","J4":"4","J5":"5","J6":"6","J7":"7","J8":"8","J9":"9"}
},
craftPlaySolveType: {
visible: 'visible',
rotation: 'rotation',
craft: 'craft',
signalwrite: 'signalwrite',
wait: 'wait',
FrameData: 'FrameData',
attach: 'attach',
warning: 'warning'
},
FrameOperation: {
playCraft: true,
visibleObject: true,
rotationObject: true,
writeSignal: true,
waitSignal: true,
attach: true,
warning: true
},
signalSolveType: {
visible: 'visible',
rotation: 'rotation',
craft: 'craft',
targetLocation: 'targetlocation',
attach: 'attach',
warning: 'warning'
}
}
// eslint-disable-next-line no-unused-vars
let ModelListTransParentList = []
const ModelList = []
const ModelListId = []
// eslint-disable-next-line no-unused-vars
const timer = null
// eslint-disable-next-line no-unused-vars
const lastIntersectModel = null
// eslint-disable-next-line no-unused-vars
const onUpPosition = new THREE.Vector2()
var raycaster = new THREE.Raycaster()
var mouse = new THREE.Vector2()
export default {
components: {},
name: 'DMT',
props: {
containerHeight: {
type: String,
default: '100vh'
},
containerWidth: {
type: String,
default: '100vw'
}
},
data() {
return {
checked: false,
cameraData: [],
object: null,
s: null
}
},
mounted() {
const scope = this
editor.objectIdSet = new Map()
editor.objMaterial = new Map()
editor.attachList = new Map()
this.getConfig().then(res => {
if (Object.hasOwnProperty.call(res, 'robotList')) {
editor.robotList = res.robotList
}
if (Object.hasOwnProperty.call(res, 'WareHouseList')) {
editor.WareHouseList = res.WareHouseList
}
if (Object.hasOwnProperty.call(res, 'transParentList')) {
ModelListTransParentList = res.transParentList
}
if (Object.hasOwnProperty.call(res, 'connectType')) {
editor.connectType = res.connectType
}
editor.mqttHost = res.MQTTHost
editor.mqttPort = res.MQTTPort
editor.ip = res.webSocketIp
editor.opname = res.webSocketOpName
editor.BSport = res.webSocketBSport
editor.rootIp = res.NodeRootIp
this.getProjectConfig()
})
editor.showMessage = function(message, type, time = 2000) {
scope.$message({
message: message,
type: type,
duration: time,
center: true
})
}
editor.addEventListener('dmtModelDBClick', function(event) {
console.log('dmtModelDBClick', event)
})
},
created() {
},
methods: {
getConfig() {
return new Promise((resolve, reject) => {
axios.get('./DMT_WEB/config/config.json').then(res => {
const configData = res.data
resolve(configData)
}).catch(err => {
reject(err)
})
})
},
/**
* 获取项目配置文件,用于初始隐藏模型
*/
getProjectConfig() {
const P1 = new Promise(function(resolve, reject) {
axios({
method: 'get',
url: './DMT_WEB/models/DTDATA.json'
}).then((res) => {
editor.animOperations = {}
editor.moveTrigger = {}
res.data.forEach(n => {
Object.keys(n).forEach(function(key) {
/**
* 获取播放数据并解析数据
*/
if (key === 'OperationTree') {
n[key].forEach(CraftData => {
editor.CraftList[CraftData.CraftCode] = {}
editor.CraftList[CraftData.CraftCode]['CraftName'] = CraftData.CraftName
editor.CraftList[CraftData.CraftCode]['Varieties'] = CraftData.Varieties
editor.CraftList[CraftData.CraftCode]['CurrPlay'] = CraftData.CurrPlay
if (CraftData.CraftPlayData.length < 2) {
editor.animOperations[CraftData.CraftCode] = ''
} else {
editor.animOperations[CraftData.CraftCode] = JSON.parse(CraftData.CraftPlayData)
}
editor.moveTrigger[CraftData.CraftCode] = {
moveStatus: 0,
myVarSetInterval: null,
doAnimation: false,
currentFrame: 0,
pausedFrame: 0,
animOperations: editor.animOperations[CraftData.CraftCode],
simPaceTime: 20,
moveStatusPosition: 0
}
})
}
/**
* HandlerType: 1:显隐,2:自转,3行为
* HandlerCode: 模型或者工艺代码
* HandlerValue: 显隐0/1 ,自传:正负转速&axis,行为暂停播放0/1
* TagValue:信号值
*/
if (key === 'TagTriggerHandler') {
n[key].forEach(TagActListValue => {
if (editor.TagActList[TagActListValue.TagID]) {
editor.TagActList[TagActListValue.TagID].push({
HandlerType: TagActListValue.HandlerType,
HandlerCode: TagActListValue.HandlerCode,
HandlerValue: TagActListValue.HandlerValue,
TagValue: TagActListValue.TagValue,
JointType: TagActListValue.JointType,
Axis: TagActListValue.Axis,
Flip: TagActListValue.Flip,
Value: TagActListValue.Value,
ValueFactor: TagActListValue.ValueFactor
})
} else {
editor.TagActList[TagActListValue.TagID] = []
editor.TagActList[TagActListValue.TagID].push({
HandlerType: TagActListValue.HandlerType,
HandlerCode: TagActListValue.HandlerCode,
HandlerValue: TagActListValue.HandlerValue,
TagValue: TagActListValue.TagValue,
JointType: TagActListValue.JointType,
Axis: TagActListValue.Axis,
Flip: TagActListValue.Flip,
Value: TagActListValue.Value,
ValueFactor: TagActListValue.ValueFactor
})
}
})
}
})
})
resolve(1)
})
})
const P2 = new Promise(function(resolve, reject) {
axios({
method: 'get',
url: './DMT_WEB/models/RobotPlan_Process.json'
}).then((res) => {
editor.sceneConfig = res.data.sceneConfig // 场景配置
editor.attachments = res.data.attachments // 附加物体
editor.resources = res.data.resources // 场景模型资源
editor.resourcesTree = res.data.resourcesTree // 模型树
editor.cameraState = res.data.cameraState // 场景相机位置
editor.ProjectCode = res.data.ProjectCode // 项目代码
editor.resourcesTree.forEach(res => {
if (res.treeType === 'OriginModel') {
ModelList.push(res.name)
}
})
editor.resources.forEach(res => {
editor.objectIdUUidMap.set(res.id, res)
})
editor.attachments.forEach(res => {
editor.attachList.set(res.RootId, res.attachList)
})
resolve(1)
}).catch((error) => {
console.log(error)
})
})
Promise.all([P1, P2]).then(res => {
this.init()
})
},
/**
* 设定模型初始状态
*/
setModelSates() {
// 模型的显示隐藏
editor.resourcesTree.forEach(res => {
if (res.visible === '0') {
if (editor.getObjectById(res.id)) {
editor.getObjectById(res.id).visible = !!(parseInt(res.visible))
}
}
})
const treeRes = editor.resourcesTree
for (const treeResValue of treeRes) {
if (treeResValue.treeType !== 'folder') {
const currentModel = editor.getObjectById(treeResValue.id)
if (Object.hasOwnProperty.call(treeResValue, 'WireFrame') && treeResValue.WireFrame) {
editor.setModelWireFrame(currentModel, true)
}
if (Object.hasOwnProperty.call(treeResValue, 'transParent') && treeResValue.transParent) {
editor.setTransparent(treeResValue.id, 0.3)
}
if (currentModel) currentModel.visible = !!parseInt(treeResValue.visible)
}
}
},
/**
* 设定场景初始状态
* @param sceneConfig {object}
* @param sceneConfig.RenderColorModel {object}
* @param sceneConfig.RenderColorModel.color {string} '#dcdcdc'
* @param sceneConfig.RenderColorModel.image {string} base64
* @param sceneConfig.RenderColorModel.model {string} '0' '1' '2'
* @param sceneConfig.sliderToneMappingExposure {number} 1
*/
setSceneStates(sceneConfig) {
const type = sceneConfig.RenderColorModel.model
switch (type) {
case '0':
scene.background = new THREE.Color('#dcdcdc')
break
case '1':
scene.background = new THREE.Color(sceneConfig.RenderColorModel.color)
break
case '2':
if (sceneConfig.RenderColorModel.image === '') {
editor.scene.background = new THREE.Color(sceneConfig.RenderColorModel.color)
return
}
new THREE.TextureLoader().load(sceneConfig.RenderColorModel.image === '', function(texture) {
scene.background = texture
texture.dispose()
})
break
default:
scene.background = new THREE.Color('#dcdcdc')
break
}
const sliderToneMappingExposure = sceneConfig.sliderToneMappingExposure
renderer.toneMappingExposure = sliderToneMappingExposure
},
/**
* 初始化场景信息
*/
init() {
this.setEditorFunction()
const scope = this
container = document.getElementById('viewPort')
scene = new THREE.Scene()
scene.environmentRotation = new THREE.Euler(Math.PI / 2, 0, 0)
scene.backgroundRotation = new THREE.Euler(Math.PI / 2, 0, 0)
editor.scene = scene
const width = container.clientWidth
const height = container.clientHeight
const aspect = width / height
camera = new THREE.PerspectiveCamera(45, aspect, 0.01, 2000)
camera.name = 'Camera'
camera.position.set(0, 50, 100)
camera.up.set(0, 0, 1)
camera.lookAt(new THREE.Vector3(1, 1, 1))
scene.add(camera)
editor.camera = camera
axesHelper = new THREE.AxesHelper(1)
scene.add(axesHelper)
renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true })
renderer.outputColorSpace = THREE.SRGBColorSpace
renderer.setPixelRatio(window.devicePixelRatio)
renderer.setSize(container.clientWidth, container.clientHeight)
renderer.setClearColor(0xcccccc)
renderer.toneMapping = THREE.LinearToneMapping
renderer.toneMappingExposure = Math.pow(4, 0)
renderer.gammaOutput = true // 期望所有纹理和颜色需要乘以gamma输出
renderer.gammaFactor = 2.2
renderer.shadowMap.enabled = true
renderer.shadowMap.type = THREE.PCFSoftShadowMap
container.appendChild(renderer.domElement) // 指定元素节点的最后一个子节点之后添加节点
var pointLight1 = new THREE.PointLight(0xffffff, 1)
pointLight1.position.set(-2, 15, 20)
// 需要开启阴影投射
pointLight1.castShadow = true
pointLight1.shadow.mapSize.width = 2048 // 阴影贴图宽度设置为2048像素
pointLight1.shadow.mapSize.height = 2048 // 阴影贴图高度设置为2048像素
scene.add(pointLight1)
const pmremGenerator = new THREE.PMREMGenerator(renderer)
pmremGenerator.compileEquirectangularShader()
const loader = new GLTFLoader().setPath('./DMT_WEB/models/')
const dracoLoader = new DRACOLoader()
dracoLoader.setDecoderPath('./DMT_WEB/draco/')
loader.setDRACOLoader(dracoLoader)
new EXRLoader().load('./DMT_WEB/assets/IndoorEnvironment.exr', (texture) => {
const envMap = pmremGenerator.fromEquirectangular(texture).texture
scene.environment = envMap
scene.background = new THREE.Color('#081f48')
pmremGenerator.dispose()
}, undefined, undefined)
// this.setSceneStates(editor.sceneConfig)
container.appendChild(renderer.domElement)
container.addEventListener('dblclick', this.ondblclick, false)
editor.cameraControls = new DmtControl(editor.camera, renderer.domElement)
editor.cameraControls.listenToKeyEvents(window) // optional
editor.cameraControls.update()
editor.cameraControls.addEventListener('change', (e) => {
this.sendCameraState()
})
window.addEventListener('resize', this.onWindowResize, false)
editor.cameraControls.resetState(editor.cameraState.target, editor.cameraState.position, editor.cameraState.zoom0)
this.animate()
setTimeout(() => {
for (let i = 0; i < ModelList.length; i++) {
loader.load(ModelList[i] + '.glb', function(gltf) {
const currentModel = gltf.scene.children[0]
currentModel.traverse(child => {
if (child.isMesh && child['material']) {
child.geometry.computeBoundsTree({
maxLeafTris: 5,
strategy: 0
})
child.geometry.boundsTree.splitStrategy = 0
editor.objMaterial.set(child.id, child['material'])
}
if (child.isMesh) {
child.receiveShadow = true
}
})
scene.add(currentModel)
scope.setObjectByConfig(currentModel)
ModelListId.push(gltf.scene.id)
modelCount += 1
scope.$refs.modelProcess.innerText = '正在加载模型' + (modelCount / ModelList.length * 100).toFixed(2) + '%'
if (modelCount === ModelList.length) {
scope.$refs.modelProcess.style.display = 'none'
scope.lookObject(scene)
scope.setModelSates()
scope.connectService()
}
}, (xhr) => {
// eslint-disable-next-line handle-callback-err
}, (error) => {
modelCount += 1
console.log(`加载模型${ModelList[i].ModelName}出错!`)
if (modelCount === ModelList.length) {
scope.$refs.modelProcess.style.display = 'none'
scope.lookObject(scene)
scope.setModelSates()
scope.connectService()
}
})
}
}, 1000)
},
setEditorFunction() {
const scope = this
/**
* 通过ModelId获取模型
* @param ModelId
* @returns {null}
*/
editor.getObjectById = function(ModelId) {
let currentModel = null
const currentModelData = editor.objectIdSet.get(ModelId)
if (currentModelData) currentModel = currentModelData.object
return currentModel
}
/**
* attach 弃用
* @param ModelId
* @param attach
*/
editor.solveAttachModel = function(ModelId, attach = true) {
console.warn('DMT: solveAttachModel弃用')
}
/**
* 移出物体
* @param object
*/
editor.removeObject = function(object) {
if (object === null) return
if (object.parent === null) return
object.parent.remove(object)
}
/**
* 设置模型线框
* @param currentObject
* @param WireframeValue
*/
editor.setModelWireFrame = function(currentObject, WireframeValue) {
currentObject.traverse(obj => {
if (obj instanceof THREE.Mesh) {
obj.material = editor.objMaterial.get(obj.id).clone()
obj.material['wireframe'] = WireframeValue
obj.material.needsUpdate = true
}
})
}
/**
* 模型透明
* @param ModelId
* @param Opacity 透明度
*/
editor.setTransparent = function(ModelId, Opacity = 0.3) {
new Promise((resolve, reject) => {
const TransModel = editor.getObjectById(ModelId)
if (!TransModel) {
console.warn('模型不存在setTransparent')
reject(false)
} else {
TransModel.traverse(obj => {
if (obj.material) {
const material_yuan = editor.objMaterial.get(obj.id).clone()
obj.material = material_yuan
if (Opacity !== 1) {
obj.material = new THREE.MeshStandardMaterial({
color: material_yuan.color,
side: 2,
transparent: true,
opacity: Opacity
})
}
}
})
resolve(true)
}
})
}
/**
* 模型上方显示悬浮文字
* @param ModelId 模型ID
* @param TagValue 显示的位置 可以换行
*/
editor.drawPartTextInfo = function(ModelId, TagValue) {
new Promise((resolve, reject) => {
let LabelInfo = editor.ModelLabelList.get(ModelId)
const TransModel = editor.getObjectById(ModelId)
if (TransModel) {
if (!LabelInfo) {
LabelInfo = {
position: scope.getDeltaPosition(new THREE.Vector3(), { x: 0, y: 0, z: 0.5 }),
label: TagValue,
object: null
}
editor.ModelLabelList.set(ModelId, LabelInfo)
}
if (LabelInfo.object) editor.removeObject(LabelInfo.object)
if (TransModel.visible) {
LabelInfo.label = TagValue.replaceAll('\\n', '\n')
const spriteLabel = new SpriteText(LabelInfo.label, 0.2, '#000000')
// spriteLabel.borderColor = '#30ff00'
// spriteLabel.borderWidth = [0.3, 0.2]
spriteLabel.backgroundColor = 'rgb(255,183,0)'
spriteLabel.position.copy(LabelInfo.position)
LabelInfo.object = spriteLabel
TransModel.add(spriteLabel)
}
}
})
}
},
/**
* 自适应窗口尺寸
*/
onWindowResize() {
const aspect = container.clientWidth / container.clientHeight
renderer.setSize(container.clientWidth, container.clientHeight)
camera.aspect = aspect
camera.updateProjectionMatrix()
this.render()
this.sendCameraState()
},
/**
* 根据有配置文件设置模型初始化属性
* @param object
*/
setObjectByConfig(object) {
const objectId = object.userData['ModelId']
const objectResource = editor.objectIdUUidMap.get(objectId)
if (objectResource) {
object.position.copy(
new THREE.Vector3(parseFloat(objectResource.location.position.x),
parseFloat(objectResource.location.position.y),
parseFloat(objectResource.location.position.z)
))
object.quaternion.copy(
new THREE.Quaternion(parseFloat(objectResource.location.quaternion.x),
parseFloat(objectResource.location.quaternion.y),
parseFloat(objectResource.location.quaternion.z),
parseFloat(objectResource.location.quaternion.w)
))
object.visible = Boolean(parseInt(objectResource.visible))
}
},
/**
* 渲染
*/
animate() {
this.render()
requestAnimationFrame(this.animate)
editor.attachList.forEach((attackList, ModelId) => {
const ModelAttachParent = editor.getObjectById(ModelId)
if (ModelAttachParent) {
if (!ModelAttachParent.lastMatrixWorld.equals(ModelAttachParent.matrixWorld)) {
for (const attackListElement of attackList) {
const attachModel = editor.getObjectById(attackListElement.ModelId)
if (attachModel) {
const newMatrixWord = ModelAttachParent.matrixWorld.clone()
const cubeTransWorld = newMatrixWord.clone().multiply(ModelAttachParent.lastMatrixWorld.clone().invert()).clone()
const cube2OldWorld = attachModel.matrixWorld.clone()
const cube2NewWorld = cubeTransWorld.clone().multiply(cube2OldWorld)
const cube2ParentWorld = attachModel.parent.matrixWorld.clone()
const cube2ParentNew = (cube2ParentWorld.invert()).multiply(cube2NewWorld)
const position = new THREE.Vector3()
const quaternion = new THREE.Quaternion()
const scale = new THREE.Vector3()
cube2ParentNew.decompose(position, quaternion, scale)
attachModel.quaternion.copy(quaternion)
attachModel.position.copy(position)
attachModel.updateMatrixWorld()
}
}
ModelAttachParent.lastMatrixWorld = ModelAttachParent.matrixWorld.clone()
}
}
})
TWEEN.update()
},
/**
* 渲染
*/
render() {
renderer.render(scene, camera)
// this.updatePosition(editor.selected)
},
connectService() {
switch (editor.connectType) {
case 1:
connect(editor)
break
case 2:
connectMqtt(editor)
break
default:
break
}
},
/**
* 解析模型
* @param object
*/
lookObject(object) {
object.traverse(function(child) {
if (!child) return
// 避免modelId重复
if (Object.hasOwnProperty.call(child.userData, 'ModelId')) {
if (editor.objectIdSet.has(child.userData['ModelId'])) {
child.userData['ModelId'] = child.uuid
editor.objectIdSet.set(child.uuid, {
ModelId: child.id,
Name: child.name,
position: JSON.parse(JSON.stringify(child.position)),
rotation: JSON.parse(JSON.stringify(child.rotation)),
quaternion: JSON.parse(JSON.stringify(child.quaternion)),
object: child,
matrix: child.matrix.clone(),
lastValue: null
})
} else {
editor.objectIdSet.set(child.userData['ModelId'], {
ModelId: child.id,
Name: child.name,
position: JSON.parse(JSON.stringify(child.position)),
rotation: JSON.parse(JSON.stringify(child.rotation)),
quaternion: JSON.parse(JSON.stringify(child.quaternion)),
object: child,
matrix: child.matrix.clone(),
lastValue: null
})
}
}
})
for (const robotListInfo in editor.robotList) {
for (const info of editor.robotList[robotListInfo]) {
info.object = editor.getObjectById(info.ModelId)
info.matrix = info.object ? info.object.matrix.clone() : null
info.lastValue = null
}
}
object.traverse(function(child) {
child.lastMatrixWorld = child.matrixWorld.clone()
})
window.editor = editor
},
/**
* 获取鼠标位置
* @param dom
* @param x
* @param y
* @returns {number[]}
*/
getMousePosition(dom, x, y) {
const rect = dom.getBoundingClientRect()
return [(x - rect.left) / rect.width, (y - rect.top) / rect.height]
},
/**
* 双击
* @param event
*/
ondblclick(event) {
try {
const array = this.getMousePosition(container, event.clientX, event.clientY)
onUpPosition.fromArray(array)
let intersects = this.getIntersects(onUpPosition, editor.scene.children)
intersects = intersects.filter(res => {
return res.object.visible
})
if (intersects.length > 0) {
const rootObjId = intersects[0].object.userData['RootId']
editor.selected = editor.getObjectById(rootObjId)
editor.dispatchEvent({
type: 'dmtModelDBClick',
ModelId: editor.selected.userData['ModelId'],
ModelName: editor.selected.userData['name']
})
} else {
editor.selected = null
editor.dispatchEvent({
type: 'dmtModelDBClick',
ModelId: '',
ModelName: ''
})
}
} catch (e) {
editor.selected = null
editor.dispatchEvent({
type: 'dmtModelDBClick',
ModelId: '',
ModelName: ''
})
}
},
/**
* 射线检测
* @param point
* @param objects
* @returns {[]}
*/
getIntersects(point, objects) {
mouse.set((point.x * 2) - 1, -(point.y * 2) + 1)
raycaster.setFromCamera(mouse, camera)
return raycaster.intersectObjects(objects, true)
},
/**
* 发送相机距离旋转中心点的位置
* @param state
*/
sendCameraState(state) {
const ModelCenter = editor.cameraControls.target
const cameraPosition = camera.position
const cameraZoom = cameraPosition.distanceTo(ModelCenter)
this.$emit('changeCameraState', cameraZoom)// 自定义事件 传递值“子向父组件传值”
},
/**
* 实时发送双击模型的位置
*/
updatePosition() {
if (editor.selected) {
const targetPosition = editor.selected.getWorldPosition(new THREE.Vector3()).clone().project(camera)
const halfWidth = window.innerWidth / 2
const halfHeight = window.innerHeight / 2
const position = {
left: targetPosition.x * halfWidth + halfWidth - 200,
top: -targetPosition.y * halfHeight + halfHeight - 500
}
this.$emit('clickModel', editor.selected, position)// 自定义事件 传递值“子向父组件传值”
}
},
getDeltaPosition(positionModel, positionLabel) {
return new THREE.Vector3((positionLabel.x - positionModel.x), (positionLabel.y - positionModel.y), (positionLabel.z - positionModel.z))
}
}
}
</script>
<style>
html {
height: 99%;
}
body {
height: 100%;
}
#app {
height: 100%;
}
</style>

View File

@@ -0,0 +1,138 @@
import { OrbitControls } from '../jsm/controls/OrbitControls.js'
import TWEEN from '../jsm/libs/tween.module'
// import { viewCubeUpdate } from './DmtViewCube'
const _changeEvent = { type: 'change' }
class DmtControl extends OrbitControls {
constructor(object, domElement) {
super(object, domElement)
this.cubeControlDirection = {
'TOP': 'TOP',
'BOTTOM': 'BOTTOM',
'FRONT': 'FRONT',
'BACK': 'BACK',
'LEFT': 'LEFT',
'RIGHT': 'RIGHT',
'BACK-LEFT': 'BACK-LEFT',
'FRONT-LEFT': 'FRONT-LEFT',
'TOP-LEFT': 'TOP-LEFT',
'TOP-RIGHT': 'TOP-RIGHT',
'RIGHT-BOTTOM': 'RIGHT-BOTTOM',
'LEFT-BOTTOM': 'LEFT-BOTTOM',
'BACK-BOTTOM': 'BACK-BOTTOM',
'TOP-FRONT': 'TOP-FRONT',
'FRONT-BOTTOM': 'FRONT-BOTTOM',
'TOP-BACK': 'TOP-BACK',
'RIGHT-FRONT': 'RIGHT-FRONT',
'BACK-RIGHT': 'BACK-RIGHT',
'BACK-RIGHT-BOTTOM': 'BACK-RIGHT-BOTTOM',
'TOP-RIGHT-BACK': 'TOP-RIGHT-BACK',
'TOP-LEFT-BACK': 'TOP-LEFT-BACK',
'TOP-LEFT-FRONT': 'TOP-LEFT-FRONT',
'FRONT-BOTTOM-RIGHT': 'FRONT-BOTTOM-RIGHT',
'TOP-RIGHT-FRONT': 'TOP-RIGHT-FRONT',
'BACK-BOTTOM-LEFT': 'BACK-BOTTOM-LEFT',
'FRONT-BOTTOM-LEFT': 'FRONT-BOTTOM-LEFT'
}
const scope = this
const STATE = {
NONE: -1,
ROTATE: 0,
DOLLY: 1,
PAN: 2,
TOUCH_ROTATE: 3,
TOUCH_PAN: 4,
TOUCH_DOLLY_PAN: 5,
TOUCH_DOLLY_ROTATE: 6
}
// eslint-disable-next-line no-unused-vars
let state = STATE.NONE
this.resetState = function(target0, position0, zoom0) {
scope.target.copy(target0)
scope.object.position.copy(position0)
if (scope.object.isOrthographicCamera) {
scope.object.zoom = zoom0
} else {
scope.object.zoom = 1
}
scope.object.updateProjectionMatrix()
scope.dispatchEvent(_changeEvent)
scope.update()
state = STATE.NONE
// viewCubeUpdate()
}
this.resetStateTween = function(target1, current1, target2, current2, duration) {
const scope = this
const positionVar = {
x1: current1.x,
y1: current1.y,
z1: current1.z,
x2: target1.x,
y2: target1.y,
z2: target1.z
}
// 关闭控制器
scope.enabled = false
var tween = new TWEEN.Tween(positionVar)
tween.to({
x1: current2.x,
y1: current2.y,
z1: current2.z,
x2: target2.x,
y2: target2.y,
z2: target2.z
}, duration)
tween.onUpdate(function() {
scope.object.position.x = positionVar.x1
scope.object.position.y = positionVar.y1
scope.object.position.z = positionVar.z1
scope.target.x = positionVar.x2
scope.target.y = positionVar.y2
scope.target.z = positionVar.z2
scope.object.updateProjectionMatrix()
scope.update()
})
tween.start()
tween.onComplete(function() {
// /开启控制器
scope.enabled = true
})
tween.easing(TWEEN.Easing.Cubic.InOut)
}
this.setLookAt = function(position0, target0, zoom0) {
scope.target.copy(target0)
scope.object.position.copy(position0)
scope.object.zoom = zoom0
scope.object.updateProjectionMatrix()
scope.dispatchEvent(_changeEvent)
scope.update()
state = STATE.NONE
}
this.setLookAt1 = function(target0, rotation) {
scope.target.copy(this.target)
scope.object.rotation.copy(rotation)
scope.object.updateProjectionMatrix()
scope.dispatchEvent(_changeEvent)
scope.update()
state = STATE.NONE
}
this.moveTo = function(x, y, z) {
scope.target.set(x, y, z)
}
this.getState = function() {
return {
target: scope.target.clone(),
position: scope.object.position.clone(),
zoom: parseFloat(scope.object.zoom.toString())
}
}
}
}
export {
DmtControl
}

View File

@@ -0,0 +1,78 @@
import { WebsocketMessageReceive } from './WebSocketMessage.js'
import mqtt from 'mqtt'
function connectMqtt(editor) {
const connection = {
host: editor.mqttHost,
port: editor.mqttPort,
endpoint: '/mqtt',
clean: true, // 保留会话
connectTimeout: 4000, // 超时时间
reconnectPeriod: 4000, // 重连时间间隔
// 认证信息
clientId: 'mqttjs_3be2c321' + new Date().getTime(), // 同一个ID 无法二次连接
username: '',
password: ''
}
const subscription = {
topic: editor.opname,
qos: 0
}
const websocketMessageReceive = new WebsocketMessageReceive(editor)
const { host, port, endpoint, ...options } = connection
const wsHeaderString = location.protocol === 'https:' ? 'wss' : 'ws'
// const connectUrl = `${wsHeaderString}://${location.host}${endpoint}`
const connectUrl = `${wsHeaderString}://${host}:${port}${endpoint}`
console.log(connectUrl)
try {
editor.mqttClient = mqtt.connect(connectUrl, options)
} catch (error) {
console.log('MQTT connect error', error)
}
editor.mqttClient.on('connect', () => {
editor.showMessage('加载完成连接MQTT服务器成功', 'success', 2000)
console.log('MQTT Connection succeeded!')
editor.isOk = true
const { topic, qos } = subscription
editor.mqttClient.subscribe(topic, { qos }, (error, res) => {
if (error) {
console.log('Subscribe to topics error', error)
return
}
websocketMessageReceive.getOriginTagValue()
})
})
editor.mqttClient.on('error', error => {
console.log('MQTT Connection failed', error)
try {
editor.showMessage('MQTT服务器连接失败', 'error', 2000)
editor.socket.close()
if (editor.IsAllowConnect) {
// 显示一下
editor.showMessage('重新连接MQTT服务器', 'warning', 2000)
console.log('重新连接MQTT服务器')
// 重新连接,打开计时器
setTimeout(function() {
connectMqtt(editor)
}, 5000)
}
} catch (exception) {
const error = exception.toString()
editor.showMessage.error('MQTT服务器出现错误,关闭连接' + error, 'error', 2000)
}
})
// 接收消息
editor.mqttClient.on('message', (topic, message) => {
try {
websocketMessageReceive.websocketMessage({ data: message.toString() })
} catch (exception) {
console.log(exception.toString())
}
})
editor.mqttClient.on('close', () => {
editor.mqttClient.end()
})
}
export { connectMqtt }

View File

@@ -0,0 +1,40 @@
import * as THREE from '../build/three.module'
/**
* @param editor Editor
* @param object THREE.Object3D
* @constructor
*/
class ObjectAlarmCommand {
constructor(editor, ModelId) {
this.type = 'ObjectAlarmCommand'
this.ModelId = ModelId
this.editor = editor
this.object = editor.getObjectById(ModelId)
}
exec(isAlarm = true) {
if (!this.object) return
if (isAlarm) {
this.object.traverse(object => {
if (object instanceof THREE.Mesh && !Object.hasOwnProperty.call(object.userData, 'isAxis')) {
object.material.color = new THREE.Color('#ff0000')
object.material.side = 2
object.material.transparent = true
object.material.opacity = 0.8
}
})
// this.editor.playSoundCommand.exec('Alarm', true, this.ModelId)
} else {
this.object.traverse(object => {
if (object instanceof THREE.Mesh) {
const m = this.editor.objMaterial.get(object.id)
if (m)object.material = m.clone()
}
})
// this.editor.playSoundCommand.exec('Alarm', false, this.ModelId)
}
}
}
export { ObjectAlarmCommand }

View File

@@ -0,0 +1,58 @@
/**
* @param editor Editor
* @param object THREE.Object3D
* @constructor
*/
class PlaySoundCommand {
constructor() {
this.type = 'PlaySoundCommand'
this.PlayType = {
Alarm: 'Alarm',
Clash: 'Clash'
}
this.AlarmList = []
this.isAlarm = false
}
/**
* 系统声音
* @param type 报警Alarm 碰撞Clash 。。。。。。。
* @param state 报警/解除报警
* @param ModelId 模型ID
*/
exec(type, state = true, ModelId) {
switch (type) {
case this.PlayType.Alarm:
if (state) {
if (!this.isAlarm) this.playAlarmSound(true)
if (this.AlarmList.indexOf(ModelId) === -1) this.AlarmList.push(ModelId)
this.isAlarm = true
} else {
this.AlarmList = this.AlarmList.filter(res => { return res !== ModelId })
if (this.AlarmList.length === 0) {
this.playAlarmSound(false)
this.isAlarm = false
}
}
break
case this.PlayType.Clash:
break
default:
break
}
}
/**
*
*/
playAlarmSound(play = true) {
// const audio = document.getElementById('alarm')
// play ? audio.play() : audio.pause()
}
playClashSound(play) {
const audio = document.getElementById('clash')
play ? audio.play() : audio.pause()
}
}
export { PlaySoundCommand }

View File

@@ -0,0 +1,629 @@
import * as THREE from '../build/three.module'
import { ObjectAlarmCommand } from './ObjectAlarmCommand.js'
import * as TWEEN from '../jsm/libs/tween.module.js'
const WebsocketMessageReceive = function(editor) {
const scope = this
this.websocketMessage = (msg) => {
new Promise((resolve, reject) => {
let returnMes
const arrays_signal = msg.data.split('|')
const m_SourceType = arrays_signal[0] // 数据类型DT数字孪生数据
const m_DeviceType = arrays_signal[1] // 设备类型Robot机器人类型的设备Device普通设备
const m_DeviceName = arrays_signal[2] // 设备名称
const m_DevicePartName = arrays_signal[3] // 设备运动部件
const m_DevicePartDate = arrays_signal[4] // 设备运动部件数据
switch (m_SourceType) {
case 'DT':
switch (m_DeviceType) {
case editor.ProtocolIdentifiers.Robot_7: // 接受机器人运动数据进行播放 --------------------------现场用----------------
returnMes = scope.deviceMoveEvent.RobotTranslation7(m_DeviceName, m_DevicePartName, m_DevicePartDate)
break
case editor.ProtocolIdentifiers.Device_3:
console.log('设备运行')// --------------------------现场用----------------
returnMes = scope.deviceMoveEvent.DeviceThreeAxis(m_DeviceName, m_DevicePartName, m_DevicePartDate)
break
case editor.ProtocolIdentifiers.Agv_3:// --------------------------现场用----------------
console.log('AGV运行')
returnMes = scope.deviceMoveEvent.AGVThreeAxis(m_DeviceName, m_DevicePartName, m_DevicePartDate)
break
case editor.ProtocolIdentifiers.Device_1: // 接受设备运动数据进行播放,已更新
break
case editor.ProtocolIdentifiers.FirstPosition: // 接受第一个点的数据,瞬间跳到该点,已更新
break
case editor.ProtocolIdentifiers.WareHousePart: //
returnMes = scope.drawWareHousePartOne(m_DeviceName)
break
case editor.ProtocolIdentifiers.Robot_6: // 接受机器人运动数据进行播放
returnMes = scope.deviceMoveEvent.RobotTranslation(m_DeviceName, m_DevicePartName, m_DevicePartDate)
break
case editor.ProtocolIdentifiers.ReLoadData: // 加载所有要播放的数据,避免资源浪费 ***********************UUID测试好用了******************************
break
case editor.ProtocolIdentifiers.PlayAct: // 根据ID 播放数据 状态为1 0暂停 ***********************UUID测试好用了******************************
scope.playActData(m_DeviceName, parseInt(m_DevicePartName))
break
// case editor.ProtocolIdentifiers.ModelTransparent: // 根据传过来的模型名字和透明度 改变模型的透明度 ***********************UUID测试好用了******************************
// returnMes = scope.robotPlan_ModelOperation.modelTrans(m_DeviceName, m_DevicePartName)
// break
case editor.ProtocolIdentifiers.Visible: // 接受CS指令显示、隐藏模型 ***********************UUID测试好用了******************************
returnMes = scope.visibleObjectToBS(m_DeviceName, m_DevicePartName)
break
case 'JointMoveTo':
if (!JSON.parse(m_DevicePartName)) console.log('JointMoveTo数据不对' + m_DevicePartName)
this.JointMoveTo(m_DeviceName, JSON.parse(m_DevicePartName))
break
case editor.ProtocolIdentifiers.C_B_TagIDTrigger:
{
const tag = JSON.parse(m_DeviceName)
scope.solveTagValue(tag.TagID, tag.TagValue)
}
break
case editor.ProtocolIdentifiers.C_B_ObjectAlarm:
{
const Info = JSON.parse(m_DeviceName)
console.log(Info)
for (const infoElement of Info) {
new ObjectAlarmCommand(editor, infoElement.ModelId).exec(!!parseInt(infoElement.value))
}
}
break
case editor.ProtocolIdentifiers.C_B_JointMoveTo:
{
const MoveValueList = JSON.parse(m_DeviceName)
scope.ModelJointMoveTo(MoveValueList)
}
break
case 'showWeld':
this.showWeld(m_DeviceName, m_DevicePartName)
break
case 'showCheckOk':
this.showCheckOk(m_DeviceName, m_DevicePartName)
break
default:
returnMes = '不存在协议:' + msg
break
}
break
default:
returnMes = '不存在协议:' + msg
break
}
resolve(returnMes)
})
}
/**
* HandlerType: 1:显隐,2:自转,3:行为,4:私服位置5:附加拆离指令
* HandlerCode: 模型或者工艺代码
* HandlerValue: 显隐0/1 ,自传:正负转速&axis,行为暂停播放0/1
* TagValueTagValue: 信号值
* @param tagId
* @param tagValue
*/
this.solveTagValue = (tagId, tagValue) => {
const scope = this
const actionInfo = editor.TagActList[tagId]
if (!actionInfo) return
for (const actionInfoElement of actionInfo) {
switch (actionInfoElement.HandlerType) {
case editor.signalSolveType.warning: // 报警
if (tagValue === actionInfoElement.TagValue) {
new ObjectAlarmCommand(editor, actionInfoElement.HandlerCode).exec(!!parseInt(actionInfoElement.HandlerValue))
}
break
case editor.signalSolveType.visible: // 显隐
if (tagValue === actionInfoElement.TagValue) {
scope.visibleObjectToBS(actionInfoElement.HandlerCode, parseInt(actionInfoElement.HandlerValue))
}
break
case editor.signalSolveType.rotation: // 自转
if (tagValue === actionInfoElement.TagValue) {
const ValueFactor = actionInfoElement.ValueFactor
const Axis = actionInfoElement.Axis
// const JointType = actionInfoElement.JointType
const Flip = actionInfoElement.Flip
const ModelCode = actionInfoElement.HandlerCode
scope.modelRotation(ModelCode, Axis, Flip * parseFloat(ValueFactor))
}
break
case editor.signalSolveType.craft: // 行为
if (tagValue === actionInfoElement.TagValue) {
scope.playActData(actionInfoElement.HandlerCode, parseInt(actionInfoElement.HandlerValue))
}
break
case editor.signalSolveType.targetLocation: // 伺服位置
scope.solveServoSignal(actionInfoElement, tagValue)
break
case editor.signalSolveType.attach: // 附加功能
console.log('这个地方的附加功能没用写')
break
default:
break
}
}
}
/**
* 根据ACTid播放动作开启线程
* @param actID
* @param state
*/
this.playActData = (actID, state) => {
const scope = this
if (!editor.isOk) return
if (!editor.worker[actID]) editor.worker[actID] = new Worker('./DMT_WEB/webWorker/playFunction.js')
if (editor.moveTrigger[actID].moveStatus !== state) {
editor.worker[actID].postMessage({
ActID: actID,
State: state,
isOk: editor.isOk,
craftPlaySolveType: editor.craftPlaySolveType,
moveTrigger: JSON.stringify(editor.moveTrigger[actID])
})
editor.moveTrigger[actID].moveStatus = state
}
editor.worker[actID].onmessage = function(event) {
editor.moveTrigger[actID].myVarSetInterval = event.data.myVarSetInterval
editor.moveTrigger[actID].currentFrame = event.data.pausedFrame
const currentFrameData = event.data.currentFrameData
const frameType = event.data.frameType
// editor.solveAttachModel('', true)
switch (frameType) {
case editor.craftPlaySolveType.attach:
if (editor.FrameOperation.attach) {
const position = currentFrameData['AttachToModelCode']
const List_AttachModel = currentFrameData['List_AttachModel']
const IsTwoWay = currentFrameData['IsTwoWay']
const IsAttach = currentFrameData['IsAttach']
if (IsAttach) {
const attachData = []
for (const editorElement of List_AttachModel) {
attachData.push({
ModelId: editorElement.ModelCode,
ModelName: editorElement.ModelName,
RootId: position,
IsTwoWay: IsTwoWay
})
}
editor.attachList.set(position, attachData)
} else {
for (const detachData of List_AttachModel) {
const detachModelCode = detachData.ModelCode
editor.scene.attach(editor.getObjectById(detachModelCode))
editor.attachList.forEach((value, key) => {
const attachList = value.filter(res => { return res.ModelId !== detachModelCode })
editor.attachList.set(key, attachList)
})
}
}
}
break
case editor.craftPlaySolveType.visible:
if (editor.FrameOperation.visibleObject) {
const position = currentFrameData['ModelCode']
const Visible = parseInt(currentFrameData['Visible'])
scope.visibleObjectToBS(position, Visible)
}
break
case editor.craftPlaySolveType.rotation:
if (editor.FrameOperation.rotationObject) {
const position = currentFrameData['ModelCode']
const Axis = currentFrameData['Axis']
const Rate = currentFrameData['Rate']
scope.modelRotation(position, Axis, Rate)
}
break
case editor.craftPlaySolveType.craft:
if (editor.FrameOperation.playCraft) {
const position = currentFrameData['CraftCode']
const craftState = parseInt(currentFrameData['CraftValue'])
scope.playActData(position, craftState)
}
break
case editor.craftPlaySolveType.FrameData:
{
const position = currentFrameData['i']
const objectToMove = editor.getObjectById(position)
if (objectToMove) {
if (currentFrameData.tx === 'NaN' || currentFrameData.ty === 'NaN' || currentFrameData.tz === 'NaN' || currentFrameData.qx === 'NaN' || currentFrameData.qy === 'NaN' || currentFrameData.qz === 'NaN' || currentFrameData.qw === 'NaN') {
console.log('craftDataError')
// editor.robotPlan_MessageList.execute(position, 'craftDataError')
} else {
const movePosition = new THREE.Vector3(parseFloat(currentFrameData.tx), parseFloat(currentFrameData.ty), parseFloat(currentFrameData.tz))
const nq = new THREE.Quaternion(parseFloat(currentFrameData.qx), parseFloat(currentFrameData.qy), parseFloat(currentFrameData.qz), parseFloat(currentFrameData.qw))
objectToMove.quaternion.copy(nq)
objectToMove.position.copy(movePosition)
}
}
}
break
case editor.craftPlaySolveType.warning: // 报警
if (editor.FrameOperation.warning) {
new ObjectAlarmCommand(scope.editor, currentFrameData['ModelCode']).exec(!!parseInt(currentFrameData['Visible']))
}
break
default:
delete editor.worker[event.data.ActID]
editor.moveTrigger[actID].moveStatus = 0
editor.moveTrigger[actID].myVarSetInterval = null
editor.moveTrigger[actID].currentFrame = 0
editor.moveTrigger[actID].pausedFrame = 0
break
}
// editor.solveAttachModel('', false)
}
}
/**
* 接受CS模型自转的指令
* 接受CS模型自转的指令
* @param objectNames
* @param values
* @param axis
*/
this.modelRotation = (objectNames, axis, values) => {
const scope = this
const EP = 0.000001
let dir = 0
if (!editor.getObjectById(objectNames)) return
const currentModel = editor.getObjectById(objectNames)
if ((parseFloat(values) >= -EP) && (parseFloat(values) <= EP)) {
if (editor.RotationWorker[objectNames]) {
editor.RotationWorker[objectNames].terminate()
delete editor.RotationWorker[objectNames]
delete editor.ModelRotateWorker[objectNames]
}
return
} else {
dir = 1
if (editor.RotationWorker[objectNames]) {
editor.RotationWorker[objectNames].terminate()
delete editor.RotationWorker[objectNames]
delete editor.ModelRotateWorker[objectNames]
}
}
editor.RotationWorker[objectNames] = new Worker('webWorker/modelRotation.js')
if (!editor.ModelRotateWorker[objectNames]) {
editor.ModelRotateWorker[objectNames] = {
state: 0,
myVarSetInterval: null,
doAnimation: false,
ModelCode: objectNames
}
}
editor.RotationWorker[objectNames].postMessage({
ObjectNames: objectNames,
Values: values,
Dir: dir,
ModelRotateWorker: editor.ModelRotateWorker[objectNames],
RotateSpeed: editor.rotateSpeed,
RotationValue: currentModel.rotation[axis]
})
editor.RotationWorker[objectNames].onmessage = (event) => {
scope.modelSelfRotation(currentModel, event.data.rotation, axis)
}
}
this.modelSelfRotation = (currentModel, rotation, axis) => {
currentModel.rotation[axis] = rotation
}
this.ModelJointMoveTo = (MoveValueList) => {
// TOBS?WEB?SCADAMain?DT|C_B_JointMoveTo|[{"ModelCode":"5E6D91B8-B44D-4C44-AAEF-10492E548A1A","JointType":"rotation","Axis":"x","Flip":1,"Value":0,"ValueFactor":0.017453292519943295,"Delta":0}]
// TOBS?WEB?SCADAMain?DT|C_B_JointMoveTo|[{"ModelCode":"644506B1-A05A-4E57-BBA2-C63635586C63","JointType":"position","Axis":"y","Flip":-1,"Value":-15.0,"ValueFactor":0.001,"Delta":-655.0}]
new Promise(resolve => {
for (const MoveValue of MoveValueList) {
const ModelCode = MoveValue.ModelCode
const ValueFactor = parseFloat(MoveValue.ValueFactor)
const type = MoveValue.JointType
const Value = parseFloat(MoveValue.Value)
const Flip = parseFloat(MoveValue.Flip)
const axis = MoveValue.Axis
const Delta = parseFloat(MoveValue.Delta)
const object = editor.getObjectById(ModelCode)
const originInfo = editor.objectIdSet.get(ModelCode)
if (!originInfo) return
const matrix = originInfo['matrix']
const originValue = type === 'rotation' ? originInfo[type]['_' + axis] : originInfo[type][axis]
const lastValue = originInfo['lastValue'] === null ? originValue : originInfo['lastValue']
const moveValue = Flip * (Value - Delta) * ValueFactor
if (object) {
// editor.solveAttachModel('', true)
const JointValue = originValue + moveValue
new TWEEN.Tween({
moveValue: lastValue
}).to({ moveValue: JointValue }, 100)
.onStart(function() {
originInfo['lastValue'] = JointValue
}).onUpdate(function() {
switch (type) {
case 'position':
object[type][axis] = this._object.moveValue
break
case 'rotation':
{
const moveAxis = {
x: new THREE.Vector3(1, 1, 1),
y: new THREE.Vector3(1, 1, 1),
z: new THREE.Vector3(1, 1, 1)
}
matrix.extractBasis(moveAxis.x, moveAxis.y, moveAxis.z)
const nM = new THREE.Matrix4()
nM.makeRotationAxis(moveAxis[axis], this._object.moveValue)
nM.multiply(matrix)
object.rotation.setFromRotationMatrix(nM)
object.updateWorldMatrix()
}
break
}
}).start()
// editor.solveAttachModel('', false)
} else {
console.log('模型不存在')
}
}
})
}
/**
* 接伺服类的数据
* @param ModelInfo
* @param tagValue
*/
this.solveServoSignal = (ModelInfo, tagValue) => {
try {
const type = ModelInfo.JointType
const axis = ModelInfo.Axis
const flip = ModelInfo.Flip
const Value = ModelInfo.Value
const ValueFactor = ModelInfo.ValueFactor // 倍率
const ModelId = ModelInfo.HandlerCode // 模型代码
const object = editor.getObjectById(ModelId)
const originInfo = editor.objectIdSet.get(ModelId)
if (!originInfo) return
const matrix = originInfo['matrix']
const originValue = type === 'rotation' ? originInfo[type]['_' + axis] : originInfo[type][axis]
const lastValue = originInfo['lastValue'] === null ? originValue : originInfo['lastValue']
const moveValue = flip * (parseFloat(tagValue) - Value) * ValueFactor
if (object) {
// editor.solveAttachModel('', true)
const JointValue = originValue + moveValue
new TWEEN.Tween({
moveValue: lastValue
}).to({ moveValue: JointValue }, 100)
.onStart(function() {
originInfo['lastValue'] = JointValue
})
.onUpdate(function() {
switch (type) {
case 'position':
object[type][axis] = this._object.moveValue
break
case 'rotation':
{
const moveAxis = {
x: new THREE.Vector3(1, 1, 1),
y: new THREE.Vector3(1, 1, 1),
z: new THREE.Vector3(1, 1, 1)
}
matrix.extractBasis(moveAxis.x, moveAxis.y, moveAxis.z)
const nM = new THREE.Matrix4()
nM.makeRotationAxis(moveAxis[axis], this._object.moveValue)
// nM.makeRotationAxis(moveAxis[axis], JointValue)
nM.multiply(matrix)
object.rotation.setFromRotationMatrix(nM)
object.updateWorldMatrix()
}
break
}
}).start()
// editor.solveAttachModel('', false)
}
//
// if (object) {
// editor.solveAttachModel('', true)
// object[type][axis] = originValue + (ValueFactor * flip * parseFloat(tagValue) + Value)
// editor.solveAttachModel('', false)
// }
} catch (e) {
console.log('solveServoSignal错误')
}
}
/**
* 接受机器人类的数据
* @param ModelId
* @param JointData
* @constructor
*/
this.JointMoveTo = (ModelId, JointData = {}) => {
if (editor.robotList[ModelId]) {
const ModelList = editor.robotList[ModelId]
// window.updateRobotData(ModelId, JointData)
// window.updateLabelInfoJoint(ModelId, JointData)
for (let i = 0; i < ModelList.length; i++) {
if (ModelList[i].ModelId === '') return
this.jointMoveToPromise(JointData, ModelList[i], i, ModelId)
}
}
}
this.jointMoveToPromise = (JointData, ModelListData, i, ModelId) => {
new Promise(resolve => {
const ModelIdJoint = ModelListData.ModelId
const object = ModelListData.object
const type = ModelListData.type
const axis = ModelListData.axis
const matrix = ModelListData.matrix
const flip = ModelListData.flip
const delta = parseFloat(ModelListData.delta)
const multiple = ModelListData.multiple
const originInfo = editor.objectIdSet.get(ModelIdJoint)
if (!originInfo) return
const originValue = type === 'rotation' ? originInfo[type]['_' + axis] : originInfo[type][axis]
const lastValue = ModelListData.lastValue === null ? originValue : ModelListData.lastValue
const moveValue = flip * (parseFloat(JointData['J' + (i + 1)]) - delta) * multiple
if (object) {
const JointValue = originValue + moveValue
new TWEEN.Tween({
moveValue: lastValue
}).to({ moveValue: JointValue }, 200)
.onStart(function() {
editor.robotList[ModelId][i]['lastValue'] = JointValue
})
.onUpdate(function() {
switch (type) {
case 'position':
object[type][axis] = this._object.moveValue
break
case 'rotation':
{
const moveAxis = {
x: new THREE.Vector3(1, 1, 1),
y: new THREE.Vector3(1, 1, 1),
z: new THREE.Vector3(1, 1, 1)
}
matrix.extractBasis(moveAxis.x, moveAxis.y, moveAxis.z)
const nM = new THREE.Matrix4()
nM.makeRotationAxis(moveAxis[axis], this._object.moveValue)
// nM.makeRotationAxis(moveAxis[axis], JointValue)
nM.multiply(matrix)
object.rotation.setFromRotationMatrix(nM)
object.updateWorldMatrix()
}
break
}
}).start()
}
})
}
this.getAxisValue = (axis, value) => {
return JSON.parse('{"' + axis + '":' + value + '}')
}
this.getAxisValue = (axis, value) => {
return JSON.parse('{"' + axis + '":' + value + '}')
}
this.showWeld = (ModelId, Welding) => {
// 徐工专用
if (ModelId === '46DDBCD8-D775-49A4-BB14-30015FF87595') editor.WeldLightVisible1 = !!parseInt(Welding)
if (ModelId === '1E96DED2-6EEF-469F-BFE6-8F52FB62C2B0') editor.WeldLightVisible2 = !!parseInt(Welding)
}
this.showCheckOk = (check) => {
// 徐工专用
if (parseInt(check)) {
editor.showTagList[3].title = '工件QY16KC, 检测OK'
} else {
editor.showTagList[3].title = '工件QY16KC'
}
}
/**
* 显示隐藏物体
* @param m_DeviceName
* @param isVisible
*/
this.visibleObjectToBS = (m_DeviceName, isVisible) => {
const currentModel = editor.getObjectById(m_DeviceName)
if (currentModel) {
currentModel.visible = !!parseInt(isVisible)
currentModel.traverse(res => {
res.visible = !!parseInt(isVisible)
})
currentModel.userData['visible'] = !!parseInt(isVisible)
}
}
/**
* 初始化获取TagValue
*/
this.getOriginTagValue = () => {
let msg = ''
let socketMsg = ''
const keyWord = 'B_C_DT_WebLoaded'
msg = 'DT|' + keyWord
socketMsg = editor.BSport + msg
const topic = editor.BSport.split('?')[2]
switch (editor.connectType) {
case 1:
editor.socket.send(socketMsg)
break
case 2:
editor.mqttClient.publish(topic, msg, 0, error => {
if (error) {
console.log('Publish error', error)
}
})
break
default:
break
}
}
/**
* 更新库存状态
* @param dataInfo
*/
this.drawWareHousePartOne = (dataInfo) => {
const scope = this
try {
const whInfo = JSON.parse(dataInfo)
for (const whStoreInfo of whInfo) {
const whStoreNum = whStoreInfo.Key // 库位号 唯一值
const whStoreState = whStoreInfo.Value // 立库状态
const whNum = whStoreNum.toString().substring(0, 4) // 立库号 1000一期立库 1003刀具库 1002三坐标测量库 1001机床线旁库
const currentStoreInfo = editor.WareHouse.get(whStoreNum)
if (currentStoreInfo) {
if (parseInt(whStoreState) === 0) {
// 0的时候直接移除库存
editor.removeObject(currentStoreInfo.object)
editor.WareHouse.delete(whStoreNum)
} else {
// 不一样的状态 更新
if (currentStoreInfo.whStoreState !== whStoreState) {
// 移除零件,更新库存信息信息
editor.removeObject(currentStoreInfo.object)
scope.updateStoreModel(whNum, whStoreNum, whStoreState)
currentStoreInfo.whStoreState = whStoreState
currentStoreInfo.object = null
}
}
} else {
editor.WareHouse.set(whStoreNum, {
whNum: whNum,
whStoreNum: whStoreNum,
whStoreState: whStoreState,
object: null
})
scope.updateStoreModel(whNum, whStoreNum, whStoreState)
}
}
} catch (e) {
console.log('库存解析错误')
}
}
/**
* 更新零件
* @param whNum
* @param whStoreNum
* @param whStoreState
*/
this.updateStoreModel = (whNum, whStoreNum, whStoreState) => {
try {
const basicPartModel = editor.WareHouseBasicModel.get('warehousepart' + whStoreState)
const basicWareHouseModelData = editor.WareHouseBasicModel.get('warehouse' + whNum)
if (basicPartModel && basicWareHouseModelData) {
const basicPartModelClone = basicPartModel.clone()
const basicPartModelPosition = basicWareHouseModelData[whStoreNum]
basicPartModelClone.position.copy(basicPartModelPosition.getWorldPosition(new THREE.Vector3()))
editor.scene.add(basicPartModelClone)
editor.WareHouse.get(whStoreNum).object = basicPartModelClone
}
} catch (e) {
console.log('库存模型解析错误')
}
}
}
export {
WebsocketMessageReceive
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,535 @@
import { LinearFilter, Sprite, SpriteMaterial, Texture } from '../build/three.module'
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError('Cannot call a class as a function')
}
}
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i]
descriptor.enumerable = descriptor.enumerable || false
descriptor.configurable = true
if ('value' in descriptor) descriptor.writable = true
Object.defineProperty(target, descriptor.key, descriptor)
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps)
if (staticProps) _defineProperties(Constructor, staticProps)
Object.defineProperty(Constructor, 'prototype', {
writable: false
})
return Constructor
}
function _inherits(subClass, superClass) {
if (typeof superClass !== 'function' && superClass !== null) {
throw new TypeError('Super expression must either be null or a function')
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
writable: true,
configurable: true
}
})
Object.defineProperty(subClass, 'prototype', {
writable: false
})
if (superClass) _setPrototypeOf(subClass, superClass)
}
function _getPrototypeOf(o) {
_getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
return o.__proto__ || Object.getPrototypeOf(o)
}
return _getPrototypeOf(o)
}
function _setPrototypeOf(o, p) {
_setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
o.__proto__ = p
return o
}
return _setPrototypeOf(o, p)
}
function _isNativeReflectConstruct() {
if (typeof Reflect === 'undefined' || !Reflect.construct) return false
if (Reflect.construct.sham) return false
if (typeof Proxy === 'function') return true
try {
Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function() {}))
return true
} catch (e) {
return false
}
}
function _assertThisInitialized(self) {
if (self === void 0) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called")
}
return self
}
function _possibleConstructorReturn(self, call) {
if (call && (typeof call === 'object' || typeof call === 'function')) {
return call
} else if (call !== void 0) {
throw new TypeError('Derived constructors may only return object or undefined')
}
return _assertThisInitialized(self)
}
function _createSuper(Derived) {
var hasNativeReflectConstruct = _isNativeReflectConstruct()
return function _createSuperInternal() {
var Super = _getPrototypeOf(Derived)
var result
if (hasNativeReflectConstruct) {
var NewTarget = _getPrototypeOf(this).constructor
result = Reflect.construct(Super, arguments, NewTarget)
} else {
result = Super.apply(this, arguments)
}
return _possibleConstructorReturn(this, result)
}
}
function _slicedToArray(arr, i) {
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest()
}
function _toConsumableArray(arr) {
return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread()
}
function _arrayWithoutHoles(arr) {
if (Array.isArray(arr)) return _arrayLikeToArray(arr)
}
function _arrayWithHoles(arr) {
if (Array.isArray(arr)) return arr
}
function _iterableToArray(iter) {
if (typeof Symbol !== 'undefined' && iter[Symbol.iterator] != null || iter['@@iterator'] != null) return Array.from(iter)
}
function _iterableToArrayLimit(arr, i) {
var _i = arr == null ? null : typeof Symbol !== 'undefined' && arr[Symbol.iterator] || arr['@@iterator']
if (_i == null) return
var _arr = []
var _n = true
var _d = false
var _s, _e
try {
for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) {
_arr.push(_s.value)
if (i && _arr.length === i) break
}
} catch (err) {
_d = true
_e = err
} finally {
try {
if (!_n && _i['return'] != null) _i['return']()
} finally {
if (_d) throw _e
}
}
return _arr
}
function _unsupportedIterableToArray(o, minLen) {
if (!o) return
if (typeof o === 'string') return _arrayLikeToArray(o, minLen)
var n = Object.prototype.toString.call(o).slice(8, -1)
if (n === 'Object' && o.constructor) n = o.constructor.name
if (n === 'Map' || n === 'Set') return Array.from(o)
if (n === 'Arguments' || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen)
}
function _arrayLikeToArray(arr, len) {
if (len == null || len > arr.length) len = arr.length
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]
return arr2
}
function _nonIterableSpread() {
throw new TypeError('Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.')
}
function _nonIterableRest() {
throw new TypeError('Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.')
}
var three = typeof window !== 'undefined' && window.THREE ? window.THREE // Prefer consumption from global THREE, if exists
: {
LinearFilter: LinearFilter,
Sprite: Sprite,
SpriteMaterial: SpriteMaterial,
Texture: Texture
}
var _default = /* #__PURE__*/(function(_three$Sprite) {
_inherits(_default, _three$Sprite)
var _super = _createSuper(_default)
function _default() {
var _this
var text = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''
var textHeight = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 10
var color = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'rgba(255, 255, 255, 1)'
_classCallCheck(this, _default)
_this = _super.call(this, new three.SpriteMaterial())
_this._text = ''.concat(text)
_this._textHeight = textHeight
_this._color = color
_this._backgroundColor = false // no background color
_this._padding = 0
_this._borderWidth = 0
_this._borderRadius = 0
_this._borderColor = 'white'
_this._strokeWidth = 0
_this._strokeColor = 'white'
_this._fontFace = 'Arial'
_this._fontSize = 90 // defines text resolution
_this._fontWeight = 'normal'
_this._canvas = document.createElement('canvas')
_this.material.depthTest = false
_this._genCanvas()
return _this
}
_createClass(_default, [{
key: 'text',
get: function get() {
return this._text
},
set: function set(text) {
this._text = text
this._genCanvas()
}
}, {
key: 'textHeight',
get: function get() {
return this._textHeight
},
set: function set(textHeight) {
this._textHeight = textHeight
this._genCanvas()
}
}, {
key: 'color',
get: function get() {
return this._color
},
set: function set(color) {
this._color = color
this._genCanvas()
}
}, {
key: 'backgroundColor',
get: function get() {
return this._backgroundColor
},
set: function set(color) {
this._backgroundColor = color
this._genCanvas()
}
}, {
key: 'padding',
get: function get() {
return this._padding
},
set: function set(padding) {
this._padding = padding
this._genCanvas()
}
}, {
key: 'borderWidth',
get: function get() {
return this._borderWidth
},
set: function set(borderWidth) {
this._borderWidth = borderWidth
this._genCanvas()
}
}, {
key: 'borderRadius',
get: function get() {
return this._borderRadius
},
set: function set(borderRadius) {
this._borderRadius = borderRadius
this._genCanvas()
}
}, {
key: 'borderColor',
get: function get() {
return this._borderColor
},
set: function set(borderColor) {
this._borderColor = borderColor
this._genCanvas()
}
}, {
key: 'fontFace',
get: function get() {
return this._fontFace
},
set: function set(fontFace) {
this._fontFace = fontFace
this._genCanvas()
}
}, {
key: 'fontSize',
get: function get() {
return this._fontSize
},
set: function set(fontSize) {
this._fontSize = fontSize
this._genCanvas()
}
}, {
key: 'fontWeight',
get: function get() {
return this._fontWeight
},
set: function set(fontWeight) {
this._fontWeight = fontWeight
this._genCanvas()
}
}, {
key: 'strokeWidth',
get: function get() {
return this._strokeWidth
},
set: function set(strokeWidth) {
this._strokeWidth = strokeWidth
this._genCanvas()
}
}, {
key: 'strokeColor',
get: function get() {
return this._strokeColor
},
set: function set(strokeColor) {
this._strokeColor = strokeColor
this._genCanvas()
}
}, {
key: '_genCanvas',
value: function _genCanvas() {
var _this2 = this
var canvas = this._canvas
var ctx = canvas.getContext('2d')
var border = Array.isArray(this.borderWidth) ? this.borderWidth : [this.borderWidth, this.borderWidth] // x,y border
var relBorder = border.map(function(b) {
return b * _this2.fontSize * 0.1
}) // border in canvas units
var borderRadius = Array.isArray(this.borderRadius) ? this.borderRadius : [this.borderRadius, this.borderRadius, this.borderRadius, this.borderRadius] // tl tr br bl corners
var relBorderRadius = borderRadius.map(function(b) {
return b * _this2.fontSize * 0.1
}) // border radius in canvas units
var padding = Array.isArray(this.padding) ? this.padding : [this.padding, this.padding] // x,y padding
var relPadding = padding.map(function(p) {
return p * _this2.fontSize * 0.1
}) // padding in canvas units
var lines = this.text.split('\n')
var font = ''.concat(this.fontWeight, ' ').concat(this.fontSize, 'px ').concat(this.fontFace)
ctx.font = font // measure canvas with appropriate font
var innerWidth = Math.max.apply(Math, _toConsumableArray(lines.map(function(line) {
return ctx.measureText(line).width
})))
var innerHeight = this.fontSize * lines.length
canvas.width = innerWidth + relBorder[0] * 2 + relPadding[0] * 2
canvas.height = innerHeight + relBorder[1] * 2 + relPadding[1] * 2 // paint border
if (this.borderWidth) {
ctx.strokeStyle = this.borderColor
if (relBorder[0]) {
// left + right borders
var hb = relBorder[0] / 2
ctx.lineWidth = relBorder[0]
ctx.beginPath()
ctx.moveTo(hb, relBorderRadius[0])
ctx.lineTo(hb, canvas.height - relBorderRadius[3])
ctx.moveTo(canvas.width - hb, relBorderRadius[1])
ctx.lineTo(canvas.width - hb, canvas.height - relBorderRadius[2])
ctx.stroke()
}
if (relBorder[1]) {
// top + bottom borders
var _hb = relBorder[1] / 2
ctx.lineWidth = relBorder[1]
ctx.beginPath()
ctx.moveTo(Math.max(relBorder[0], relBorderRadius[0]), _hb)
ctx.lineTo(canvas.width - Math.max(relBorder[0], relBorderRadius[1]), _hb)
ctx.moveTo(Math.max(relBorder[0], relBorderRadius[3]), canvas.height - _hb)
ctx.lineTo(canvas.width - Math.max(relBorder[0], relBorderRadius[2]), canvas.height - _hb)
ctx.stroke()
}
if (this.borderRadius) {
// strike rounded corners
var cornerWidth = Math.max.apply(Math, _toConsumableArray(relBorder))
var _hb2 = cornerWidth / 2
ctx.lineWidth = cornerWidth
ctx.beginPath();
[!!relBorderRadius[0] && [relBorderRadius[0], _hb2, _hb2, relBorderRadius[0]], !!relBorderRadius[1] && [canvas.width - relBorderRadius[1], canvas.width - _hb2, _hb2, relBorderRadius[1]], !!relBorderRadius[2] && [canvas.width - relBorderRadius[2], canvas.width - _hb2, canvas.height - _hb2, canvas.height - relBorderRadius[2]], !!relBorderRadius[3] && [relBorderRadius[3], _hb2, canvas.height - _hb2, canvas.height - relBorderRadius[3]]].filter(function(d) {
return d
}).forEach(function(_ref) {
var _ref2 = _slicedToArray(_ref, 4)
var x0 = _ref2[0]
var x1 = _ref2[1]
var y0 = _ref2[2]
var y1 = _ref2[3]
ctx.moveTo(x0, y0)
ctx.quadraticCurveTo(x1, y0, x1, y1)
})
ctx.stroke()
}
} // paint background
if (this.backgroundColor) {
ctx.fillStyle = this.backgroundColor
if (!this.borderRadius) {
ctx.fillRect(relBorder[0], relBorder[1], canvas.width - relBorder[0] * 2, canvas.height - relBorder[1] * 2)
} else {
// fill with rounded corners
ctx.beginPath()
ctx.moveTo(relBorder[0], relBorderRadius[0]);
[[relBorder[0], relBorderRadius[0], canvas.width - relBorderRadius[1], relBorder[1], relBorder[1], relBorder[1]], // t
[canvas.width - relBorder[0], canvas.width - relBorder[0], canvas.width - relBorder[0], relBorder[1], relBorderRadius[1], canvas.height - relBorderRadius[2]], // r
[canvas.width - relBorder[0], canvas.width - relBorderRadius[2], relBorderRadius[3], canvas.height - relBorder[1], canvas.height - relBorder[1], canvas.height - relBorder[1]], // b
[relBorder[0], relBorder[0], relBorder[0], canvas.height - relBorder[1], canvas.height - relBorderRadius[3], relBorderRadius[0]] // t
].forEach(function(_ref3) {
var _ref4 = _slicedToArray(_ref3, 6)
var x0 = _ref4[0]
var x1 = _ref4[1]
var x2 = _ref4[2]
var y0 = _ref4[3]
var y1 = _ref4[4]
var y2 = _ref4[5]
ctx.quadraticCurveTo(x0, y0, x1, y1)
ctx.lineTo(x2, y2)
})
ctx.closePath()
ctx.fill()
}
}
ctx.translate.apply(ctx, _toConsumableArray(relBorder))
ctx.translate.apply(ctx, _toConsumableArray(relPadding)) // paint text
ctx.font = font // Set font again after canvas is resized, as context properties are reset
ctx.fillStyle = this.color
ctx.textBaseline = 'bottom'
var drawTextStroke = this.strokeWidth > 0
if (drawTextStroke) {
ctx.lineWidth = this.strokeWidth * this.fontSize / 10
ctx.strokeStyle = this.strokeColor
}
lines.forEach(function(line, index) {
var lineX = (innerWidth - ctx.measureText(line).width) / 2
var lineY = (index + 1) * _this2.fontSize
drawTextStroke && ctx.strokeText(line, lineX, lineY)
ctx.fillText(line, lineX, lineY)
}) // Inject canvas into sprite
if (this.material.map) this.material.map.dispose() // gc previous texture
var texture = this.material.map = new three.Texture(canvas)
texture.minFilter = three.LinearFilter
texture.needsUpdate = true
var yScale = this.textHeight * lines.length + border[1] * 2 + padding[1] * 2
this.scale.set(yScale * canvas.width / canvas.height, yScale, 0.001)
}
}, {
key: 'clone',
value: function clone() {
return new this.constructor(this.text, this.textHeight, this.color).copy(this)
}
}, {
key: 'copy',
value: function copy(source) {
three.Sprite.prototype.copy.call(this, source)
this.color = source.color
this.backgroundColor = source.backgroundColor
this.padding = source.padding
this.borderWidth = source.borderWidth
this.borderColor = source.borderColor
this.fontFace = source.fontFace
this.fontSize = source.fontSize
this.fontWeight = source.fontWeight
this.strokeWidth = source.strokeWidth
this.strokeColor = source.strokeColor
return this
}
}])
return _default
}(three.Sprite))
export { _default as default }

View File

@@ -0,0 +1,74 @@
import { WebsocketMessageReceive } from './WebSocketMessage.js'
function connect(editor) {
const host = 'ws://' + editor.ip + '//WebModule//websocket'
let timeout = null
const websocketMessageReceive = new WebsocketMessageReceive(editor)
// 尝试连接至服务器
try {
if ('WebSocket' in window) {
editor.socket = new WebSocket(host)
} else {
editor.showMessage('浏览器不支持WebSocket', 'error', 2000)
}
} catch (exception) {
editor.showMessage('与服务器断开连接', 'error', 2000)
return
}
// 连接成功
editor.socket.onopen = function() {
// 关闭timer
try {
clearInterval(timeout)
} catch (exception) {
console.log(exception)
}
const name = editor.opname
editor.socket.send('LIN,' + name)
editor.showMessage('加载完成,连接服务器成功!', 'success', 2000)
editor.isOk = true
websocketMessageReceive.getOriginTagValue()
// let a = 0
// setInterval(() => {
// a += 0.5
// const message = `DT|JointMoveTo|0f26fc6e-1caf-4f57-beb3-d8a65872fbdd|{"J1":"${a}","J2":"0","J3":"0","J4":"0","J5":"0","J6":"0","J7":"0","J8":"0","J9":"0","J10":"0","J11":"0","J12":"0"}`
// websocketMessageReceive.websocketMessage({ data: message })
// }, 10)
}
// 收到消息
editor.socket.onmessage = function(msg) {
try {
websocketMessageReceive.websocketMessage(msg)
} catch (exception) {
const error = exception.toString()
console.log(error)
}
}
// 连接断开
editor.socket.onclose = function(event) {
try {
editor.showMessage('onclose' + '服务器连接失败', 'error', 2000)
editor.socket.close()
if (editor.IsAllowConnect) {
// 显示一下
editor.showMessage('重新连接服务器', 'warning', 2000)
console.log('onclose' + '重新连接服务器')
// 重新连接,打开计时器
timeout = setTimeout(function() {
connect(editor)
}, 5000)
}
} catch (exception) {
const error = exception.toString()
editor.showMessage.error('服务器出现错误,关闭连接' + error, 'error', 2000)
}
}
// 出现错误
editor.socket.onerror = function(event) {
console.log('onerror_' + '服务器连接失败')
editor.showMessage.error('服务器连接失败', 'error', 2000)
}
}
export { connect }

View File

@@ -0,0 +1,48 @@
<template>
<div :ref="c_id" :id="c_id" :style="c_style">
{{ c_text }}
</div>
</template>
<script>
export default {
name: 'MesTvDiv',
model: {
prop: 'c_text',
event: 'change'
},
props: {
c_id: {
default: '',
type: String,
required: true
},
c_style: {
default: () => {},
type: Object
},
c_text: {
default: '',
type: String
}
},
data() {
return {
}
},
mounted() {
// console.log(this.$refs)
},
created() {
},
methods: {
changeText(text) {
this.c_text = text
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,57 @@
<template>
<div :ref="c_id_div" :id="c_id_div" :style="c_style_div">
<img :id="c_id" :style="c_style" :src="c_base64" alt=""/>
</div>
</template>
<script>
export default {
name: 'MesTvImg',
model: {
prop: 'c_base64',
event: 'change'
},
props: {
c_id_div: {
default: '',
type: String,
required: true
},
c_style_div: {
default: () => {},
type: Object
},
c_id: {
default: '',
type: String,
required: true
},
c_style: {
default: () => {},
type: Object
},
c_base64: {
default: '',
type: String
}
},
data() {
return {
}
},
mounted() {
// console.log(this.$refs)
},
created() {
},
methods: {
changeImage(base64) {
this.c_base64 = base64
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,49 @@
// Inspired by https://github.com/Inndy/vue-clipboard2
const Clipboard = require('clipboard')
if (!Clipboard) {
throw new Error('you shold npm install `clipboard` --save at first ')
}
export default {
bind(el, binding) {
if (binding.arg === 'success') {
el._v_clipboard_success = binding.value
} else if (binding.arg === 'error') {
el._v_clipboard_error = binding.value
} else {
const clipboard = new Clipboard(el, {
text() { return binding.value },
action() { return binding.arg === 'cut' ? 'cut' : 'copy' }
})
clipboard.on('success', e => {
const callback = el._v_clipboard_success
callback && callback(e) // eslint-disable-line
})
clipboard.on('error', e => {
const callback = el._v_clipboard_error
callback && callback(e) // eslint-disable-line
})
el._v_clipboard = clipboard
}
},
update(el, binding) {
if (binding.arg === 'success') {
el._v_clipboard_success = binding.value
} else if (binding.arg === 'error') {
el._v_clipboard_error = binding.value
} else {
el._v_clipboard.text = function() { return binding.value }
el._v_clipboard.action = function() { return binding.arg === 'cut' ? 'cut' : 'copy' }
}
},
unbind(el, binding) {
if (binding.arg === 'success') {
delete el._v_clipboard_success
} else if (binding.arg === 'error') {
delete el._v_clipboard_error
} else {
el._v_clipboard.destroy()
delete el._v_clipboard
}
}
}

View File

@@ -0,0 +1,13 @@
import Clipboard from './clipboard'
const install = function(Vue) {
Vue.directive('Clipboard', Clipboard)
}
if (window.Vue) {
window.clipboard = Clipboard
Vue.use(install); // eslint-disable-line
}
Clipboard.install = install
export default Clipboard

View File

@@ -0,0 +1,46 @@
export default{
bind(el, binding) {
const dialogHeaderEl = el.querySelector('.el-dialog__header')
const dragDom = el.querySelector('.el-dialog')
dialogHeaderEl.style = 'cursor:move;'
// 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
const sty = dragDom.currentStyle || window.getComputedStyle(dragDom, null)
dialogHeaderEl.onmousedown = (e) => {
// 鼠标按下,计算当前元素距离可视区的距离
const disX = e.clientX - dialogHeaderEl.offsetLeft
const disY = e.clientY - dialogHeaderEl.offsetTop
// 获取到的值带px 正则匹配替换
let styL, styT
// 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
if (sty.left.includes('%')) {
styL = +document.body.clientWidth * (+sty.left.replace(/\%/g, '') / 100)
styT = +document.body.clientHeight * (+sty.top.replace(/\%/g, '') / 100)
} else {
styL = +sty.left.replace(/\px/g, '')
styT = +sty.top.replace(/\px/g, '')
}
document.onmousemove = function(e) {
// 通过事件委托,计算移动的距离
const l = e.clientX - disX
const t = e.clientY - disY
// 移动当前元素
dragDom.style.left = `${l + styL}px`
dragDom.style.top = `${t + styT}px`
// 将此时的位置传出去
// binding.value({x:e.pageX,y:e.pageY})
}
document.onmouseup = function(e) {
document.onmousemove = null
document.onmouseup = null
}
}
}
}

View File

@@ -0,0 +1,13 @@
import drag from './drag'
const install = function(Vue) {
Vue.directive('el-drag-dialog', drag)
}
if (window.Vue) {
window['el-drag-dialog'] = drag
Vue.use(install); // eslint-disable-line
}
drag.install = install
export default drag

91
src/directive/sticky.js Normal file
View File

@@ -0,0 +1,91 @@
const vueSticky = {}
let listenAction
vueSticky.install = Vue => {
Vue.directive('sticky', {
inserted(el, binding) {
const params = binding.value || {}
const stickyTop = params.stickyTop || 0
const zIndex = params.zIndex || 1000
const elStyle = el.style
elStyle.position = '-webkit-sticky'
elStyle.position = 'sticky'
// if the browser support css stickyCurrently Safari, Firefox and Chrome Canary
// if (~elStyle.position.indexOf('sticky')) {
// elStyle.top = `${stickyTop}px`;
// elStyle.zIndex = zIndex;
// return
// }
const elHeight = el.getBoundingClientRect().height
const elWidth = el.getBoundingClientRect().width
elStyle.cssText = `top: ${stickyTop}px; z-index: ${zIndex}`
const parentElm = el.parentNode || document.documentElement
const placeholder = document.createElement('div')
placeholder.style.display = 'none'
placeholder.style.width = `${elWidth}px`
placeholder.style.height = `${elHeight}px`
parentElm.insertBefore(placeholder, el)
let active = false
const getScroll = (target, top) => {
const prop = top ? 'pageYOffset' : 'pageXOffset'
const method = top ? 'scrollTop' : 'scrollLeft'
let ret = target[prop]
if (typeof ret !== 'number') {
ret = window.document.documentElement[method]
}
return ret
}
const sticky = () => {
if (active) {
return
}
if (!elStyle.height) {
elStyle.height = `${el.offsetHeight}px`
}
elStyle.position = 'fixed'
elStyle.width = `${elWidth}px`
placeholder.style.display = 'inline-block'
active = true
}
const reset = () => {
if (!active) {
return
}
elStyle.position = ''
placeholder.style.display = 'none'
active = false
}
const check = () => {
const scrollTop = getScroll(window, true)
const offsetTop = el.getBoundingClientRect().top
if (offsetTop < stickyTop) {
sticky()
} else {
if (scrollTop < elHeight + stickyTop) {
reset()
}
}
}
listenAction = () => {
check()
}
window.addEventListener('scroll', listenAction)
},
unbind() {
window.removeEventListener('scroll', listenAction)
}
})
}
export default vueSticky

View File

@@ -0,0 +1,13 @@
import waves from './waves'
const install = function(Vue) {
Vue.directive('waves', waves)
}
if (window.Vue) {
window.waves = waves
Vue.use(install); // eslint-disable-line
}
waves.install = install
export default waves

View File

@@ -0,0 +1,26 @@
.waves-ripple {
position: absolute;
border-radius: 100%;
background-color: rgba(0, 0, 0, 0.15);
background-clip: padding-box;
pointer-events: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-transform: scale(0);
-ms-transform: scale(0);
transform: scale(0);
opacity: 1;
}
.waves-ripple.z-active {
opacity: 0;
-webkit-transform: scale(2);
-ms-transform: scale(2);
transform: scale(2);
-webkit-transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
transition: opacity 1.2s ease-out, transform 0.6s ease-out;
transition: opacity 1.2s ease-out, transform 0.6s ease-out, -webkit-transform 0.6s ease-out;
}

View File

@@ -0,0 +1,42 @@
import './waves.css'
export default{
bind(el, binding) {
el.addEventListener('click', e => {
const customOpts = Object.assign({}, binding.value)
const opts = Object.assign({
ele: el, // 波纹作用元素
type: 'hit', // hit点击位置扩散center中心点扩展
color: 'rgba(0, 0, 0, 0.15)' // 波纹颜色
}, customOpts)
const target = opts.ele
if (target) {
target.style.position = 'relative'
target.style.overflow = 'hidden'
const rect = target.getBoundingClientRect()
let ripple = target.querySelector('.waves-ripple')
if (!ripple) {
ripple = document.createElement('span')
ripple.className = 'waves-ripple'
ripple.style.height = ripple.style.width = Math.max(rect.width, rect.height) + 'px'
target.appendChild(ripple)
} else {
ripple.className = 'waves-ripple'
}
switch (opts.type) {
case 'center':
ripple.style.top = (rect.height / 2 - ripple.offsetHeight / 2) + 'px'
ripple.style.left = (rect.width / 2 - ripple.offsetWidth / 2) + 'px'
break
default:
ripple.style.top = (e.pageY - rect.top - ripple.offsetHeight / 2 - document.body.scrollTop) + 'px'
ripple.style.left = (e.pageX - rect.left - ripple.offsetWidth / 2 - document.body.scrollLeft) + 'px'
}
ripple.style.backgroundColor = opts.color
ripple.className = 'waves-ripple z-active'
return false
}
}, false)
}
}

370
src/icon/demo.css Normal file
View File

@@ -0,0 +1,370 @@
*{margin: 0;padding: 0;list-style: none;}
/*
KISSY CSS Reset
理念1. reset 的目的不是清除浏览器的默认样式,这仅是部分工作。清除和重置是紧密不可分的。
2. reset 的目的不是让默认样式在所有浏览器下一致,而是减少默认样式有可能带来的问题。
3. reset 期望提供一套普适通用的基础样式。但没有银弹,推荐根据具体需求,裁剪和修改后再使用。
特色1. 适应中文2. 基于最新主流浏览器。
维护:玉伯<lifesinger@gmail.com>, 正淳<ragecarrier@gmail.com>
*/
/** 清除内外边距 **/
body, h1, h2, h3, h4, h5, h6, hr, p, blockquote, /* structural elements 结构元素 */
dl, dt, dd, ul, ol, li, /* list elements 列表元素 */
pre, /* text formatting elements 文本格式元素 */
form, fieldset, legend, button, input, textarea, /* form elements 表单元素 */
th, td /* table elements 表格元素 */ {
margin: 0;
padding: 0;
}
/** 设置默认字体 **/
body,
button, input, select, textarea /* for ie */ {
font: 12px/1.5 tahoma, arial, \5b8b\4f53, sans-serif;
}
h1, h2, h3, h4, h5, h6 { font-size: 100%; }
address, cite, dfn, em, var { font-style: normal; } /* 将斜体扶正 */
code, kbd, pre, samp { font-family: courier new, courier, monospace; } /* 统一等宽字体 */
small { font-size: 12px; } /* 小于 12px 的中文很难阅读,让 small 正常化 */
/** 重置列表元素 **/
ul, ol { list-style: none; }
/** 重置文本格式元素 **/
a { text-decoration: none; }
a:hover { text-decoration: underline; }
/** 重置表单元素 **/
legend { color: #000; } /* for ie6 */
fieldset, img { border: 0; } /* img 搭车:让链接里的 img 无边框 */
button, input, select, textarea { font-size: 100%; } /* 使得表单元素在 ie 下能继承字体大小 */
/* 注optgroup 无法扶正 */
/** 重置表格元素 **/
table { border-collapse: collapse; border-spacing: 0; }
/* 清除浮动 */
.ks-clear:after, .clear:after {
content: '\20';
display: block;
height: 0;
clear: both;
}
.ks-clear, .clear {
*zoom: 1;
}
.main {
padding: 30px 100px;
width: 960px;
margin: 0 auto;
}
.main h1{font-size:36px; color:#333; text-align:left;margin-bottom:30px; border-bottom: 1px solid #eee;}
.helps{margin-top:40px;}
.helps pre{
padding:20px;
margin:10px 0;
border:solid 1px #e7e1cd;
background-color: #fffdef;
overflow: auto;
}
.icon_lists{
width: 100% !important;
}
.icon_lists li{
float:left;
width: 100px;
height:180px;
text-align: center;
list-style: none !important;
}
.icon_lists .icon{
font-size: 42px;
line-height: 100px;
margin: 10px 0;
color:#333;
-webkit-transition: font-size 0.25s ease-out 0s;
-moz-transition: font-size 0.25s ease-out 0s;
transition: font-size 0.25s ease-out 0s;
}
.icon_lists .icon:hover{
font-size: 100px;
}
.markdown {
color: #666;
font-size: 14px;
line-height: 1.8;
}
.highlight {
line-height: 1.5;
}
.markdown img {
vertical-align: middle;
max-width: 100%;
}
.markdown h1 {
color: #404040;
font-weight: 500;
line-height: 40px;
margin-bottom: 24px;
}
.markdown h2,
.markdown h3,
.markdown h4,
.markdown h5,
.markdown h6 {
color: #404040;
margin: 1.6em 0 0.6em 0;
font-weight: 500;
clear: both;
}
.markdown h1 {
font-size: 28px;
}
.markdown h2 {
font-size: 22px;
}
.markdown h3 {
font-size: 16px;
}
.markdown h4 {
font-size: 14px;
}
.markdown h5 {
font-size: 12px;
}
.markdown h6 {
font-size: 12px;
}
.markdown hr {
height: 1px;
border: 0;
background: #e9e9e9;
margin: 16px 0;
clear: both;
}
.markdown p,
.markdown pre {
margin: 1em 0;
}
.markdown > p,
.markdown > blockquote,
.markdown > .highlight,
.markdown > ol,
.markdown > ul {
width: 80%;
}
.markdown ul > li {
list-style: circle;
}
.markdown > ul li,
.markdown blockquote ul > li {
margin-left: 20px;
padding-left: 4px;
}
.markdown > ul li p,
.markdown > ol li p {
margin: 0.6em 0;
}
.markdown ol > li {
list-style: decimal;
}
.markdown > ol li,
.markdown blockquote ol > li {
margin-left: 20px;
padding-left: 4px;
}
.markdown code {
margin: 0 3px;
padding: 0 5px;
background: #eee;
border-radius: 3px;
}
.markdown pre {
border-radius: 6px;
background: #f7f7f7;
padding: 20px;
}
.markdown pre code {
border: none;
background: #f7f7f7;
margin: 0;
}
.markdown strong,
.markdown b {
font-weight: 600;
}
.markdown > table {
border-collapse: collapse;
border-spacing: 0px;
empty-cells: show;
border: 1px solid #e9e9e9;
width: 95%;
margin-bottom: 24px;
}
.markdown > table th {
white-space: nowrap;
color: #333;
font-weight: 600;
}
.markdown > table th,
.markdown > table td {
border: 1px solid #e9e9e9;
padding: 8px 16px;
text-align: left;
}
.markdown > table th {
background: #F7F7F7;
}
.markdown blockquote {
font-size: 90%;
color: #999;
border-left: 4px solid #e9e9e9;
padding-left: 0.8em;
margin: 1em 0;
font-style: italic;
}
.markdown blockquote p {
margin: 0;
}
.markdown .anchor {
opacity: 0;
transition: opacity 0.3s ease;
margin-left: 8px;
}
.markdown .waiting {
color: #ccc;
}
.markdown h1:hover .anchor,
.markdown h2:hover .anchor,
.markdown h3:hover .anchor,
.markdown h4:hover .anchor,
.markdown h5:hover .anchor,
.markdown h6:hover .anchor {
opacity: 1;
display: inline-block;
}
.markdown > br,
.markdown > p > br {
clear: both;
}
.hljs {
display: block;
background: white;
padding: 0.5em;
color: #333333;
overflow-x: auto;
}
.hljs-comment,
.hljs-meta {
color: #969896;
}
.hljs-string,
.hljs-variable,
.hljs-template-variable,
.hljs-strong,
.hljs-emphasis,
.hljs-quote {
color: #df5000;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-type {
color: #a71d5d;
}
.hljs-literal,
.hljs-symbol,
.hljs-bullet,
.hljs-attribute {
color: #0086b3;
}
.hljs-section,
.hljs-name {
color: #63a35c;
}
.hljs-tag {
color: #333333;
}
.hljs-title,
.hljs-attr,
.hljs-selector-id,
.hljs-selector-class,
.hljs-selector-attr,
.hljs-selector-pseudo {
color: #795da3;
}
.hljs-addition {
color: #55a532;
background-color: #eaffea;
}
.hljs-deletion {
color: #bd2c00;
background-color: #ffecec;
}
.hljs-link {
text-decoration: underline;
}
pre{
background: #fff;
}

30
src/icon/iconfont.css Normal file
View File

@@ -0,0 +1,30 @@
@font-face {font-family: "fontFamily";
src: url('iconfont.eot?t=1527493375212'); /* IE9*/
src: url('iconfont.eot?t=1527493375212#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('data:application/x-font-woff;charset=utf-8;base64,d09GRgABAAAAAAXoAAsAAAAACHwAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABCAAAADMAAABCsP6z7U9TLzIAAAE8AAAARAAAAFZW7kf3Y21hcAAAAYAAAABjAAABnM7GacRnbHlmAAAB5AAAAfsAAAIsdf0weGhlYWQAAAPgAAAALwAAADYRguv+aGhlYQAABBAAAAAcAAAAJAfeA4VobXR4AAAELAAAABAAAAAQD+kAAGxvY2EAAAQ8AAAACgAAAAoBjAC6bWF4cAAABEgAAAAfAAAAIAEaAF1uYW1lAAAEaAAAAVMAAAKFV8s9R3Bvc3QAAAW8AAAAKgAAADsY6RIYeJxjYGRgYOBikGPQYWB0cfMJYeBgYGGAAJAMY05meiJQDMoDyrGAaQ4gZoOIAgCKIwNPAHicY2Bk/sU4gYGVgYOpk+kMAwNDP4RmfM1gxMjBwMDEwMrMgBUEpLmmMDgwVDzjZm7438AQw9zA0AAUZgTJAQAk0wx5eJzFkNENgCAMRK+ChIij+GkcyC9HYOKugdfCDxNw5JX2ckkJAHYAgVwkAvJBYHrpivsBh/sRD+fMs/GumrS0NnUm8UT2LlhSEpZJ1q2edXq9x2T/XQd8oqaO+Vo62H4fLw+3AHicLZC/b9NAFMffu6udpM0PbMdx4jQ/LhfXoDRBtpN2IGkXkArNgNQpKkiNYlSBRNd2YKiQEB0YWFDFCkiIiYEfytAJVbDTv6CFjYXSFhbsckE53dP3fZ/e6X3egQRwfkj3aBY0uAgOXIWbACjXsJIkBWR2s0FqqDNJN9JJanObRXilQTtoVOR0xp1rzhhyRE5hEovoMXfObhAbW80FcgXdTAExlzdXVGtapU9xMmsXH4U3yAvUS3w6tVAPr88upt2yFt2Mq2pOVZ9EZUmKEjKRSuJ9IxOTYpNy+EpKmfpe6RIpYTxnm91eopxX+zvNjYJlxBC3t1HLl5OvFxVTEfeBmdHUXORCIpo1E7yaxs3vU1ktXpj5BuJExK7P6A/agwmIQhxyUAAGltiXKUyxmM5GicaF4Yqns5ZnoCjqns5RBK0GlO4Hy7gTbuFRcESKu6vBvdVdAurL4DF2w/cHB1jvdGjvb5uy9Q/B3VFt1E27x8cPw2vtdpt83QIxGc6f0190A6hgmoKU+HsD8lACDpfBg3kAQ4AYo5ljRcFEecuTRG6NeSzeEpj/QTkVfl5EFofh0trp6dpY8RMOBycnwbLrkpLjBIdC3w1+zvaxduez73/x/XUc3jrDjzi8/RtXwiXx7u2Z7zhOmHbq+8JXB3/CN/1+H+AfnVR/vQB4nGNgZGBgAOLuWSW34/ltvjJwszCAwHXDy/8R9P+pLAzMeUAuBwMTSBQAWOoL7AB4nGNgZGBgbvjfwBDDwgACQJKRARWwAABHCgJtBAAAAAPpAAAEAAAABAAAAAAAAAAAdgC6ARYAAHicY2BkYGBgYQhk4GEAASYg5gJCBob/YD4DABGzAXgAeJxtkk1uwjAQhZ/LT9UgddHSdlmvWBQp/CzZooZlJRbsQ3AgKIkjxyDRXQ/Q8/QQPUE3vUHv0EcwQkIk8uibN2/GthIAd/iFwOF54DqwgMfswFe4xrPjGvWO4zq577iBFkaOm9RfHXvo4s1xC/d45wRRv2H2gk/HAm18Ob7CLb4d16j/OK6T/xw38CiE4yba4smxh5noOm6hIz68sVGhVQs538kk0nmsc+vtQxBmSbqbquUmDc1JONFMmTLRuRz4/ZM4Ubkyx3nldjm0Npax0ZkM6FFpqmVh9FpF1l9ZW4x6vdjpfqQzHm8MA4UQlnEBiTl2jAkiaOSIq2jpO1JAb8Z6St+UPUtsyCGnXHJc0mbsMiiZ7WsSA/j8ZJecEzrzyn1+vhJb7jykatkpuQz7M1Lg5ihOSMkSRVVbU4mo+1hVXQV/jR7f+MzvVzfP/gHCFnRdAHicY2BigAAuBuyAhZGJkZmRhZGVgbGCycCSI7WoPDUzN9GQgQEAJkQEKgAA') format('woff'),
url('iconfont.ttf?t=1527493375212') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
url('iconfont.svg?t=1527493375212#fontFamily') format('svg'); /* iOS 4.1- */
}
.fontFamily {
font-family:"fontFamily" !important;
font-size:16px;
font-style:normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
[class^="el-icon-cjn"], [class*=" el-icon-cjn"] {
font-family:"fontFamily" !important;
/* 以下内容参照第三方图标库本身的规则 */
font-size: 13px;
font-style:normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.el-icon-cjn-09:before { content: "\e60b"; }
.el-icon-cjn-erweima1:before { content: "\e606"; }

BIN
src/icon/iconfont.eot Normal file

Binary file not shown.

1
src/icon/iconfont.js Normal file
View File

@@ -0,0 +1 @@
(function(window) { var svgSprite = '<svg><symbol id="el-icon-cjn-09" viewBox="0 0 1024 1024"><path d="M804.141176 39.152941H39.152941v963.764706h963.764706V201.788235l-198.776471-162.635294z m-493.929411 60.235294h391.529411v180.705883h-391.529411v-180.705883z m481.882353 843.294118h-542.117647v-331.294118h542.117647v331.294118z m150.588235 0h-90.352941v-391.529412h-662.588236v391.529412h-90.352941v-843.294118h150.588236v240.941177h512v-240.941177h18.070588l162.635294 129.505883v713.788235z" fill="#2c2c2c" ></path><path d="M310.211765 671.623529h331.294117v60.235295h-331.294117zM310.211765 792.094118h210.823529v60.235294h-210.823529zM611.388235 129.505882h60.235294v120.470589h-60.235294z" fill="#2c2c2c" ></path></symbol><symbol id="el-icon-cjn-erweima1" viewBox="0 0 1024 1024"><path d="M23.92225303 998.84837371l439.58598408 0L463.50823711 559.26238962 23.92225303 559.26238962 23.92225303 998.84837371zM119.78212494 651.01398129l243.75796004 0 0 245.12738674L119.78212494 896.14136803 119.78212494 651.01398129z" ></path><path d="M23.92225303 457.92481072l439.58598408 0 0-439.58598412L23.92225303 18.33882658 23.92225303 457.92481072zM119.78212494 111.45984508l243.75796004 0 0 245.12738672L119.78212494 356.5872318 119.78212494 111.45984508z" ></path><path d="M570.32352297 18.33882658l0 439.58598414L1009.90950704 457.92481072l0-439.58598412L570.32352297 18.33882658zM911.31078166 355.21780509L667.55282162 355.21780509l0-245.12738681 243.75796004 0L911.31078166 355.21780509z" ></path><path d="M218.38085034 210.05857039l49.29936273 0 0 49.29936276-49.29936273 0 0-49.29936276Z" ></path><path d="M760.67384005 210.05857039l49.29936271 0 0 49.29936276-49.29936273 0 0-49.29936276Z" ></path><path d="M218.38085034 750.98213347l49.29936273 0 0 49.29936266-49.29936273 0 0-49.29936266Z" ></path><path d="M908.57192818 755.09041369L809.97320276 755.09041369 809.97320276 559.26238962 570.32352297 559.26238962 570.32352297 998.84837371 614.14517874 998.84837371 614.14517874 707.16047766 711.37447735 707.16047766 711.37447735 805.75920314 1009.90950704 805.75920314 1009.90950704 559.26238962 908.57192818 559.26238962Z" ></path><path d="M711.37447735 901.61907503l99.96815218 0 0 97.22929868-99.96815218 0 0-97.22929868Z" ></path><path d="M909.94135491 901.61907503l99.96815213 0 0 97.22929868-99.96815213 0 0-97.22929868Z" ></path></symbol></svg>'; var script = (function() { var scripts = document.getElementsByTagName('script'); return scripts[scripts.length - 1] }()); var shouldInjectCss = script.getAttribute('data-injectcss'); var ready = function(fn) { if (document.addEventListener) { if (~['complete', 'loaded', 'interactive'].indexOf(document.readyState)) { setTimeout(fn, 0) } else { var loadFn = function() { document.removeEventListener('DOMContentLoaded', loadFn, false); fn() }; document.addEventListener('DOMContentLoaded', loadFn, false) } } else if (document.attachEvent) { IEContentLoaded(window, fn) } function IEContentLoaded(w, fn) { var d = w.document, done = false, init = function() { if (!done) { done = true; fn() } }; var polling = function() { try { d.documentElement.doScroll('left') } catch (e) { setTimeout(polling, 50); return }init() }; polling(); d.onreadystatechange = function() { if (d.readyState == 'complete') { d.onreadystatechange = null; init() } } } }; var before = function(el, target) { target.parentNode.insertBefore(el, target) }; var prepend = function(el, target) { if (target.firstChild) { before(el, target.firstChild) } else { target.appendChild(el) } }; function appendSvg() { var div, svg; div = document.createElement('div'); div.innerHTML = svgSprite; svgSprite = null; svg = div.getElementsByTagName('svg')[0]; if (svg) { svg.setAttribute('aria-hidden', 'true'); svg.style.position = 'absolute'; svg.style.width = 0; svg.style.height = 0; svg.style.overflow = 'hidden'; prepend(svg, document.body) } } if (shouldInjectCss && !window.__iconfont__svg__cssinject__) { window.__iconfont__svg__cssinject__ = true; try { document.write('<style>.svgfont {display: inline-block;width: 1em;height: 1em;fill: currentColor;vertical-align: -0.1em;font-size:16px;}</style>') } catch (e) { console && console.log(e) } }ready(appendSvg) })(window)

39
src/icon/iconfont.svg Normal file
View File

@@ -0,0 +1,39 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<!--
2013-9-30: Created.
-->
<svg>
<metadata>
Created by iconfont
</metadata>
<defs>
<font id="fontFamily" horiz-adv-x="1024" >
<font-face
font-family="fontFamily"
font-weight="500"
font-stretch="normal"
units-per-em="1024"
ascent="896"
descent="-128"
/>
<missing-glyph />
<glyph glyph-name="x" unicode="x" horiz-adv-x="1001"
d="M281 543q-27 -1 -53 -1h-83q-18 0 -36.5 -6t-32.5 -18.5t-23 -32t-9 -45.5v-76h912v41q0 16 -0.5 30t-0.5 18q0 13 -5 29t-17 29.5t-31.5 22.5t-49.5 9h-133v-97h-438v97zM955 310v-52q0 -23 0.5 -52t0.5 -58t-10.5 -47.5t-26 -30t-33 -16t-31.5 -4.5q-14 -1 -29.5 -0.5
t-29.5 0.5h-32l-45 128h-439l-44 -128h-29h-34q-20 0 -45 1q-25 0 -41 9.5t-25.5 23t-13.5 29.5t-4 30v167h911zM163 247q-12 0 -21 -8.5t-9 -21.5t9 -21.5t21 -8.5q13 0 22 8.5t9 21.5t-9 21.5t-22 8.5zM316 123q-8 -26 -14 -48q-5 -19 -10.5 -37t-7.5 -25t-3 -15t1 -14.5
t9.5 -10.5t21.5 -4h37h67h81h80h64h36q23 0 34 12t2 38q-5 13 -9.5 30.5t-9.5 34.5q-5 19 -11 39h-368zM336 498v228q0 11 2.5 23t10 21.5t20.5 15.5t34 6h188q31 0 51.5 -14.5t20.5 -52.5v-227h-327z" />
<glyph glyph-name="09" unicode="&#58891;" d="M804.141 856.847h-764.988v-963.765h963.765v801.129l-198.776 162.635zM310.212 796.612h391.529v-180.706h-391.529v180.706zM792.094-46.682h-542.118v331.294h542.118v-331.294zM942.682-46.682h-90.353v391.529h-662.588v-391.529h-90.353v843.294h150.588v-240.941h512v240.941h18.071l162.635-129.506v-713.788zM310.212 224.376h331.294v-60.235h-331.294zM310.212 103.906h210.824v-60.235h-210.824zM611.388 766.494h60.235v-120.471h-60.235z" horiz-adv-x="1024" />
<glyph glyph-name="erweima1" unicode="&#58886;" d="M23.92225303-102.84837371000003l439.58598408 0L463.50823711 336.73761038 23.92225303 336.73761038 23.92225303-102.84837371000003zM119.78212494 244.98601871000005l243.75796004 0 0-245.12738674L119.78212494-0.1413680299999669 119.78212494 244.98601871000005zM23.92225303 438.07518928l439.58598408 0 0 439.58598412L23.92225303 877.66117342 23.92225303 438.07518928zM119.78212494 784.54015492l243.75796004 0 0-245.12738672L119.78212494 539.4127682000001 119.78212494 784.54015492zM570.32352297 877.66117342l0-439.58598414L1009.90950704 438.07518928l0 439.58598412L570.32352297 877.66117342zM911.31078166 540.78219491L667.55282162 540.78219491l0 245.12738681 243.75796004 0L911.31078166 540.78219491zM218.38085034 685.94142961l49.29936273 0 0-49.29936276-49.29936273 0 0 49.29936276ZM760.67384005 685.94142961l49.29936271 0 0-49.29936276-49.29936273 0 0 49.29936276ZM218.38085034 145.01786653l49.29936273 0 0-49.29936266-49.29936273 0 0 49.29936266ZM908.57192818 140.90958631L809.97320276 140.90958631 809.97320276 336.73761038 570.32352297 336.73761038 570.32352297-102.84837371000003 614.14517874-102.84837371000003 614.14517874 188.83952234000003 711.37447735 188.83952234000003 711.37447735 90.24079686000005 1009.90950704 90.24079686000005 1009.90950704 336.73761038 908.57192818 336.73761038ZM711.37447735-5.619075029999976l99.96815218 0 0-97.22929868-99.96815218 0 0 97.22929868ZM909.94135491-5.619075029999976l99.96815213 0 0-97.22929868-99.96815213 0 0 97.22929868Z" horiz-adv-x="1024" />
</font>
</defs></svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
src/icon/iconfont.ttf Normal file

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More