functionFan3.vue 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064
  1. <template>
  2. <div style="width: 100%; height: calc(100%); background: #fff; display: flex">
  3. <div class="ablockly">
  4. <div id="blocklyDiv"></div>
  5. <xml id="toolbox" style="display: none">
  6. <category name="逻辑" colour="%{BKY_LOGIC_HUE}">
  7. <block type="controls_if"></block>
  8. <block type="logic_compare"></block>
  9. <block type="logic_operation"></block>
  10. <block type="logic_negate"></block>
  11. <block type="logic_boolean"></block>
  12. <block type="logic_number"></block>
  13. </category>
  14. <sep></sep>
  15. <category name="循环" colour="#5ba55b">
  16. <block type="controls_repeat_forever"></block>
  17. <block type="controls_whileUntil"></block>
  18. <block type="controls_for"></block>
  19. </category>
  20. <sep></sep>
  21. <category id="catIOTScreen" name="屏幕" colour="#5cb2d6">
  22. <block type="iot_lcd_screeninit"></block>
  23. </category>
  24. <sep></sep>
  25. <category id="cat" name="人脸识别" colour="#ee783a">
  26. <block type="iot_lcd_faceinit"></block>
  27. </category>
  28. <sep></sep>
  29. <category id="police" name="电子警察组件" colour="#1b5873">
  30. <block type="iot_lcd_policeinit"></block>
  31. </category>
  32. <sep></sep>
  33. <category id="police" name="AI组件" colour="#935ba5">
  34. <block type="ai_gesture"></block>
  35. <block type="ai_motor"></block>
  36. </category>
  37. </xml>
  38. </div>
  39. <div class="container">
  40. <div class="img">
  41. <div class="left" style="width: 120px"></div>
  42. <div class="controlZ">
  43. <div id="fan" ref="fan">
  44. <img :src="img[0]" alt />
  45. </div>
  46. <div id="fanB">
  47. <img :src="img[6]" alt />
  48. </div>
  49. <div id="motor">
  50. <img :src="img[1]" alt />
  51. </div>
  52. <div id="base">
  53. <img :src="img[2]" alt />
  54. </div>
  55. <div id="a4">
  56. <img :src="img[3]" alt />
  57. </div>
  58. <div id="screan">
  59. <img :src="img[4]" alt />
  60. <!--图片展示-->
  61. <!-- <video
  62. ref="video"
  63. id="video_cam"
  64. width="178"
  65. height="142.4"
  66. class="face"
  67. autoplay
  68. v-show="isCamera"
  69. ></video>
  70. <canvas
  71. ref="canvasDOM"
  72. width="178"
  73. height="142.4"
  74. class="kuang"
  75. v-show="isCamera"
  76. ></canvas> -->
  77. <video
  78. ref="video"
  79. id="video_cam"
  80. width="118.666"
  81. height="94.933"
  82. class="face"
  83. autoplay
  84. v-show="isCamera"
  85. ></video>
  86. <canvas
  87. ref="canvasDOM"
  88. width="118.666"
  89. height="94.933"
  90. class="kuang"
  91. v-show="isCamera"
  92. ></canvas>
  93. </div>
  94. <div id="line">
  95. <img :src="img[5]" alt />
  96. </div>
  97. </div>
  98. <div class="cameraZ">
  99. <!--开启摄像头-->
  100. <div class="cameraBtn">
  101. <div class="open" @click="start()" v-if="!isZuan">
  102. <img src="../assets/img/fan/icon.png" alt />
  103. </div>
  104. <div class="close" @click="closeCamera()" v-else>
  105. <img src="../assets/img/fan/icon2.png" alt />
  106. </div>
  107. </div>
  108. <!--确认-->
  109. <div v-show="false" class="isPhoto">
  110. <!--canvas截取流-->
  111. <canvas
  112. ref="canvas"
  113. width="300"
  114. height="240"
  115. v-show="false"
  116. ></canvas>
  117. </div>
  118. </div>
  119. </div>
  120. </div>
  121. </div>
  122. </template>
  123. <style>
  124. .as {
  125. animation: myfirst 1s linear infinite;
  126. }
  127. .asn {
  128. transform: rotate(0deg);
  129. }
  130. @keyframes myfirst {
  131. 0% {
  132. transform: rotate(0deg);
  133. }
  134. 100% {
  135. transform: rotate(360deg);
  136. }
  137. }
  138. @-webkit-keyframes myfirst /* Safari and Chrome */ {
  139. 0% {
  140. transform: rotate(0deg);
  141. }
  142. 100% {
  143. transform: rotate(360deg);
  144. }
  145. }
  146. .ass {
  147. animation: myfirst 3s linear infinite;
  148. }
  149. </style>
  150. <script>
  151. import * as handPoseDetection from "@tensorflow-models/hand-pose-detection";
  152. import "@tensorflow/tfjs-backend-webgl";
  153. import * as mpHands from "@mediapipe/hands";
  154. // 引入Blockly
  155. import Blockly from "blockly";
  156. // 引入想要转换的语言,语言有php python dart lua javascript
  157. import * as JavaScript from "blockly/javascript";
  158. import * as Blocks from "blockly/blocks";
  159. // 引入语言包并使用
  160. import * as hans from "blockly/msg/zh-hans";
  161. Blockly.setLocale(hans);
  162. //引入媒体文件:我是在github上下载的blockly源码,将源码中的media文件放入我项目中的public文件夹下
  163. import $ from "jquery";
  164. //忽略被vue错认为组件的blockly中的标签,不止以下这些,请发现一个忽略一个
  165. import Vue from "vue";
  166. Vue.config.ignoredElements.push("xml");
  167. Vue.config.ignoredElements.push("block");
  168. Vue.config.ignoredElements.push("field");
  169. Vue.config.ignoredElements.push("category");
  170. Vue.config.ignoredElements.push("sep");
  171. Vue.config.ignoredElements.push("value");
  172. Vue.config.ignoredElements.push("statement");
  173. Vue.config.ignoredElements.push("mutation");
  174. export default {
  175. data() {
  176. return {
  177. that: this,
  178. img: [
  179. require("../assets/img/fan/fan.png"),
  180. require("../assets/img/fan/2.png"),
  181. require("../assets/img/fan/3.png"),
  182. require("../assets/img/fan/4.png"),
  183. require("../assets/img/fan/5.png"),
  184. require("../assets/img/fan/6.png"),
  185. require("../assets/img/fan/fanB.png"),
  186. ],
  187. shibieImg: require("../assets/img/face.png"),
  188. isCamera: false,
  189. isZuan: false,
  190. count: 0,
  191. change: 0,
  192. closeUpdateMessage: false,
  193. updateMessage: false,
  194. upName: "",
  195. number: 0,
  196. isdetected: "请您保持脸部在画面中央",
  197. videoEl: {},
  198. canvasEL: {},
  199. formLabelWidth: "100px",
  200. resultImg: {
  201. img: [],
  202. name: "",
  203. },
  204. // 预设样本图,支持本地,网络,beas64
  205. sampleArr: [
  206. // {
  207. // name: "编号1",
  208. // img: []
  209. // }
  210. ],
  211. // 匹配图,支持本地,网络,beas64
  212. detArr: [
  213. //"" 图片1
  214. ],
  215. numberOne: 0,
  216. // 匹配结果
  217. resultArr: [],
  218. // 人脸匹配矩阵数组对象转码结果
  219. faceMatcher: null,
  220. rotate: 0,
  221. timer: null,
  222. detector: null,
  223. hand: 0,
  224. isC: false,
  225. f: null,
  226. };
  227. },
  228. methods: {
  229. cancel() {
  230. this.updateMessage = false;
  231. this.sampleArr[this.sampleArr.length - 1].name = "编号:" + this.number;
  232. if (this.sampleArr.length > 0) {
  233. this.fnsample();
  234. }
  235. },
  236. async start() {
  237. this.isZuan = true;
  238. this.isCamera = true;
  239. // let video = this.$refs["video"];
  240. this.timer = setInterval(() => {
  241. this.handsFind();
  242. }, 5000);
  243. },
  244. zhuan() {
  245. var _fan = this.$refs.fan;
  246. _fan.className = "asn as";
  247. clearInterval(this.timer);
  248. this.timer = setInterval(function () {
  249. _fan.className = "asn";
  250. setTimeout(function () {
  251. _fan.className = "as";
  252. }, 0);
  253. }, 1000);
  254. },
  255. zhuann() {
  256. var _fan = this.$refs.fan;
  257. this.$refs.fan.className = "asn ass";
  258. clearInterval(this.timer);
  259. this.timer = setInterval(function () {
  260. _fan.className = "asn";
  261. setTimeout(function () {
  262. _fan.className = "ass";
  263. }, 0);
  264. }, 3000);
  265. },
  266. update() {
  267. this.change = 1;
  268. this.number = this.number + 1;
  269. if (this.change == 1) {
  270. if (this.sampleArr.length > 0) {
  271. this.sampleArr[this.sampleArr.length - 1].name = this.upName;
  272. this.isdetected = "已识别到" + this.resultImg.name + "的图片";
  273. }
  274. }
  275. if (this.sampleArr.length > 0) {
  276. // var a = document.getElementsByClassName("spot");
  277. // a[0].style.display = "block";
  278. this.fnsample();
  279. }
  280. this.updateMessage = false;
  281. },
  282. // image conversion
  283. b64toBlob(b64Data, contentType, sliceSize) {
  284. contentType = contentType || "";
  285. sliceSize = sliceSize || 512;
  286. var byteCharacters = atob(b64Data);
  287. var byteArrays = [];
  288. for (
  289. var offset = 0;
  290. offset < byteCharacters.length;
  291. offset += sliceSize
  292. ) {
  293. var slice = byteCharacters.slice(offset, offset + sliceSize);
  294. var byteNumbers = new Array(slice.length);
  295. for (var i = 0; i < slice.length; i++) {
  296. byteNumbers[i] = slice.charCodeAt(i);
  297. }
  298. var byteArray = new Uint8Array(byteNumbers);
  299. byteArrays.push(byteArray);
  300. }
  301. var blob = new Blob(byteArrays, { type: contentType });
  302. return blob;
  303. },
  304. async handsFind() {
  305. var gesture_imageURLbase64 = this.photograph2();
  306. var gesture_ImageURL = gesture_imageURLbase64;
  307. var gesture_block = gesture_ImageURL.split(";");
  308. var gesture_contentType = gesture_block[0].split(":")[1];
  309. var gesture_realData = gesture_block[1].split(",")[1];
  310. var gesture_blob = this.b64toBlob(gesture_realData, gesture_contentType);
  311. let str = new File([gesture_blob], "filename.png", { type: "image/png" });
  312. var gesture_formData = new FormData();
  313. gesture_formData.append("image", str);
  314. let params = [
  315. {
  316. gesture_formData,
  317. },
  318. ];
  319. let _this = this
  320. $.ajax({
  321. url: `//ai-api.cocorobo.cn/gesture`,
  322. data: gesture_formData,
  323. type: "POST",
  324. contentType: false, // NEEDED, DON'T OMIT THIS (requires jQuery 1.6+)
  325. processData: false, // NEEDED, DON'T OMIT THIS
  326. timeout: 10000,
  327. })
  328. .done(function (res, data) {
  329. // console.log(res.data.result[0].classname);
  330. let hand = res.data.result;
  331. console.log(hand);
  332. console.log(hand.length);
  333. console.log(hand.length > 0 && _this.isCamera);
  334. if (hand.length > 0 && _this.isCamera) {
  335. let hands = res.data.result[0]
  336. console.log(hands)
  337. console.log(hands.classname)
  338. /*石头剪刀布的转速 */
  339. let buNum = 100;
  340. let sNum = 0;
  341. let jNum = 50;
  342. /**1布2石头3剪刀 */
  343. if (hands.classname == "Five") {
  344. console.log("布");
  345. if (_this.hand == 1) {
  346. return;
  347. }
  348. _this.hand = 1;
  349. // this.zhuan();
  350. _this.$refs.fan.className = "as";
  351. } else if (hands.classname == "Fist") {
  352. console.log("石头");
  353. if (_this.hand == 2) {
  354. return;
  355. }
  356. _this.hand = 2;
  357. //clearInterval(this.timer);
  358. _this.$refs.fan.className = "asn";
  359. } else if (hands.classname == "Two") {
  360. console.log("剪刀");
  361. if (_this.hand == 3) {
  362. return;
  363. }
  364. _this.hand = 3;
  365. _this.$refs.fan.className = "ass";
  366. // this.zhuann();
  367. }
  368. }
  369. })
  370. .catch((err) => {
  371. console.log(err);
  372. });
  373. },
  374. // 调用摄像头
  375. callCamera() {
  376. const loading = this.$loading.service({
  377. background: "rgba(255, 255, 255, 0.7)",
  378. target: document.body,
  379. });
  380. let _this = this;
  381. // H5调用电脑摄像头API
  382. window.navigator.mediaDevices
  383. .getUserMedia({
  384. video: true,
  385. })
  386. .then((success) => {
  387. // 摄像头开启成功
  388. _this.$refs["video"].srcObject = success;
  389. // 实时拍照效果
  390. _this.$refs["video"].play();
  391. loading.close();
  392. })
  393. .catch((error) => {
  394. // console.error("摄像头开启失败,请检查摄像头是否可用!");
  395. _this.isC = false;
  396. _this.$message.error("摄像头开启失败,请检查摄像头是否可用!");
  397. loading.close();
  398. });
  399. },
  400. // 拍照
  401. photograph2() {
  402. let ctx = this.$refs["canvas"].getContext("2d");
  403. // 把当前视频帧内容渲染到canvas上
  404. ctx.drawImage(this.$refs["video"], 0, 0, 300, 240);
  405. // 转base64格式、图片格式转换、图片质量压缩
  406. let imgBase64 = this.$refs["canvas"].toDataURL("image/jpeg", 0.7); // 由字节转换为KB 判断大小
  407. return imgBase64;
  408. },
  409. // 拍照
  410. photograph() {
  411. let ctx = this.$refs["canvas"].getContext("2d");
  412. // 把当前视频帧内容渲染到canvas上
  413. ctx.drawImage(this.$refs["video"], 0, 0, 300, 240);
  414. // 转base64格式、图片格式转换、图片质量压缩
  415. let imgBase64 = this.$refs["canvas"].toDataURL("image/jpeg", 0.7); // 由字节转换为KB 判断大小
  416. let str = imgBase64.replace("data:image/jpeg;base64,", "");
  417. let strLength = str.length;
  418. let fileLength = parseInt(strLength - (strLength / 8) * 2); // 图片尺寸 用于判断
  419. let size = (fileLength / 1024).toFixed(2);
  420. console.log(size); // 上传拍照信息 调用接口上传图片 .........
  421. // this.detArr.push(imgBase64);
  422. var json = { name: "", img: [] };
  423. this.number = this.number + 1;
  424. this.upName = "";
  425. json.img.push(imgBase64);
  426. this.sampleArr.push(json);
  427. this.updateMessage = true;
  428. },
  429. // 关闭摄像头
  430. closeCamera() {
  431. this.isCamera = false;
  432. this.isZuan = false;
  433. clearInterval(this.timer);
  434. this.$refs.fan.className = "asn";
  435. this.timer = null;
  436. this.hand = 0;
  437. },
  438. async fnInit() {
  439. const model = handPoseDetection.SupportedModels.MediaPipeHands;
  440. const detectorConfig = {
  441. runtime: "mediapipe", // or 'tfjs'
  442. modelType: "full",
  443. solutionPath: `/static/hands`,
  444. };
  445. this.detector = await handPoseDetection.createDetector(
  446. model,
  447. detectorConfig
  448. );
  449. },
  450. async fnsample() {
  451. const labeledFaceDescriptors = await Promise.all(
  452. this.sampleArr.map(async (item) => {
  453. // 临时图片转码数据,将图片对象转数据矩阵对象
  454. let descriptors = [];
  455. for (let image of item.img) {
  456. const imageEl = await faceapi.fetchImage(image);
  457. descriptors.push(await faceapi.computeFaceDescriptor(imageEl));
  458. }
  459. // 返回图片用户和图片转码数组
  460. return new faceapi.LabeledFaceDescriptors(item.name, descriptors);
  461. })
  462. );
  463. // 人脸匹配矩阵数组对象转码结果
  464. this.faceMatcher = new faceapi.FaceMatcher(labeledFaceDescriptors);
  465. },
  466. // 执行遍历识别匹配图片,数值误差越小越精确
  467. fnRun() {
  468. let ctx = this.$refs["canvas"].getContext("2d");
  469. // 把当前视频帧内容渲染到canvas上
  470. ctx.drawImage(this.$refs["video"], 0, 0, 300, 240);
  471. // 转base64格式、图片格式转换、图片质量压缩
  472. let imgBase64 = this.$refs["canvas"].toDataURL("image/jpeg", 0.7); // 由字节转换为KB 判断大小
  473. this.detArr = [];
  474. this.detArr.push(imgBase64);
  475. this.detArr.forEach(async (img) => {
  476. let ts = Date.now();
  477. // 将图片对象转数据矩阵对象,进行匹配
  478. const inputEl = await faceapi.fetchImage(img);
  479. const inputDescriptor = await faceapi.computeFaceDescriptor(inputEl);
  480. const bestMatch = await this.faceMatcher.findBestMatch(inputDescriptor);
  481. // 结果
  482. this.resultArr = [];
  483. this.resultArr.push({
  484. target: img,
  485. result: bestMatch.toString(),
  486. time: Date.now() - ts + "ms",
  487. fps: Math.round(1000 / (Date.now() - ts)),
  488. });
  489. console.log(this.resultArr);
  490. var a = document.getElementsByClassName("pFace");
  491. for (var i = 0; i < this.sampleArr.length; i++) {
  492. if (this.sampleArr[i].name == bestMatch.label) {
  493. // this.closeUpdateMessage = true;
  494. // if (this.change == 1) {
  495. // this.resultImg.name = this.upName;
  496. // } else {
  497. // this.resultImg.name = this.sampleArr[i].name;
  498. // }
  499. this.isdetected = "已识别到" + this.sampleArr[i].name + "的图片";
  500. this.shibieImg = this.sampleArr[i].img[0];
  501. if (this.shibieImg.length > 0) {
  502. a[0].style.width = "300px";
  503. }
  504. this.resultImg.img[0] = this.sampleArr[i].img[0];
  505. }
  506. }
  507. });
  508. },
  509. handleClose(done) {
  510. done();
  511. },
  512. // 更换匹配图
  513. async fnChange(e) {
  514. if (!e.target.files.length) return;
  515. this.detArr = [];
  516. this.resultArr = [];
  517. // 将文件显示为图像并识别
  518. e.target.files.forEach(async (file) => {
  519. let ts = Date.now();
  520. let img = await faceapi.bufferToImage(file);
  521. const inputDescriptor = await faceapi.computeFaceDescriptor(img);
  522. const bestMatch = await this.faceMatcher.findBestMatch(inputDescriptor);
  523. // 结果
  524. this.detArr.push(img.src);
  525. this.resultArr.push({
  526. target: file.name,
  527. result: bestMatch.toString(),
  528. time: Date.now() - ts + "ms",
  529. fps: Math.round(1000 / (Date.now() - ts)),
  530. });
  531. });
  532. },
  533. blocklyInit() {
  534. this.workspace = Blockly.inject("blocklyDiv", {
  535. //工具栏
  536. toolbox: document.getElementById("toolbox"),
  537. //网格效果
  538. grid: { spacing: 20, length: 3, colour: "#ccc", snap: true },
  539. //媒体资源
  540. media: "../assets/img/",
  541. //垃圾桶
  542. trashcan: false,
  543. });
  544. //工作区监听代码生成器
  545. this.workspace.addChangeListener(this.myUpdateFunction);
  546. Blockly.Blocks["iot_lcd_screeninit"] = {
  547. init: function () {
  548. this.appendDummyInput().appendField(
  549. new Blockly.FieldImage(
  550. require("../assets/img/screen_init_header.png"),
  551. 45,
  552. 45
  553. )
  554. );
  555. this.appendDummyInput().appendField("LCD屏幕打开");
  556. this.setInputsInline(false);
  557. this.setPreviousStatement(true);
  558. this.setNextStatement(true);
  559. this.setColour("#5cb2d6");
  560. this.setTooltip("");
  561. this.setHelpUrl("");
  562. },
  563. };
  564. Blockly.JavaScript.iot_lcd_screeninit = function (block) {
  565. var _code = "screen=1;";
  566. return _code;
  567. };
  568. Blockly.Blocks["iot_lcd_faceinit"] = {
  569. init: function () {
  570. this.appendDummyInput().appendField(
  571. new Blockly.FieldImage(
  572. require("../assets/img/face_recognition_header.png"),
  573. 45,
  574. 45
  575. )
  576. );
  577. this.appendDummyInput().appendField("人脸辨识");
  578. this.setInputsInline(false);
  579. this.setPreviousStatement(true);
  580. this.setNextStatement(true);
  581. this.setColour("#ee783a");
  582. this.setTooltip("");
  583. this.setHelpUrl("");
  584. },
  585. };
  586. Blockly.JavaScript.iot_lcd_faceinit = function (block) {
  587. var _code = "face=1;";
  588. return _code;
  589. };
  590. Blockly.Blocks["iot_lcd_policeinit"] = {
  591. init: function () {
  592. this.appendDummyInput().appendField(
  593. new Blockly.FieldImage(
  594. require("../assets/img/screen_init_header.png"),
  595. 45,
  596. 45
  597. )
  598. );
  599. this.appendDummyInput().appendField("电子警察组件");
  600. this.setInputsInline(false);
  601. this.setPreviousStatement(true);
  602. this.setNextStatement(true);
  603. this.setColour("#1b5873");
  604. this.setTooltip("");
  605. this.setHelpUrl("");
  606. },
  607. };
  608. Blockly.JavaScript.iot_lcd_policeinit = function (block) {
  609. var _code = "police=1;";
  610. return _code;
  611. };
  612. Blockly.Blocks["logic_loop"] = {
  613. init: function () {
  614. this.appendStatementInput("NAME")
  615. .setCheck(null)
  616. .appendField("重复执行");
  617. this.setPreviousStatement(true, null);
  618. this.setNextStatement(true, null);
  619. this.setColour("#5b80a5");
  620. this.setTooltip("");
  621. this.setHelpUrl("");
  622. },
  623. };
  624. Blockly.JavaScript["logic_loop"] = function (block) {
  625. var statements_name = Blockly.JavaScript.statementToCode(block, "NAME");
  626. // TODO: Assemble JavaScript into code variable.
  627. var code = "for;\n";
  628. return code;
  629. };
  630. Blockly.Blocks.controls_repeat_forever = {
  631. init: function () {
  632. this.jsonInit({
  633. message0: Blockly.Msg.CONTROLS_REPEAT_FOREVER,
  634. previousStatement: null,
  635. nextStatement: null,
  636. colour: "#5ba55b",
  637. tooltip: Blockly.Msg.CONTROLS_REPEAT_FOREVER_TOOLTIP,
  638. helpUrl: Blockly.Msg.CONTROLS_REPEAT_HELPURL,
  639. });
  640. this.appendStatementInput("DO").appendField(
  641. Blockly.Msg.CONTROLS_REPEAT_INPUT_DO
  642. );
  643. },
  644. };
  645. Blockly.JavaScript.controls_repeat_forever = function (a) {
  646. var d = Blockly.JavaScript.statementToCode(a, "DO");
  647. d = Blockly.JavaScript.addLoopTrap(d, a);
  648. return "while (true) {\n" + d + "}\n";
  649. };
  650. Blockly.Blocks["logic_number"] = {
  651. init: function () {
  652. this.appendDummyInput().appendField(
  653. new Blockly.FieldTextInput("0"),
  654. "number"
  655. );
  656. this.setInputsInline(true);
  657. this.setOutput(true, "Number");
  658. this.setColour("#5b80a5");
  659. this.setTooltip("");
  660. this.setHelpUrl("");
  661. },
  662. };
  663. Blockly.JavaScript["logic_number"] = function (block) {
  664. var text_number = block.getFieldValue("number");
  665. // TODO: Assemble JavaScript into code variable.
  666. var code = text_number;
  667. // TODO: Change ORDER_NONE to the correct strength.
  668. return [code, Blockly.JavaScript.ORDER_NONE];
  669. };
  670. Blockly.Blocks["ai_gesture"] = {
  671. init: function () {
  672. this.appendDummyInput()
  673. .appendField("AI手势识别")
  674. .appendField(new Blockly.FieldDropdown([["ID", "ID"]]), "ID");
  675. this.setInputsInline(true);
  676. this.setOutput(true, null);
  677. this.setColour(285);
  678. this.setTooltip("");
  679. this.setHelpUrl("");
  680. },
  681. };
  682. Blockly.JavaScript["ai_gesture"] = function (block) {
  683. var dropdown_id = block.getFieldValue("ID");
  684. // TODO: Assemble JavaScript into code variable.
  685. var code = "hands";
  686. // TODO: Change ORDER_NONE to the correct strength.
  687. return [code, Blockly.JavaScript.ORDER_NONE];
  688. };
  689. Blockly.Blocks["ai_motor"] = {
  690. init: function () {
  691. this.appendDummyInput()
  692. .appendField("马达")
  693. .appendField(new Blockly.FieldDropdown([["M1", "M1"]]), "motor")
  694. .appendField("以速度")
  695. .appendField(new Blockly.FieldTextInput("0"), "speed")
  696. .appendField("转动");
  697. this.setPreviousStatement(true, null);
  698. this.setNextStatement(true, null);
  699. this.setColour(285);
  700. this.setTooltip("");
  701. this.setHelpUrl("");
  702. },
  703. };
  704. Blockly.JavaScript["ai_motor"] = function (block) {
  705. var dropdown_motor = block.getFieldValue("motor");
  706. var text_speed = block.getFieldValue("speed");
  707. // TODO: Assemble JavaScript into code variable.
  708. var code = "motor=" + text_speed;
  709. // TODO: Change ORDER_NONE to the correct strength.
  710. return code;
  711. };
  712. },
  713. // 代码生成器
  714. myUpdateFunction(event) {
  715. var code = Blockly.JavaScript.workspaceToCode(this.workspace);
  716. // debugger;
  717. return code;
  718. },
  719. // 清空工作区
  720. clearBlockData() {
  721. this.workspace.clear();
  722. },
  723. // 回显工作区中的xml结构
  724. setBlockData(xmlText) {
  725. this.clearBlockData();
  726. const xml = Blockly.Xml.textToDom(xmlText);
  727. Blockly.Xml.domToWorkspace(xml, this.workspace);
  728. },
  729. },
  730. mounted() {
  731. this.blocklyInit();
  732. // this.fnInit();
  733. this.callCamera();
  734. this.videoEl = this.$refs.video;
  735. this.canvasEL = this.$refs.canvasDOM;
  736. var xmlText =
  737. '<xml xmlns="https://developers.google.com/blockly/xml"><block type="iot_lcd_screeninit" id="{3nwI]%M1OB@v~%c^GJ*" x="270" y="150"><next><block type="controls_repeat_forever" id="%RwQN-vn~S,Qz:U%Dp2C"><statement name="DO"><block type="controls_if" id="tTNBMMPITBf)yE@hA}Lt"><value name="IF0"><block type="logic_compare" id="kW(af5I*_dMR|37aEHA8"><field name="OP">EQ</field><value name="A"><block type="ai_gesture" id="Msy)DT1[/[pA7vU$u2BD"><field name="ID">ID</field></block></value><value name="B"><block type="logic_number" id="F7nQ+Rn{h=Z-:`nxfOV{"><field name="number">1</field></block></value></block></value><statement name="DO0"><block type="ai_motor" id="9=+m`N)^mOs;,8?7ZZ:K"><field name="motor">M1</field><field name="speed">100</field></block></statement><next><block type="controls_if" id="~ykQvxBR]wnz6FHIGc^s"><value name="IF0"><block type="logic_compare" id="+v0*1:oG$.+wMFe_g_F@"><field name="OP">EQ</field><value name="A"><block type="ai_gesture" id=",|{9@1In%8:74vXPPn{O"><field name="ID">ID</field></block></value><value name="B"><block type="logic_number" id="[J4:1z-D*iz3){K$v[gM"><field name="number">2</field></block></value></block></value><statement name="DO0"><block type="ai_motor" id="XIVuWHcKb[O5|0*HC_Em"><field name="motor">M1</field><field name="speed">0</field></block></statement><next><block type="controls_if" id="bNZCd.Zj2arimcA^dZvc"><value name="IF0"><block type="logic_compare" id="ul/^s*@P{HkWe6(^9fgn"><field name="OP">EQ</field><value name="A"><block type="ai_gesture" id="Wd)15h0yyFb`)Sy:H}0w"><field name="ID">ID</field></block></value><value name="B"><block type="logic_number" id="1f0Wep9dlC0i-})rTiqN"><field name="number">3</field></block></value></block></value><statement name="DO0"><block type="ai_motor" id="bY;.J)_PvmP5TAD/KDs,"><field name="motor">M1</field><field name="speed">50</field></block></statement></block></next></block></next></block></statement></block></next></block></xml>';
  738. this.setBlockData(xmlText);
  739. },
  740. };
  741. </script>
  742. <style scoped>
  743. html,
  744. body {
  745. margin: 0;
  746. padding: 0;
  747. width: 100%;
  748. }
  749. .dialog_diy >>> .el-form-item__label {
  750. width: 50px !important;
  751. margin-left: 35px !important;
  752. }
  753. .dialog_diy >>> .el-form-item__content {
  754. margin-left: 0 !important;
  755. }
  756. .update {
  757. margin-left: 20%;
  758. font-size: 16px !important;
  759. }
  760. .tip {
  761. margin: 25px 0 30px 20px;
  762. }
  763. #fan > img,
  764. #fanB > img,
  765. #motor > img,
  766. #base > img,
  767. #line > img,
  768. .right > img,
  769. #a4 > img,
  770. #screan > img {
  771. width: 100%;
  772. height: 100%;
  773. user-select: none;
  774. }
  775. .img {
  776. display: flex;
  777. flex-direction: row;
  778. justify-content: flex-start;
  779. justify-content: center;
  780. width: 100%;
  781. height: 500px;
  782. position: relative;
  783. }
  784. #fan {
  785. /* width: 425px; */
  786. width: 283.33px;
  787. position: absolute;
  788. z-index: 5;
  789. /* left: 150px; */
  790. left: 100px;
  791. top: 0;
  792. transition: all 1s;
  793. transform: rotate(0deg);
  794. }
  795. #fanB {
  796. /* width: 116.6px; */
  797. width: 77.733px;
  798. position: absolute;
  799. z-index: 4;
  800. /* left: 300px;
  801. top: 155px; */
  802. left: 200px;
  803. top: 103.333px;
  804. }
  805. #base {
  806. /* width: 423.33px; */
  807. width: 282.21px;
  808. position: absolute;
  809. z-index: 4;
  810. /* top: 295px;
  811. left: 0; */
  812. top: 196.666px;
  813. left: 0;
  814. }
  815. #motor {
  816. /* width: 134.16px; */
  817. width: 89.44px;
  818. position: absolute;
  819. z-index: 3;
  820. /* left: 292px;
  821. top: 175px; */
  822. left: 194.666px;
  823. top: 116.666px;
  824. }
  825. #a4 {
  826. /* width: 210px; */
  827. width: 140px;
  828. position: absolute;
  829. z-index: 5;
  830. /* top: 517px;
  831. left: 111px; */
  832. top: 344.666px;
  833. left: 74px;
  834. }
  835. #screan {
  836. /* width: 178.33px; */
  837. width: 118.886px;
  838. position: absolute;
  839. /* left: -19px;
  840. top: 126px; */
  841. left: -12.666px;
  842. top: 84px;
  843. }
  844. #line {
  845. /* width: 470.83px; */
  846. width: 313.886px;
  847. position: absolute;
  848. z-index: 2;
  849. /* top: 245px;
  850. left: -113px; */
  851. top: 163.333px;
  852. left: -75.333px;
  853. }
  854. .button {
  855. color: #fff;
  856. background: #8ca1de;
  857. width: 550px;
  858. height: 55px;
  859. font-size: 20px;
  860. text-align: center;
  861. line-height: 55px;
  862. position: absolute;
  863. bottom: 10%;
  864. left: 50%;
  865. transform: translateX(-50%);
  866. user-select: none;
  867. }
  868. .right {
  869. width: 40px;
  870. position: absolute;
  871. left: 55%;
  872. top: 70%;
  873. display: none;
  874. }
  875. .dark {
  876. background: #5b79d0;
  877. cursor: pointer;
  878. }
  879. .controlZ {
  880. width: 560px;
  881. height: 620px;
  882. /* margin-left: calc(50% - (490px / 2)); */
  883. position: relative;
  884. top: 10%;
  885. left: 5%;
  886. }
  887. .cameraZ {
  888. display: flex;
  889. height: 340px;
  890. flex-direction: column;
  891. flex-wrap: nowrap;
  892. width: 300px;
  893. }
  894. .cameraBtn {
  895. display: flex;
  896. flex-direction: column;
  897. align-items: center;
  898. }
  899. .cameraBtn button {
  900. margin: 0 0 10px 0;
  901. }
  902. .face {
  903. position: absolute;
  904. z-index: 9999;
  905. padding: 5px 0px;
  906. left: 0;
  907. top: 37px;
  908. }
  909. .kuang {
  910. position: absolute;
  911. z-index: 10000;
  912. padding: 26.5px 0;
  913. left: 0;
  914. top: 37px;
  915. }
  916. .pFace {
  917. /* width: 300px; */
  918. /* height: 240px; */
  919. width: 150px;
  920. margin: 0 auto;
  921. margin-top: 220px;
  922. }
  923. .close > img,
  924. .save > img,
  925. .pFace > img,
  926. .open > img,
  927. .spotPhoto > img {
  928. width: 100%;
  929. height: 100%;
  930. cursor: pointer;
  931. }
  932. .cameraBtn {
  933. margin-top: 80px;
  934. }
  935. .close {
  936. margin-bottom: 25px;
  937. }
  938. .isPhoto {
  939. height: 410px;
  940. padding: 80px 0 0 0;
  941. box-sizing: border-box;
  942. background: #fff;
  943. }
  944. .isPhoto > span {
  945. font-size: 25px;
  946. color: #ccc;
  947. margin-left: 10px;
  948. }
  949. .nav {
  950. text-align: center;
  951. font-size: 32px;
  952. color: #ccc;
  953. }
  954. .spot {
  955. background: #64ff64;
  956. color: #fff;
  957. width: 140px;
  958. height: 40px;
  959. text-align: center;
  960. line-height: 40px;
  961. border-radius: 20px;
  962. margin-top: 25px;
  963. cursor: pointer;
  964. display: none;
  965. }
  966. .spotNumber {
  967. text-align: center;
  968. margin: 0 auto;
  969. font-size: 20px;
  970. color: #8c8c8c;
  971. }
  972. .spotPhoto {
  973. width: 300px;
  974. height: 245px;
  975. }
  976. .spotPhoto {
  977. margin-top: 20px;
  978. font-size: 20px;
  979. }
  980. .gdt {
  981. display: flex;
  982. flex-direction: column;
  983. }
  984. .ablockly,
  985. #blocklyDiv {
  986. height: 100%;
  987. width: 100%;
  988. }
  989. .blocklySvg {
  990. height: 905px !important;
  991. }
  992. .ablockly {
  993. position: relative;
  994. width: 50%;
  995. }
  996. .container {
  997. width: 50%;
  998. height: 100%;
  999. min-width: 700px;
  1000. }
  1001. </style>