程序猿的世界 http://dengtongyu.com 程序猿的那些事儿 Fri, 13 Nov 2020 06:26:06 +0000 zh-CN 1.2 http://dengtongyu.com http://dengtongyu.com 1 1 2 4nav_menu https://wordpress.org/?v=4.5.23 无脸男 http://dengtongyu.com/archives/4.html/015986554b84ec000001bf7267e627 Tue, 24 May 2016 10:28:55 +0000 https://image.dengtongyu.com/blog/2016/05/015986554b84ec000001bf7267e627.jpg 5 4 0 0 奇妙能力歌 http://dengtongyu.com/archives/8.html/%e5%a5%87%e5%a6%99%e8%83%bd%e5%8a%9b%e6%ad%8c-2 Wed, 25 May 2016 14:55:15 +0000 https://image.dengtongyu.com/blog/2016/05/奇妙能力歌.mp3 12 8 0 0 小新 http://dengtongyu.com/archives/24.html/u23298692062573679482fm21gp0 Tue, 31 May 2016 13:01:41 +0000 https://image.dengtongyu.com/blog/2016/05/u23298692062573679482fm21gp0.jpg 25 24 0 0 无脸男 http://dengtongyu.com/archives/34.html/20150121124317_k2jgj Sun, 12 Jun 2016 13:52:26 +0000 https://image.dengtongyu.com/blog/2016/06/20150121124317_k2JGJ.jpg 35 34 0 0 20170901165944 http://dengtongyu.com/archives/115.html/attachment/20170901165944 Fri, 01 Sep 2017 09:00:55 +0000 https://image.dengtongyu.com/blog/2017/09/20170901165944.png 122 115 0 0 20170901171508 http://dengtongyu.com/archives/115.html/attachment/20170901171508 Fri, 01 Sep 2017 09:16:42 +0000 https://image.dengtongyu.com/blog/2017/09/20170901171508.png 124 115 0 0 20170901171729 http://dengtongyu.com/archives/115.html/attachment/20170901171729 Fri, 01 Sep 2017 09:18:44 +0000 https://image.dengtongyu.com/blog/2017/09/20170901171729.png 125 115 0 0 app-works http://dengtongyu.com/archives/143.html/app-works Wed, 20 Sep 2017 07:49:16 +0000 https://image.dengtongyu.com/blog/2017/09/app-works.png 163 143 0 0 angular-logo http://dengtongyu.com/archives/143.html/angular-logo Tue, 17 Oct 2017 07:36:46 +0000 https://image.dengtongyu.com/blog/2017/09/angular-logo.png 178 143 0 0 egret-cat http://dengtongyu.com/archives/115.html/egret-cat Tue, 17 Oct 2017 07:44:11 +0000 https://image.dengtongyu.com/blog/2017/09/egret-cat.png 179 115 0 0 media-banner http://dengtongyu.com/archives/94.html/media-banner Tue, 17 Oct 2017 07:49:16 +0000 https://image.dengtongyu.com/blog/2017/04/media-banner.jpg 180 94 0 0 vue-logo http://dengtongyu.com/archives/173.html/vue-logo-2 Tue, 17 Oct 2017 10:04:40 +0000 https://image.dengtongyu.com/blog/2017/10/vue-logo-1.png 181 173 0 0 vue-resource http://dengtongyu.com/archives/69.html/vue-resource Tue, 17 Oct 2017 10:08:30 +0000 https://image.dengtongyu.com/blog/2016/07/vue-resource.png 182 69 0 0 vode-express http://dengtongyu.com/archives/90.html/vode-express Tue, 17 Oct 2017 10:14:40 +0000 https://image.dengtongyu.com/blog/2017/01/vode-express.png 183 90 0 0 react-native http://dengtongyu.com/archives/84.html/react-native Tue, 17 Oct 2017 10:17:59 +0000 https://image.dengtongyu.com/blog/2016/12/react-native.png 184 84 0 0 html-dom http://dengtongyu.com/archives/76.html/html-dom Tue, 17 Oct 2017 10:24:11 +0000 https://image.dengtongyu.com/blog/2016/08/html-dom.png 185 76 0 0 browser-sync http://dengtongyu.com/archives/64.html/browser-sync Tue, 17 Oct 2017 10:34:01 +0000 https://image.dengtongyu.com/blog/2016/06/browser-sync.png 188 64 0 0 let http://dengtongyu.com/archives/52.html/let Tue, 17 Oct 2017 10:43:35 +0000 https://image.dengtongyu.com/blog/2016/06/let.png 189 52 0 0 if-oe http://dengtongyu.com/archives/38.html/if-oe Wed, 18 Oct 2017 02:31:27 +0000 https://image.dengtongyu.com/blog/2016/06/if-oe.png 190 38 0 0 egret粒子系统创建示例 http://dengtongyu.com/archives/200.html/qq%e6%88%aa%e5%9b%be20171020160019 Fri, 20 Oct 2017 07:59:51 +0000 https://image.dengtongyu.com/blog/2017/10/QQ截图20171020160019.png 206 200 0 0 egret-feather http://dengtongyu.com/archives/200.html/egret-feather Fri, 20 Oct 2017 08:42:49 +0000 https://image.dengtongyu.com/blog/2017/10/egret-feather.png 214 200 0 0 egret陀螺仪 http://dengtongyu.com/archives/217.html/attachment/20171122 Wed, 22 Nov 2017 07:55:30 +0000 https://image.dengtongyu.com/blog/2017/11/20171122.png 234 217 0 0 egret陀螺仪demo http://dengtongyu.com/archives/217.html/%e4%b8%8b%e8%bd%bd-1 Wed, 22 Nov 2017 09:25:06 +0000 https://image.dengtongyu.com/blog/2017/11/下载-1.png 235 217 0 0 egret天空盒子demo http://dengtongyu.com/archives/238.html/%e4%b8%8b%e8%bd%bd-2 Wed, 22 Nov 2017 10:17:35 +0000 https://image.dengtongyu.com/blog/2017/11/下载-2.png 246 238 0 0 天空盒子 http://dengtongyu.com/archives/238.html/images Wed, 22 Nov 2017 10:29:04 +0000 https://image.dengtongyu.com/blog/2017/11/images.jpeg 248 238 0 0 egret天空盒子 http://dengtongyu.com/archives/238.html/egret%e5%a4%a9%e7%a9%ba%e7%9b%92%e5%ad%90 Wed, 22 Nov 2017 10:35:20 +0000 https://image.dengtongyu.com/blog/2017/11/egret天空盒子.png 250 238 0 0 egret引用HTML5 Canvas http://dengtongyu.com/archives/252.html/attachment/20171215173527 Fri, 15 Dec 2017 09:36:38 +0000 https://image.dengtongyu.com/blog/2017/12/20171215173527.png 255 252 0 0 egret引用HTML5 Canvas http://dengtongyu.com/archives/252.html/egret-animation Fri, 15 Dec 2017 10:04:23 +0000 https://image.dengtongyu.com/blog/2017/12/egret-animation.png 259 252 0 0 视频贴图 http://dengtongyu.com/archives/267.html/%e4%b8%8b%e8%bd%bd Mon, 29 Jan 2018 09:48:33 +0000 https://image.dengtongyu.com/blog/2018/01/下载.png 273 267 0 0 视频贴图 http://dengtongyu.com/archives/267.html/banner Mon, 29 Jan 2018 09:54:57 +0000 https://image.dengtongyu.com/blog/2018/01/banner.jpg 275 267 0 0 input新特性 http://dengtongyu.com/archives/276.html/%e6%9c%aa%e6%a0%87%e9%a2%98-1 Wed, 07 Feb 2018 10:25:21 +0000 https://image.dengtongyu.com/blog/2018/02/未标题-1.png 289 276 0 0 egret粒子系统demo http://dengtongyu.com/archives/200.html/%e4%b8%8b%e8%bd%bd-3 Thu, 08 Feb 2018 08:54:25 +0000 https://image.dengtongyu.com/blog/2017/10/下载.png 299 200 0 0 通配符证书 http://dengtongyu.com/archives/304.html/qq20180711-1815032x Wed, 11 Jul 2018 10:15:42 +0000 https://image.dengtongyu.com/blog/2018/07/QQ20180711-181503@2x.png 316 304 0 0 let's-encrypt http://dengtongyu.com/archives/304.html/lets-encrypt Thu, 12 Jul 2018 03:36:35 +0000 https://image.dengtongyu.com/blog/2018/07/lets-encrypt.png 328 304 0 0 使用acme.sh 申请 Let's Encrypt 泛域名SSL证书 http://dengtongyu.com/archives/333.html/tdcdjdcxsov Mon, 23 Jul 2018 09:53:57 +0000 https://image.dengtongyu.com/blog/2018/07/tdcdjdcxsov.png 339 333 0 0 acme.sh http://dengtongyu.com/archives/333.html/acme-sh Mon, 23 Jul 2018 10:25:37 +0000 https://image.dengtongyu.com/blog/2018/07/acme.sh_.png 343 333 0 0 情景图 http://dengtongyu.com/archives/346.html/%e6%83%85%e6%99%af%e5%9b%be Sun, 16 Dec 2018 05:06:23 +0000 https://image.dengtongyu.com/blog/2018/12/情景图.jpg 347 346 0 0 QQ截图20200620114436 http://dengtongyu.com/archives/361.html/qq%e6%88%aa%e5%9b%be20200620114436 Sat, 20 Jun 2020 03:45:02 +0000 https://image.dengtongyu.com/blog/2020/06/QQ截图20200620114436.png 370 361 0 0 微信图片_20200620120800 http://dengtongyu.com/archives/361.html/%e5%be%ae%e4%bf%a1%e5%9b%be%e7%89%87_20200620120800 Sat, 20 Jun 2020 04:08:12 +0000 https://image.dengtongyu.com/blog/2020/06/微信图片_20200620120800.png 376 361 0 0 微信图片_20200620120806 http://dengtongyu.com/archives/361.html/%e5%be%ae%e4%bf%a1%e5%9b%be%e7%89%87_20200620120806 Sat, 20 Jun 2020 04:08:16 +0000 https://image.dengtongyu.com/blog/2020/06/微信图片_20200620120806.png 377 361 0 0 第一条写些什么呢? http://dengtongyu.com/archives/4.html Tue, 24 May 2016 10:30:10 +0000 http://dengtongyu.com/?p=4 以后的生活会更精彩吧···嗯嗯···]]> 4 0 0 0 奇妙能力歌 http://dengtongyu.com/archives/8.html Tue, 24 May 2016 14:59:20 +0000 http://dengtongyu.com/?p=8 8 0 0 0 忙碌的工作日,潮流的朋友圈 http://dengtongyu.com/archives/14.html Wed, 25 May 2016 15:17:50 +0000 http://dengtongyu.com/?p=14 14 0 0 0 http://dengtongyu.com/archives/16.html Thu, 26 May 2016 08:54:35 +0000 http://dengtongyu.com/?p=16 16 0 2 0 http://dengtongyu.com/archives/17.html Thu, 26 May 2016 08:54:35 +0000 http://dengtongyu.com/?p=17 17 0 3 0 首页 http://dengtongyu.com/archives/18.html Thu, 26 May 2016 08:57:35 +0000 http://dengtongyu.com/?p=18 18 0 1 0 人应该要学会生活 http://dengtongyu.com/archives/20.html Thu, 26 May 2016 15:27:30 +0000 http://dengtongyu.com/?p=20 20 0 0 0 一个星期一早晨感慨 http://dengtongyu.com/archives/22.html Mon, 30 May 2016 01:59:06 +0000 http://dengtongyu.com/?p=22 22 0 0 0 如果有来生 http://dengtongyu.com/archives/24.html Wed, 01 Jun 2016 01:31:05 +0000 http://dengtongyu.com/?p=24 如果有来生,我要当条被子,不是躺在床上就是在晒太阳! ——野原新之助]]> 24 0 0 0 咸鱼需要冷藏 http://dengtongyu.com/archives/29.html Thu, 02 Jun 2016 13:22:10 +0000 http://dengtongyu.com/?p=29 29 0 0 0 我脑中的橡皮擦 http://dengtongyu.com/archives/34.html Sun, 12 Jun 2016 13:52:59 +0000 http://dengtongyu.com/?p=34 最近感觉自己容易忘记一些东西,重要的、琐碎的、又或者无关紧要的。 它犹如一块橡皮擦,偷偷的抹掉你一个字,一个词,甚至一句话,而你却浑然不觉。 待你回顾这些篇章的时候,你才发现记忆的空白。 于是你努力回想,企图找回只字片语,但看到的只是一片模糊的掠影。]]> 34 0 0 0 条件注释判断浏览器 http://dengtongyu.com/archives/38.html Tue, 14 Jun 2016 02:03:23 +0000 http://dengtongyu.com/?p=38 项目 范例 说明 ! [if !IE] The NOT operator. This is placed immediately in front of the?feature,?operator, or?subexpression?to reverse the Boolean meaning of the expression. NOT运算符。这是摆立即在前面的功能,操作员,或子表达式扭转布尔表达式的意义。 lt [if lt IE 5.5] The less-than operator. Returns true if the first argument is less than the second argument. 小于运算符。如果第一个参数小于第二个参数,则返回true。 lte [if lte IE 6] The less-than or equal operator. Returns true if the first argument is less than or equal to the second argument. 小于或等于运算。如果第一个参数是小于或等于第二个参数,则返回true。 gt [if gt IE 5] The greater-than operator. Returns true if the first argument is greater than the second argument. 大于运算符。如果第一个参数大于第二个参数,则返回true。 gte [if gte IE 7] The greater-than or equal operator. Returns true if the first argument is greater than or equal to the second argument. 大于或等于运算。如果第一个参数是大于或等于第二个参数,则返回true。 ( ) [if !(IE 7)] Subexpression operators. Used in conjunction with boolean operators to create more complex expressions. 子表达式运营商。在与布尔运算符用于创建更复杂的表达式。 & [if (gt IE 5)&(lt IE 7)] The AND operator. Returns true if all subexpressions evaluate to true AND运算符。如果所有的子表达式计算结果为true,返回true | [if (IE 6)|(IE 7)] The OR operator. Returns true if any of the subexpressions evaluates to true. OR运算符。返回true,如果子表达式计算结果为true。   举个栗子

<!-- [if IE 7]> 仅IE7可识别 <![endif]-->

<!--[if lte IE 7]> IE7以及IE7以下版本可识别 <![endif]-->

<!--[if gte IE 7]> IE7以及IE7以上版本可识别 <![endif]-->

  ]]>
38 0 0 0
ES6 下定义变量,let大法好! http://dengtongyu.com/archives/52.html Thu, 16 Jun 2016 14:37:51 +0000 http://dengtongyu.com/?p=52 var 声明的变量作用域不是块级的,会扩大变量的作用域,可能造成变量污染。 let 声明的变量作用域就更精确,离开作用域变量就销毁。 const 顾名思义就是常量了。 变量作用域更加精准 不用担心变量作用域自动提升,造成上一级或全局变量值被覆盖。 举个栗子:
let a = 1;
var b = 1;
if (true) {
  let a = 2;
  var b = 2;
}
console.log(a) // 输出 1
console.log(b) // 输出 2
变量作用域可控性更好 let 的作用域是根据代码块(enclosing block)来判定的,而 var 的作用域是根据函数块(function block)来判定的。这样的话,如果我们的变量都使用 let/const 来声明,那么以前的立即执行函数就不需要了,我们只要加一个代码块就好了。 举个栗子:
{
let a = 1;
}
console.log(a) // 输出 a is not defined
Runtime自动检查重复声明的函数并报错 在同一个作用域内不允许重复声明变量。 举个栗子:
if (true) {
  let a = 1;
  let a = 2;
}
Runtime会报错:Uncaught SyntaxError: Identifier 'a' has already been declared 有了更加清晰的作用域,我们的代码就能够更好被预测,也更好维护。 有了更容易控制的作用域可以让我们减少很多立即执行的函数。 Runtime的自动检查可以避免不必要,甚至是错误的代码声明。  ]]>
52 0 0 0 14 0 0
吾日三省吾身 http://dengtongyu.com/archives/61.html Thu, 23 Jun 2016 15:13:16 +0000 http://dengtongyu.com/?p=61 61 0 0 0 browser-sync代理接口在IE8下返回406问题 http://dengtongyu.com/archives/64.html Tue, 28 Jun 2016 02:15:34 +0000 http://dengtongyu.com/?p=64 var browserSync = require('browser-sync'); var proxyMiddleware = require('http-proxy-middleware'); var proxy_context = ['/service/web']; var proxy_option = { target: 'http://' + proxyConfig.host + ':' + proxyConfig.port, //增加一个错误处理在window 7 ie7,8 onProxyReq: function(proxyReq, req, res){ var is4dot0 = false; var acceptValue = ""; var acceptEncodeing = ""; var rawHeaders = req.rawHeaders; rawHeaders.forEach(function(value, index){ if(value === "Accept"){ acceptValue = rawHeaders[index+1]; } if(value === "Accept-Encoding"){ acceptEncodeing = rawHeaders[index+1]; } if(value.indexOf("Mozilla/4.0") === 0){ is4dot0 = true; } }); if(is4dot0){ proxyReq.setHeader("Accept", acceptValue); proxyReq.setHeader("Accept-Encoding", acceptEncodeing); } } }; var proxy = proxyMiddleware(proxy_context, proxy_option); browserSync({ host: 'local.xxx.com', port: 3000, open: 'external', browser: 'google chrome', ghostMode: false, // 每个页面的镜像独立,不相互影响 server: { baseDir: "build", middleware: [proxy] } }); ]]> 64 0 0 0 vue-resource http请求在ios浏览器下的一个小坑 http://dengtongyu.com/archives/69.html Tue, 05 Jul 2016 10:41:00 +0000 http://dengtongyu.com/?p=69 new Vue({ el: 'body', ready:function(){ this.$http.get('url',{ }).then(function(json){ console.log( typeof json.data ) //谷歌返回的是string,ios返回的是object },function(json){ }); } }); 以上代码,在谷歌返回的是string,ios浏览器返回的是object, 所以通过JSON.parse()格式化json.data的时候,在ios浏览器下就报错了 通过使用vue-resource提供的json()方法解决 具体代码如下

new Vue({
	el: 'body',
	ready:function(){
		this.$http.get('url',{

		}).then(function(json){
			console.log( typeof json.json()) 
		},function(json){
			
		});
	}
});
 ]]>
69 0 0 0
字符html创建DOM节点 http://dengtongyu.com/archives/76.html Thu, 25 Aug 2016 01:58:05 +0000 http://dengtongyu.com/?p=76 function createDom(html) { var tempDom = document.createElement('div'); tempDom.innerHTML = html; return tempDom.childNodes; }; var div = createDom('<div>新创建的div</div>')[0]; document.getElementsByTagName('body').appendChild(div); 不过值得注意的是,childNodes返回的是一个DOM节点的列表,记得处理一下]]> 76 0 0 0 2 0 0 3 0 0 4 0 0 8 0 0 20 0 0 21 0 0 24 0 0 25 0 0 react native for ios 下的一个小坑 http://dengtongyu.com/archives/84.html Fri, 09 Dec 2016 10:07:07 +0000 http://dengtongyu.com/?p=84 Error: *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'bundleURL must be non-nil when not implementing loadSourceForBridge' 谷歌百度一系列之后,仍然无法解决,然后加了react native中文的官方群提问,有人说是开启了VPN导致,然而我的Mac并没有配置VPN,一切又回到原点。 然而受到这个启发,把之前写web dom时配置的 127.0.0.1 localhost 还原。神奇的事情发生了,Xcode里的项目跑起来了!喜大普奔,然而我也没搞懂这是为什么。

#host文件一定要有这个
127.0.0.1 localhost

]]>
84 0 0 0 36 0 0
微信图片_20200620120811 http://dengtongyu.com/archives/361.html/%e5%be%ae%e4%bf%a1%e5%9b%be%e7%89%87_20200620120811 Sat, 20 Jun 2020 04:08:19 +0000 https://image.dengtongyu.com/blog/2020/06/微信图片_20200620120811.png 378 361 0 0 鉴黄师 http://dengtongyu.com/archives/361.html/u6922217982175452464fm26gp0 Sat, 20 Jun 2020 04:10:55 +0000 https://image.dengtongyu.com/blog/2020/06/u6922217982175452464fm26gp0.jpg 381 361 0 0 用Node+express搭建本地https服务 http://dengtongyu.com/archives/90.html Tue, 24 Jan 2017 07:21:05 +0000 http://dengtongyu.com/?p=90 //生成私钥key文件 openssl genrsa 1024 > /keys/private.pem //通过私钥文件生成CSR证书签名 openssl req -new -key /keys/private.pem -out /keys/csr.pem //通过私钥文件和CSR证书签名生成证书文件 openssl x509 -req -days 365 -in /keys/csr.pem -signkey /keys/private.pem -out /keys/file.crt 4.编写server文件

var app = require('express')();
var fs = require('fs');
var http = require('http');
var https = require('https');

//引入私钥、证书
var privateKey  = fs.readFileSync('./keys/private.pem', 'utf8');
var certificate = fs.readFileSync('./keys/file.crt', 'utf8');
var credentials = {key: privateKey, cert: certificate};

//创建服务,设置端口号
var httpServer = http.createServer(app);
var httpsServer = https.createServer(credentials, app);
var PORT = 18080;
var SSLPORT = 18081;

//监听端口号
httpServer.listen(PORT, function() {
    console.log('HTTP Server is running on: http://localhost:%s', PORT);
});
httpsServer.listen(SSLPORT, function() {
    console.log('HTTPS Server is running on: https://localhost:%s', SSLPORT);
});

//路由
app.get('/', function(req, res) {
    if(req.protocol === 'https') {
        res.status(200).send('这是一个经过加密的https请求!');
    }
    else {
        res.status(200).send('这是一个普通的http请求!');
    }
});


5.启动服务

node server.js

]]>
90 0 0 0
navigator.mediaDevices.getUserMedia调用本地摄像头 http://dengtongyu.com/archives/94.html Fri, 28 Apr 2017 07:20:27 +0000 http://dengtongyu.com/?p=94 注意,由于用户不会被要求必须作出允许或者拒绝的选择,所以返回的Promise对象可能既不会触发resolve 也不会触发 reject。 首先在页面中放置一个video标签,用来播放本地摄像头采集到的视频流

     <video id="video" width="200" height="150" autoplay=""></video>

然后在js部分如下

	//获取video标签
	var vedio = document.querySelector('#video');

	//constraints 参数是一个包含了video 和 audio两个成员的MediaStreamConstraints
	//对象,用于说明请求的媒体类型。必须至少一个类型或者两个同时可以被指定。
	var constraints = {
		audio: true,
		video: {
                        //帧率
			frameRate: { ideal: 10,max: 15,min: 8 }
		}
	}

	//获取设备(摄像头或者麦克风)
	navigator.mediaDevices.getUserMedia({ audio: false, video: true })
	.then(function(mediaStream){
		console.log(mediaStream);
		video.src = window.URL.createObjectURL(mediaStream);
		video.onloadedmetadata = function(e) {
		    video.play();
		    console.log(e);
		};
	})
	.catch(function(error){
		console.log(error);
	});


注意:调取本地视频或音频设备的接口,出于安全的考虑,只能在localhost或者https下使用!

demo 传送门]]>
94 0 0 0
小悟 http://dengtongyu.com/archives/110.html Tue, 01 Aug 2017 01:12:01 +0000 http://dengtongyu.com/?p=110 110 0 0 0 egret 练手 《围住神经猫》 http://dengtongyu.com/archives/115.html Mon, 04 Sep 2017 03:42:10 +0000 http://dengtongyu.com/?p=115 白鹭引擎官网 最近学习Egret,看了一些文档后,决定找个简单的项目自己练一下手,《围住神经猫》应该是个很好的选择。 先贴上完成的作品 Demo 1.新建项目 打开EgretWing --> 文件 --> 新建项目 --> Egret游戏项目 完成后打开 src 下的 Main.ts,改文件就是整个项目的入口文件,里面还有一些已经写好的方法,方便你后面调用。 具体请参考 传送门 里面介绍得很详细 2.加载进度条 新建游戏项目后,默认的加载进度比较简陋,我们需要美化一下。 打开 src\LoadingUI.ts 文件,这个就是加载进度条的类。

class LoadingUI extends egret.Sprite {

    public constructor() {
        super();
        this.createView();
    }

    private textField:egret.TextField;

    private createView():void {
        this.textField = new egret.TextField();
        this.addChild(this.textField);
        this.textField.y = 300;
        this.textField.width = 480;
        this.textField.height = 100;
        this.textField.textAlign = "center";
    }

    public setProgress(current:number, total:number):void {
        this.textField.text = `Loading...${current}/${total}`;
    }
}

从代码可以看出,进度条仅仅是用文字展示了加载进度,我们来加个进度条UI美化一下。

class LoadingUI extends egret.Sprite {

    public constructor() {
        super();
        this.createView();
    }

    private textField:egret.TextField;
    private pBarBg:egret.Shape;
    private pBarMove:egret.Shape;

    private createView():void {
        this.pBarBg = new egret.Shape();
        this.pBarBg.graphics.beginFill( 0x989898, 1); 
        this.pBarBg.graphics.drawRect( 0, 0, this.width, this.height ); 
        this.pBarBg.graphics.endFill();
        this.addChild(this.pBarBg);
        
        this.pBarMove = new egret.Shape();
        this.addChild(this.pBarMove);

        this.textField = new egret.TextField();
        this.textField.width = this.width;
        this.textField.textAlign = "center";
        this.textField.y = 15;
        this.addChild(this.textField);
    }
  
    private moveProgressBar(percent:number):void{
        this.pBarMove.graphics.beginFill( 0x518cdd, 1); 
        this.pBarMove.graphics.drawRect( 0, 0, this.width*percent, this.height); 
        this.pBarMove.graphics.endFill();
    }

    public setProgress(current:number, total:number):void {
        var num = Math.floor(current / total * 100);
        this.textField.text = 'Loading...  ' + num.toString() + " %";
        this.moveProgressBar(current/total);
    }
}

效果如图: 20170901165944 3.开始画面 进度条弄好之后,我们开始做游戏开始的画面。如图: 20170901171729 可以看出,开始画面由背景、网格地图和开始按钮的图片组成,这个实现起来很简单。

    private  mapGroup:eui.Group;//地图容器
    private  circleArray:Array<object>;//圆圈网格的数组

    private bg:egret.Bitmap;//开始Bitmap
    private popGroup:eui.Group;//开始画面容器
    private btnStart:eui.Button;//开始按钮
    private btnStartPng:egret.Bitmap;//开始Bitmap

    private init():void{
        //利用白鹭预设的创建bitmap方法创建背景图片
        this.bg = this.createBitmapByName("bg_jpg");
        this.stage.addChild(this.bg);

        //地图容器
        this.mapGroup = new eui.Group();
        this.mapGroup.width = 560;
        this.mapGroup.height = 560;
        this.mapGroup.x = 40;
        this.mapGroup.y = 400;
        this.stage.addChild(this.mapGroup);

        //开始画面容器
        this.popGroup = new eui.Group();
        this.popGroup.width = this.SW;
        this.popGroup.height = this.SH;
        this.popGroup.layout = new eui.BasicLayout();
        this.stage.addChild(this.popGroup);

        //开始Bitmap
        this.btnStartPng = this.createBitmapByName("btn_start_png");
        this.btnStartPng.scaleX = this.btnStartPng.scaleY = 1.2;

        //开始按钮
        this.btnStart = new eui.Button();
        this.btnStart.width = this.btnStartPng.width;
        this.btnStart.height = this.btnStartPng.height;
        this.btnStart.horizontalCenter = 0;
        this.btnStart.verticalCenter = 0;
        this.popGroup.addChild(this.btnStart);
        this.btnStart.addChild(this.btnStartPng);
        this.btnStart.addEventListener(egret.TouchEvent.TOUCH_TAP,this.touchHandler,this);

    }

    private touchHandler(event:TouchEvent) {
        this.popGroup.visible = this.btnStartPng.visible = false;
        this.btnStart.removeEventListener(egret.TouchEvent.TOUCH_TAP,this.touchHandler,this);
     }



然后在createGameScene方法里面执行this.init()就可以了。

但是我们还要绘制围住神经猫的9X9的网格地图。
我们在 src 下面创建一个自定义布局类,命名为 Map.ts

module uilayout {

    var UIComponentClass = "eui.UIComponent";

    /**自定义的布局类*/
    export class CatMap extends eui.LayoutBase{
        public constructor(){
            super();
        }
        /**
         * 计算target的尺寸
         * 如果您的自定义布局需要根据内部子项计算尺寸,请重写这个方法
         **/
        public measure():void{
            super.measure();
        }
        /**
         * 重写显示列表更新
         */
        public updateDisplayList(unscaledWidth:number, unscaledHeight:number):void{
            super.updateDisplayList(unscaledWidth, unscaledHeight);
            if (this.target==null)
                return;
	    let sunElement:eui.UIComponent;
	    //子元素个数		
            let count:number = this.target.numElements;
            //元素x轴方向间隔
	    let gapX:number = 0;
            //元素y轴方向间隔
            let gapY:number = 0;
            //元素所在列数
	    let column:number = 0;
            //元素所在行数
	    let row:number = 0;
            //奇偶行数错位距离
	    let parityWidth:number = 0;
            if(count > 0) {
		sunElement = <eui.uicomponent> this.target.getElementAt(0);
		gapX = (unscaledWidth - sunElement.width * 9 - sunElement.width / 2)/8;
		gapY = (unscaledHeight - sunElement.height * 9 - sunElement.height / 2)/8;
		//console.log(unscaledWidth,unscaledHeight,sunElement.width,sunElement.height);
	   }
           for (let i:number = 0; i < count; i++){

                let layoutElement:eui.UIComponent = <eui.uicomponent> ( this.target.getElementAt(i) );
                if ( !egret.is(layoutElement,UIComponentClass) || !layoutElement.includeInLayout ) {
                    continue;
                }
		row = Math.floor(i / 9);
		column = i % 9;
		if(row % 2 == 0) {
			parityWidth = 0;
		}else{
			parityWidth = layoutElement.width / 2;
		} 
		let childX:number = column * (layoutElement.width + gapX) + parityWidth;
		let childY:number = row * (layoutElement.height + gapY);
                layoutElement.setLayoutBoundsPosition(childX, childY);
            }
        }
    }
}

这样一个自定义布局类就写好了,如果对自定义布局不太了解的,可以去Egret的官网查看文档 传送门 然后,我们在Main.ts入口文件里绘制9X9的圆圈网格。

/**创建网格**/
     private creatMap() {
        this.circleArray = new Array();
        for(let i = 0;i<81;i++){ let circleData = new Object(); circleData['ui'] = new eui.Group(); circleData['ui'].name = i; circleData['img1'] = this.createBitmapByName('pot1_png'); circleData['img2'] = this.createBitmapByName('pot2_png'); if(i == 40) { circleData['img1'].visible = true; circleData['img2'].visible = false; circleData['val'] = 0; }else{ if(Math.random()*10 > 8) {
                    circleData['img1'].visible = false;
                    circleData['img2'].visible = true;
                    circleData['val'] = 1;
                }else{
                    circleData['img1'].visible = true;
                    circleData['img2'].visible = false;
                    circleData['val'] = 0;
                }
            }
            this.circleArray.push(circleData);
            circleData['img1'].scaleX = circleData['img1'].scaleY = 1.2;
            circleData['img2'].scaleX = circleData['img2'].scaleY = 1.2;
            circleData['ui'].width = circleData['img1'].width;
            circleData['ui'].height = circleData['img1'].height;
            //circleData['ui'].layout = new eui.BasicLayout();
            circleData['ui'].addChild(circleData['img1']);
            circleData['ui'].addChild(circleData['img2']);
            if(i == 40) {//中间神经猫的位置
                this.insertRunCat(circleData['ui']);
                this.cat.visible = false;
                this.catPos = 40;
            }
            if(circleData['val'] == 0) {
                circleData['img1'].touchEnabled = true;
                circleData['img1'].addEventListener(egret.TouchEvent.TOUCH_TAP,this.touchCircle,this);
            }
            this.mapGroup.addChild(circleData['ui']);
        }
        //引用自定义布局
        this.mapGroup.layout = new uilayout.CatMap();
     }

然后在init方法里面执行this.creatMap()就可以完成绘制了 20170901171508 后面的操作逻辑就不赘述了,有机会再跟大家分享。]]>
115 0 0 0
Angular CLI 之初体验 http://dengtongyu.com/archives/143.html Wed, 20 Sep 2017 09:13:04 +0000 http://dengtongyu.com/?p=143 Angular CLI是一个命令行界面工具,它可以创建项目、添加文件以及执行一大堆开发任务,比如测试、打包和发布。 比起需要自己去搭建工作流,Angular CLI 可以为你省去这些繁琐的工作,直接进行项目的开发。

配置开发环境

  1. 安装最新版本的node,angular官方要求node 6.9.x 和 npm 3.x.x 以上的版本。 具体安装请参考 node官网 ,安装过程不再赘述。
  2. 全局安装 Angular CLI
    npm install -g @angular/cli

创建新项目

  1. 打开终端窗口 运行下列命令来生成一个新项目以及应用的骨架代码:
    ng new myapp
  2. 进入项目目录,并启动服务器。
    cd myapp
    ng serve --open
    ng serve命令会启动开发服务器,监听文件变化,并在修改这些文件时重新构建此应用。 使用--open(或-o)参数可以自动打开浏览器并访问http://localhost:4200/。

    app-works

设置代理

  1. 我们开发的时候,有时需要对接口做代理,Angular CLI同样给我们提供了设置代理的方式

    首先在项目的根目录下创建一个proxy.conf.json 文件

    {
        "/data": {
            "target": "http://xxx.xxx.xxx.xxx:8080",
            "secure": false,
            "changeOrigin": true
        }
    }

    "/data"是接口所包含的字符,target则是代理的ip和端口号

  2. 然后在项目的根目录打开终端,运行下面的指令:
    ng serve --proxy-config proxy.conf.json

    这样代理的设置就完成了。

样式编译

Angular CLI 支持sass、less、stylus等方式编译样式

  1. 在创建项目时可以设置编译方式:
    ng new myapp --style=sass
    ng new myapp --style=less
    ng new myapp --style=stylus
    

    上面分别是创建项目时设定的样式编译方式:sass、less、stylus

  2. 当然,你也可以在手动修改,在项目根目录下找到 .angular-cli.json
    "defaults": {
        "styleExt": "styl",
        "component": {}
      }

    defaults下面的styleExt就是你要设定的编译方式,这里采用了stylus,stylus的后缀为styl,其他的方式设置对应的后缀名。

    然后继续在该文件中找到

    "styles": [
            "styles.styl"
          ]

    全改完了之后,不要忘了把项目根目录里的css文件和src/app里的css文件也改成相应的后缀

打包编译后资源引入根目录

Angular CLI 打包编译后,引入的资源都是"/"根目录引入,但有时候我们的项目可能并不是存放在域名的根目录,所以这种情况就需要我们设置一下引入资源的根目录了

  1. 打开src目录下面的index.html文件,在<head>标签里面有个base标签
    <!doctype html>
    <html>
    <head>
      <meta charset="utf-8">
      <title>myapp</title>
      <base href="/">
      <link rel="icon" type="image/x-icon" href="favicon.ico">
    </head>
    <body>
      <app-root></app-root>
    </body>
    </html>         
    

    base标签默认是"/"根目录

  2. 然后我们回到整项目的根目录下面找到package.json文件,打开文件,找到"scripts",修改"build"的值
    "scripts": {
        "ng": "ng",
        "start": "ng serve --proxy-config proxy.conf.json",
        "build": "ng build --prod --bh /pages/myapp/",
        "test": "ng test",
        "lint": "ng lint",
        "e2e": "ng e2e"
      },
    

    然后在命令行中输入

    npm run build 
    
    等待编译完成后,在dist目录下的index.html文件中的base标签的值就变成你之前设置的目录了,引入的资源放到正式环境也可以正常访问。

    当然,你也可以不设置package.json文件,直接在命令行输入

    ng build --prod --bh /pages/myapp/
    或者
    ng build --prod --base-href /pages/myapp/
    
]]>
143 0 0 0
vue CLI 代理设置以及打包引入配置 http://dengtongyu.com/archives/173.html Tue, 17 Oct 2017 07:25:49 +0000 http://dengtongyu.com/?p=173 代理设置

在用 vue CLI 做开发的时候,很多时候我们需要用到代理请求获取数据,vue CLI 也很方便的为我们提供配置代理的API,打开vue CLI项目的 /config/index.js 文件,找到dev里的proxyTable


module.exports = {
  //代理设置
  dev: {
    env: require('./dev.env'),
    port: 8080,
    autoOpenBrowser: true,
    assetsSubDirectory: 'static',
    assetsPublicPath: '/',
    proxyTable: {
      '/data': {
        target: 'http://dengtongyu.com',  //代理目标地址
        secure: false,
        changeOrigin: true
      }
    },
    cssSourceMap: false
  }
}

打包引入配置

我们用vue CLI打包项目的时候默认引入的资源是"/"根目录,如果我们的项目在非根目录下就要重新配置一下了,同样的,打开vue CLI项目的 /config/index.js 文件,找到build里的assetsPublicPath


module.exports = {
  build: {
    env: require('./prod.env'),
    index: path.resolve(__dirname, '../dist/index.html'),
    assetsRoot: path.resolve(__dirname, '../dist'),
    assetsSubDirectory: 'static',
    assetsPublicPath: '/pages/myproject/',   //配置引入资源的根目录
    productionSourceMap: true,
    productionGzip: false,
    productionGzipExtensions: ['js', 'css'],
    bundleAnalyzerReport: process.env.npm_config_report
  }
]]>
173 0 0 0
egret粒子系统官方文档的那些坑 http://dengtongyu.com/archives/200.html Fri, 20 Oct 2017 08:33:15 +0000 http://dengtongyu.com/?p=200 最近体验了一下egret粒子系统,看了官方文档后,照着文档写,发现各种报错,不知道是原来文档就是错误的,还是egret版本多次迭代后,文档没有及时更新,而且在egret开发者中心提供的QQ群加了也没有回应,或许是egret官方太忙了,但是不管怎样,这种错误的官方文档对新手很不友好。

下面我来说说我在体验egret粒子系统踩的一些坑

说到egret的粒子系统,egret官方提供了一个制作粒子素材的工具——Egret Feather

有兴趣的可以移步到相关的官方文档查看,因为我使用Egret Feather的时候没有遇到什么问题,所以这里就不做赘述了,大家看官方文档就好了

egret粒子系统官方文档的错误?

在egret的粒子系统文档中(传送门),在创建粒子示例的地方是这样的

egret粒子系统创建示例

按照示例的代码在egret 4.0.3版本中,编译就会报错

error TS2339: Property 'system' does not exist on type 'Main'.

'system'这个属性不属于'Main',新人们在这里会懵逼一会儿,但是代码是死的,人是活的,我直接用个变量来保存particle对象嘛。我把代码改一下

        let texture = RES.getRes("funny");
        let config = RES.getRes("funny_json");
        let funny = new particle.GravityParticleSystem(texture, config);
        funny.start();
        this.addChild(funny);

我用个变量funny来保存particle对象,然后我再编译一下,没有报错,但是刷新浏览器的时候报错了

Uncaught TypeError: Cannot read property 'textureWidth' of null

无法读取纹理的宽度,其值为null。出现这种报错一般就是纹理加载不成功,所以要看看加载素材的地方

        let texture = RES.getRes("funny");
        let config = RES.getRes("funny_json");

上面的纹理加载很明显与egret的素材加载方式有点不一样,不知道官方文档为什么会这样写,所以我改了一下,把纹理的后缀加上

        let texture = RES.getRes("funny_png");
        let config = RES.getRes("funny_json");

编译没有报错,刷新浏览器,粒子效果完美呈现。demo传送门

egret粒子系统demo

egret粒子系统库的引入,另一个坑?

egret粒子系统库的引入也是一个小坑,我从egret第三方库的GitHub上下载了particle粒子库,然后放到项目里引入,结果编译时间很久,而且会各种报错,经过一系列的Google 百度后,结果是:

第三方库必须放到项目外面!

第三方库必须放到项目外面!

第三方库必须放到项目外面!

重要的事情说三遍

]]>
200 0 0 0
egret 获取设备陀螺仪信息以及运动状态信息 http://dengtongyu.com/archives/217.html Wed, 22 Nov 2017 07:55:55 +0000 http://dengtongyu.com/?p=217 egret.DeviceOrientation 可以监听设备方向的变化。 egret.Motion从用户设备读取运动状态信息并派发 CHANGE 事件。当设备移动时,传感器会检测到此移动并返回设备加速度,重力和旋转数据。 废话不多说,直接上代码:
    class Main extends egret.DisplayObjectContainer {

    private orientationLabel: egret.TextField;

    private motionLabel: egret.TextField;

    public constructor() {
        super();

        this.orientationLabel = new egret.TextField();
        this.orientationLabel.width = 640;
        this.orientationLabel.textAlign = egret.HorizontalAlign.CENTER;
        this.addChild(this.orientationLabel);

        this.motionLabel = new egret.TextField();
        this.motionLabel.width = 640;
        this.motionLabel.y = 300;
        this.motionLabel.textAlign = egret.HorizontalAlign.CENTER;
        this.addChild(this.motionLabel);

        //创建 DeviceOrientation 类
        var orientation = new egret.DeviceOrientation();
        //添加事件监听器
        orientation.addEventListener(egret.Event.CHANGE,this.onOrientation,this);
        //开始监听设备方向变化
        orientation.start();

        //创建 Motion 类
        var motion = new egret.Motion();
        //添加事件监听器
        motion.addEventListener(egret.Event.CHANGE,this.onMotion,this);
        //开始监听设备方向变化
        motion.start();
    }

    private onOrientation(e:egret.OrientationEvent){
        this.orientationLabel.textFlow = >[
            {text: "绕 Z 轴的角度:\n"}
            , {text: e.alpha, style: {"textColor": 0xff0000}}
            , {text: "\n\n绕 X 轴的角度:\n"}
            , {text: e.beta, style: {"textColor": 0xff0000}}
            , {text: "\n\n绕 Y 轴的角度:\n"}
            , {text: e.gamma, style: {"textColor": 0xff0000}}
        ];
    }

    private onMotion(e:egret.MotionEvent){
      this.motionLabel.textFlow = >[
            {text: "X 轴方向的加速度\n"}
            , {text: e.acceleration.x, style: {"textColor": 0xff0000}}
            , {text: "\n\nY 轴方向的加速度:\n"}
            , {text: e.acceleration.y, style: {"textColor": 0xff0000}}
            , {text: "\n\nZ 轴方向的加速度:\n"}
            , {text: e.acceleration.z, style: {"textColor": 0xff0000}}
            , {text: "\n\nX 轴加速度(考虑重力加速度)\n"}
            , {text: e.accelerationIncludingGravity.x, style: {"textColor": 0xff0000}}
            , {text: "\n\nZ 轴方向的加速度:\n"}
            , {text: e.accelerationIncludingGravity.y, style: {"textColor": 0xff0000}}
            , {text: "\n\nZ 轴方向的加速度:\n"}
            , {text: e.accelerationIncludingGravity.z, style: {"textColor": 0xff0000}}
            , {text: "\n\n左右旋转速度(alpha轴向的角速度)\n"}
            , {text: e.rotationRate.alpha, style: {"textColor": 0xff0000}}
            , {text: "\n\n前后旋转速度(beta轴向的角速度)\n"}
            , {text: e.rotationRate.beta, style: {"textColor": 0xff0000}}
            , {text: "\n\n扭转速度(gamma轴向的角速度)\n"}
            , {text: e.rotationRate.gamma, style: {"textColor": 0xff0000}}
        ];
    }
}
首先创建了DeviceOrientation的实例orientation。并给他添加了一个事件侦听器,监听它的CHANGE事件。然后调用了他的start()方法来开始监听设备方向的变化。 当系统监听到了方向的变化后,将回调函数 onOrientation。然后通过egret.OrientationEvent事件的三个属性来获取设备的方向变化信息。 OrientationEvent的三个属性:alpha,beta和gamma。 alpha表示设备绕 Z 轴的角度,单位是 角度 beta 表示设备绕 X 轴的角度,单位是 角度 gamma 表示设备绕 Y 轴的角度,单位是 角度 同样,创建了Motion的实例motion。并给他添加了一个事件侦听器,监听它的CHANGE事件。然后调用了他的start()方法来开始监听设备方向的变化。 当系统监听到了方向的变化后,将回调函数 onMotion。然后通过egret.MotionEvent事件的三个属性来获取设备运动的具体信息。 acceleration 表示设备在 X Y Z 轴方将的加速度信息,单位是 m/s2,不包含重力。 acceleration 表示设备在 X Y Z 轴方将的加速度信息,单位是 m/s2,包含重力。 rotationRate 表示设备在 alpha、 beta 和 gamma 三个轴向的角速度信息,单位是 角度每秒。 最终的效果demo->传送门 或者手机扫一扫: egret陀螺仪demo]]>
217 0 0 0
egret天空盒子浅尝 http://dengtongyu.com/archives/238.html Wed, 22 Nov 2017 10:35:36 +0000 http://dengtongyu.com/?p=238 egret3d.Sky 在 Egret 3D 所创建的空间中最外层是由天空盒子来包裹起来的。我们通常使用天空盒子来展现风景,地平线,天空,星空等等空间的“大背景”。天空盒子由一组无缝的贴图包裹起来的盒状空间。当我们的 3D 场景中包含有物体时,天空盒子总是充当其背景。 天空盒子 环境:egret 5.0.12 IDE:egret wing 3

加载天空盒子素材资源

通过egret3d.QueueLoader加载器加载资源,然后监听资源加载完成事件egret3d.LoaderEvent3D.LOADER_COMPLETE。

    /**
     *  加载器
     */
    private queueLoader: egret3d.QueueLoader;
    // 加载天空盒资源
    private loaderSkyBox() {
        this.queueLoader = new egret3d.QueueLoader();
        this.queueLoader.load("resource/front.png");
        this.queueLoader.load("resource/back.png");
        this.queueLoader.load("resource/left.png");
        this.queueLoader.load("resource/right.png");
        this.queueLoader.load("resource/up.png");
        this.queueLoader.load("resource/down.png");
        this.queueLoader.addEventListener(egret3d.LoaderEvent3D.LOADER_COMPLETE, this.onSkyBoxTexture, this);
    }

创建天空盒子

资源加载完成后,用egret3d.Sky创建天空盒子,egret3d.Sky方法有三个参数, Sky(geometry:egret3d.Geometry, material:egret3d.MaterialBase, camera:egret3d.Camera3D), 分别是3D几何形状,纹理贴图,摄像机。然后把天空盒子添加到3D显示类里。

    // 天空盒资源加载完成 创建天空盒
    private onSkyBoxTexture(e: egret3d.LoaderEvent3D) {
        var loader: egret3d.QueueLoader = e.target;

        var fr: egret3d.ITexture = loader.getAsset("resource/front.png");
        var bk: egret3d.ITexture = loader.getAsset("resource/back.png");
        var lf: egret3d.ITexture = loader.getAsset("resource/left.png");
        var rt: egret3d.ITexture = loader.getAsset("resource/right.png");
        var up: egret3d.ITexture = loader.getAsset("resource/up.png");
        var dn: egret3d.ITexture = loader.getAsset("resource/down.png");

        // 创建cube贴图
        var cubeTexture: egret3d.CubeTexture = egret3d.CubeTexture.createCubeTextureByImageTexture(bk, fr, lf, rt, up, dn);

        // 创建cube geometry 和 cube 材质
        var sky: egret3d.Sky = new egret3d.Sky(new egret3d.CubeGeometry(500, 500, 500), new egret3d.CubeTextureMaterial(cubeTexture), this.view.camera3D);
        // 设置天空盒 渲染模式为背面渲染
        sky.material.cullMode = egret3d.ContextConfig.FRONT;
        this.view.addChild3D(sky);
        
    }

获取陀螺仪信息

我们需要通过获取陀螺仪信息来根据手机的旋转,让天空盒子视角旋转对应的角度。

    // 获取设备旋转角度
    private setOrientation() {
        //创建 DeviceOrientation 类
        var orientation = new egret.DeviceOrientation();
        //添加事件监听器
        orientation.addEventListener(egret.Event.CHANGE,this.onOrientation,this);
        //开始监听设备方向变化
        orientation.start();
    }

    private onOrientation(e:egret.OrientationEvent){
        this._alpha = e.alpha;
        this._beta = e.beta;
        this._gamma = e.gamma;
       
        this.cameraCtl.rotationY = (this._alpha % 360) * (-1);
        this.cameraCtl.rotationX = (this._beta - 90) % 360 * (-1);
        this.cameraCtl.rotationZ = 0;

        //console.log(e.rotationRate)
    }
最终效果->传送门 手机扫一扫 egret天空盒子demo]]>
238 0 0 0
egret引用Animate CC发布的HTML5 Canvas http://dengtongyu.com/archives/252.html Fri, 15 Dec 2017 10:04:34 +0000 http://dengtongyu.com/?p=252 在flash时代,我们可以在Adobe Flash中导出swf,然后在ActionScript 3.0项目里面引用。让设计人员可以直接提供素材给开发人员,这大大提高了开发效率。

但在egret里,虽然官方也提供了很丰富的工具,但是不得不承认,目前并没有足够的设计人员参与进来,导致开发人员拿到素材后还要“二次加工”,开发效率自然上不去。

所以,在Adobe Animate CC已经普及的今天,我们能不能让Animate CC导出的HTML5 Canvas直接用到我们的项目里呢?

在我尝试了一翻后,确实能达到不错的效果。


1.建立引用路径

egret引用HTML5 Canvas

在egret项目里建立一个存放Animate CC导出的HTML文件目录,这里我引用了/html/man的实例。里面的index.html和index.js是用Animate CC发布导出的


2.动画采集器

通过外部引用html,然后获取页面的canvas的bitmap,然后添加到egret的舞台上。

新创建一个类,命名为CollectAnimation.ts

class CollectAnimation extends egret.DisplayObjectContainer {
	
	private _iframe:any;

	private _canvas:any;

	private _canvasBitmapData:any;

	private _canvasTexture:egret.Texture;

	private _canvasBitmap:egret.Bitmap;

	private _oldCanvasBitmap:egret.Bitmap;

	private _timer:egret.Timer;
	
	public constructor(url:string) {
		super();

		this._iframe = document.createElement('iframe');
		this._iframe.style.height = 0;
		this._iframe.style.border = 'none';
		this._iframe.style.display = 'none';
		this._iframe.src = url;
		document.querySelector('body').appendChild(this._iframe);
		this._iframe.onload = () => {
			this._canvas = this._iframe.contentWindow.canvas;
			
			//console.log(this._canvas);
		}

		this._timer = new egret.Timer(50);
		this._timer.addEventListener(egret.TimerEvent.TIMER,this.timerFunc,this);
	}

	public get getCanvasBitmap() {
		if(this._canvas) {
			this._canvasBitmapData = new egret.BitmapData(this._canvas);
			this._canvasTexture = new egret.Texture();
			this._canvasTexture.bitmapData = this._canvasBitmapData;
			this._canvasBitmap = new egret.Bitmap(this._canvasTexture);
			return this._canvasBitmap;
		}else{
			return null;
		}
		
	}

	private timerFunc() {
		if(this._canvas) {

			this._canvasBitmapData = new egret.BitmapData(this._canvas);
			this._canvasTexture = new egret.Texture();
			this._canvasTexture.bitmapData = this._canvasBitmapData;
			if(this._canvasBitmap) {
				this._oldCanvasBitmap = this._canvasBitmap;
			}
			this._canvasBitmap = new egret.Bitmap(this._canvasTexture);
			if(this._oldCanvasBitmap && this._oldCanvasBitmap.parent) {
                this.removeChild(this._oldCanvasBitmap);
            }
            this.addChild(this._canvasBitmap);
		}
    }

	public start() {
		this._timer.start();
	}

	public stop() {
		this._timer.stop();
	}

	public depose() {
		if(this._iframe) {
			this._iframe = null;
		}

		if(this._canvas) {
			this._canvas = null;
		}

		if(this._canvasBitmapData) {
			this._canvasBitmapData = null;
		}

		if(this._canvasTexture) {
			this._canvasTexture = null;
		}

		if(this._canvasBitmap) {
			this._canvasBitmap = null;
		}

		if(this._oldCanvasBitmap) {
			this._oldCanvasBitmap = null;
		}

		if(this._timer) {
			this._timer.stop();
			this._timer = null;
		}

		if(this.parent) {
			this.parent.removeChild(this);
		}
	}
}

3.在egret中使用

在Main.ts中使用我们刚刚创建的类

class Main extends egret.DisplayObjectContainer {
    
    public constructor() {
        super();

        this.addEventListener(egret.Event.ADDED_TO_STAGE, this.onAddToStage, this);

    }

    private onAddToStage(event: egret.Event) {

        let man = new CollectAnimation('html/man/index.html');
        this.addChild(man);
        man.start();
        
        // setTimeout(() =>{
        //     man.stop();
        //     man.depose();
        //     man = null;
        // },3000)
        
    }
}

通过start和stop方法开始播放和停止,depose方法删除

以上就是在egret中引用HTML5 Canvas的一些尝试,还有别的东西可能要等我慢慢挖掘了。

效果->传送门

]]>
252 0 0 0
egret3d 用视频video做纹理贴图 http://dengtongyu.com/archives/267.html Mon, 29 Jan 2018 09:50:02 +0000 http://dengtongyu.com/?p=267 前段时间学习了一下egret3d,然后有些奇妙的想法,如果用视频video来做纹理贴图可不可以呢?于是就尝试了一下,效果还不错。

思路也很简单,创建一个立方体,然后把立方的纹理设置成一个视频video,主要代码如下

     public createGameScene() {

        this.createVideoTexture();

        this.loaderSkyBox();
    }
    //创建视频纹理
    private createVideoTexture() {
        this.video = new egret3d.VideoTexture(640,264);
        this.video.source = "resource/oceans-clip.mp4";
    }

    // 加载资源
    private loaderSkyBox() {
        this.queueLoader = new egret3d.QueueLoader();
        this.queueLoader.load("resource/background.jpg");
        this.queueLoader.addEventListener(egret3d.LoaderEvent3D.LOADER_COMPLETE, this.onSkyBoxTexture, this);
    }

    // 资源加载完成 创建立方体
    private onSkyBoxTexture(e: egret3d.LoaderEvent3D) {
        // 设置背景
        let panelIamge: egret3d.ITexture = this.queueLoader.getAsset("resource/background.jpg");
        this.view.backImage = panelIamge;

        // 创建立方体和cube贴图
        this.ge = new egret3d.CubeGeometry(200, 200, 200);
        this.mat = new egret3d.TextureMaterial(panelIamge);
        this.mat.diffuseTexture = this.video;

        this.mesh = new egret3d.Mesh(this.ge,this.mat);
        this.view.addChild3D(this.mesh);

        // 更新摄像机信息
        this.cameraCtl.distance = 1000;
        this.cameraCtl.rotationX = 45;
        this.cameraCtl.rotationY = 45;

        this.cameraCtl.update();
        
    }

效果->传送门

视频贴图]]>
267 0 0 0
浅尝 HTML 5 input 新属性 http://dengtongyu.com/archives/276.html Wed, 07 Feb 2018 10:16:11 +0000 http://dengtongyu.com/?p=276 #color::-webkit-input-placeholder { /* WebKit, Blink, Edge */ color:#f00; } #color::-moz-placeholder { /* Mozilla Firefox 19+ */ color:#f00; } #color:-ms-input-placeholder { /* Internet Explorer 10-11 */ color:#f00; } dl input { border: 1px solid #ccc; }

required 属性

required属性规定必需在提交表单之前填写输入字段。

<!-- 此输入框为必填-->
<input type="text" required>
			

list 属性

属性引用 datalist 元素,其中包含 input 元素的预定义选项。

<input list="city">
<datalist id="city">
<option value="北京">
<option value="上海">
<option value="广州">
<option value="深圳">
<option value="杭州">
</datalist> 
				

maxlength 属性

属性规定 input 元素中允许的最大字符数。

 <!-- 只允许输入3个字符 -->
<input type="text" name="usrname" maxlength="3">
			

max min 属性

属性规定 input 元素的最大和最小值。

<!-- 最大值为10 -->
<input type="number" max="10" required>
<!-- 最小值为10 -->
<input type="number" min="10" required>
<!-- 1到10之间的数字 -->
<input type="number" min="1" max="10" required>
			

multiple 属性

可接受多个值的文件上传字段

<!-- 按住Ctrl,可选择上传多个文件 -->
<input type="file" multiple required>
			

pattern 属性

pattern 属性规定用于验证 input 元素的值的正则表达式。

<!-- 用pattern属性限制只能输入字母 -->
<input type="text" pattern="^[a-zA-Z]+$" title="只能输入字母" required>
			

step 属性

step 属性规定 input 元素的合法数字间隔。

<!-- 只能输入能被5整除的数字 -->
<input type="number" step="5" required>
			

src alt 属性规定

input按钮用图片展示

<!-- src的值可以是图片链接或者base64 -->
<input type="image" src="data:image/png;base64">
			

placeholder 属性

placeholder 属性规定可描述输入 input 字段预期值的简短的提示信息 。

<!-- 带有 placeholder 文本的输入字段 -->
<input type="text" placeholder="请输入你的文本">

<!-- placeholder 文本也可以指定颜色 -->
<style type="text/css">	
#color::-webkit-input-placeholder { /* WebKit, Blink, Edge */
    color:#f00;
}
#color::-moz-placeholder { /* Mozilla Firefox 19+ */
   color:#f00;
}
#color:-ms-input-placeholder { /* Internet Explorer 10-11 */
   color:#f00;
}
</style>
<input id="color" type="text" placeholder="请输入你的文本">
			

type 属性

在HTML5中,type有了更多丰富的控件类型让我们使用

color 拾色器


<!-- 拾色器 -->
<input type="color">
			

date 日期控件


<!-- 日期控件 -->
<input type="date">
			

month 年月控件


<!-- 定义 month 和 year 控件(不带时区) -->
<input type="month">
			

time 时间控件


<!-- 定义用于输入时间的控件(不带时区) -->
<input type="time">
			

week 周控件


<!-- 定义 week 和 year 控件(不带时区) -->
<input type="week">
			

datetime-local 带时间的日期控件


<!-- date 和 time 控件(不带时区) -->
<input type="datetime-local">
			

email 定义用于 e-mail 地址的字段(当提交表单时会自动对 email 字段的值进行验证)


<!-- 输入的必须是邮箱格式 -->
<input type="email" required>
			

number 数字


<!-- 输入的必须是数字 -->
<input type="number">
			

password 密码


<!-- 输入密码控件 -->
<input type="password">
			

range 范围取值


<!-- 选择1到10的范围 -->
<input type="range" min="1" max="10">
			

tel 电话


<!-- 输入的值必须是电话号码 -->
<input type="tel">
			

url 链接


<!-- 输入的值必须是链接 -->
<input type="url" required>
			

页面demo

]]>
276 0 0 0
https实践,Let's Encrypt 免费泛域名 SSL 证书申请 http://dengtongyu.com/archives/304.html Thu, 12 Jul 2018 03:26:42 +0000 http://dengtongyu.com/?p=304

2018 年 3 月 14 日,Let’s Encrypt 对外宣布 ACME v2 已正式支持泛域名证书。这就意外味着用户可以在 Let’s Encrypt 上免费申请支持泛域名的 SSL 证书。

什么是 Let’s Encrypt

部署 HTTPS 网站的时候需要证书,证书由 CA 机构签发,大部分传统 CA 机构签发证书是需要收费的,这不利于推动 HTTPS 协议的使用。

Let’s Encrypt 也是一个 CA 机构,但这个 CA 机构是免费的!也就是说签发证书不需要任何费用。

Let’s Encrypt 是国外一个公共的免费 SSL 项目,由 Linux 基金会托管。由 Mozilla、思科、Akamai、IdenTrust 和 EFF 等组织发起,目的就是向网站自动签发和管理免费证书。以便加速互联网由 HTTP 过渡到 HTTPS,目前 Facebook 等大公司开始加入赞助行列。

Let’s Encrypt 已经得了 IdenTrust 的交叉签名,这意味着其证书现在已经可以被 Mozilla、Google、Microsoft 和 Apple 等主流的浏览器所信任。用户只需要在 Web 服务器证书链中配置交叉签名,浏览器客户端会自动处理好其它的一切,Let’s Encrypt 安装简单,使用非常方便。

什么是泛域名证书

泛域名证书类似 DNS 解析的泛域名概念,泛域名证书就是证书中可以包含一个通配符。主域名签发的泛域名证书可以在所有子域名中使用,比如 demo.domain.com、bbs.domain.com。这样就一张证书可以用于更多的主机了

如何申请 Let’s Encrypt 泛域名证书

Let’s Encrypt 上的证书申请是通过 ACME 协议来完成的。ACME 协议规范化了证书申请、更新、撤销等流程,实现了 Let’s Encrypt CA 自动化操作。解决了传统的 CA 机构是人工手动处理证书申请、证书更新、证书撤销的效率和成本问题。

ACME v2 是 ACME 协议的更新版本,泛域名证书只能通过 ACME v2 获得。要使用 ACME v2 协议申请泛域名证书,只需一个支持该协议的客户端就可以了,官方推荐的客户端是 Certbot。

安装Certbot

如果没有下载安装过Certbot,先下载Certbot客户端

wget https://dl.eff.org/certbot-auto

然后把certbot-auto设为可执行权限

chmod a+x certbot-auto

升级Certbot

如果已经安装了Certbot,查看下自己的Certbot客户端是不是支持 ACME v2 版本,官方介绍 Certbot 0.22.0 版本支持新的协议版本

./certbot-auto --version
Upgrading certbot-auto 0.21.1 to 0.25.1...
Replacing certbot-auto... 

./certbot-auto --version
certbot 0.22.0 

客户在申请 Let’s Encrypt 证书的时候,需要校验域名的所有权,证明操作者有权利为该域名申请证书,目前支持三种验证方式:

  1. dns-01:给域名添加一个 DNS TXT 记录。
  2. http-01:在域名对应的 Web 服务器下放置一个 HTTP well-known URL 资源文件。
  3. tls-sni-01:在域名对应的 Web 服务器下放置一个 HTTPS well-known URL 资源文件。

申请泛域名证书

申请泛域名证书,只能使用 dns-01 的方式

使用 Certbot 客户端申请证书方法比较的简单,输入以下命令:

./certbot-auto certonly  -d domain.com -d *.domain.com --manual --preferred-challenges dns --server https://acme-v02.api.letsencrypt.org/directory 

1、把domain换成你自己的域名。

2、*.domain.com可作用于所有子域名,但好像不能作用于domain.com,所以加上domain.com这样的裸域名。

相关参数说明

  1. certonly,表示安装模式,Certbot 有安装模式和验证模式两种类型的插件。
  2. --manual 表示手动安装插件,Certbot 有很多插件,不同的插件都可以申请证书,用户可以根据需要自行选择
  3. -d 为那些主机申请证书,如果是通配符,输入 *.domain.com(可以替换为你自己的域名)
  4. --preferred-challenges dns,使用 DNS 方式校验域名所有权
  5. --server,Let's Encrypt ACME v2 版本使用的服务器不同于 v1 版本,需要显示指定。

执行完这一步之后,就是命令行的输出,请根据提示输入相应内容:

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer None
Cert is due for renewal, auto-renewing...
Renewing an existing certificate
Performing the following challenges:
dns-01 challenge for xxxxx.com
dns-01 challenge for xxxxx.com

-------------------------------------------------------------------------------
NOTE: The IP of this machine will be publicly logged as having requested this
certificate. If you're running certbot in manual mode on a machine that is not
your server, please ensure you're okay with that.

Are you OK with your IP being logged?
-------------------------------------------------------------------------------
(Y)es/(N)o: y

上述有两个交互式的提示:

  1. 是否同意 Let's Encrypt 协议要求
  2. 询问是否对域名和机器(IP)进行绑定

确认同意才能继续。

继续查看命令行的输出,非常关键:

-------------------------------------------------------------------------------
Please deploy a DNS TXT record under the name
_acme-challenge.xxxxx.com with the following value:

XQOqY8npyso******ovtudA3zMd_C1dh9bjMEkbkKHM

Before continuing, verify the record is deployed.
-------------------------------------------------------------------------------
Press Enter to Continue

执行到上图最后一步时,先暂时不要回车。要求配置 DNS TXT 记录,从而校验域名所有权,也就是判断证书申请者是否有域名的所有权。接下来需要按照提示在域名后台添加对应的 DNS TXT 记录。

上面输出要求给 _acme-challenge.XXXXX.com 配置一条 TXT 记录,在没有确认 TXT 记录生效之前不要回车执行。

我使用的是阿里云的域名服务器,登录控制台操作如下图:

泛域名证书

如上图所示,有两条DNS TXT,因为我们申请的时候就有两个域名,domain.com 和 *.domain.com,所以我们在阿里云的后台添加一条DNS TXT后,我们回到命令行,按回车继续,然后会输出第二条DNS TXT

-------------------------------------------------------------------------------
Please deploy a DNS TXT record under the name
_acme-challenge.xxxxx.com with the following value:

XQOqY8npyso******ovtudA3zMd_C1dh9bjMEkbkKHM

Before continuing, verify the record is deployed.
-------------------------------------------------------------------------------
Press Enter to Continue

同样,按照上面的步骤在阿里云的后台多加一条DNS TXT解析就好。加完稍等几分钟后,回到命令行,按回车

Waiting for verification...
Cleaning up challenges

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/dengtongyu.com/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/dengtongyu.com/privkey.pem
   Your cert will expire on 2018-XX-XX. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot-auto
   again. To non-interactively renew *all* of your certificates, run
   "certbot-auto renew"
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le
Press Enter to Continue

看到上面的输出,说明已经生效。

你也可以输入以下命令确认 TXT 记录是否生效:

dig  -t txt  _acme-challenge.XXXXXX.com @8.8.8.8

; <<>> DiG 9.10.6 <<>> -t txt _acme-challenge.XXXXXX.com @8.8.8.8
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 55138
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;_acme-challenge.XXXXXX.com.	IN	TXT

;; ANSWER SECTION:
_acme-challenge.XXXXXX.com.	599 IN	TXT	"bQzqaEADZbE******KvPiltbucW130jaj9PNTkAH3mU"
_acme-challenge.dengtongyu.com.	599 IN	TXT	"XQOqY8npyso******ovtudA3zMd_C1dh9bjMEkbkKHM"

;; Query time: 175 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Thu Jul 12 10:59:20 CST 2018
;; MSG SIZE  rcvd: 171

到了这一步后,恭喜您,证书申请成功。 证书和密钥保存在下列目录:

/etc/letsencrypt/live/xxx.com/

├── cert.pem
├── chain.pem
├── fullchain.pem
└── privkey.pem

然后校验证书信息,输入如下命令:

openssl x509 -in  /etc/letsencrypt/live/xxx.com/cert.pem -noout -text 
...
Authority Information Access: 
        OCSP - URI:http://ocsp.int-x3.letsencrypt.org
        CA Issuers - URI:http://cert.int-x3.letsencrypt.org/

X509v3 Subject Alternative Name: 
    DNS:*.xxx.com
...

可以看到证书包含了 SAN 扩展,该扩展的值就是 *.xxx.com

在 Nginx 中 配置 Let’s Encrypt 证书

Nginx 配置文件片断:

server {
    server_name xxx.com;
    listen 443 http2 ssl;
    ssl on;
    ssl_certificate /etc/letsencrypt/live/XXXXXX.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/XXXXXX.com/privkey.pem;

    location / {
      proxy_pass http://127.0.0.1:8080;
    }
}
]]>
304 0 0 0
使用acme.sh 申请 Let's Encrypt 泛域名SSL证书 http://dengtongyu.com/archives/333.html Mon, 23 Jul 2018 10:25:45 +0000 http://dengtongyu.com/?p=333 之前用ertbot方式获取Let's Encrypt泛域名证书,必须手动在添加DNS TXT 记录,也不能自动续签,使用起来颇为不便。

今天发现了github上的一个开源工具acme.sh,是一个开源的Let’s Encrypt SSL申请工具,操作和流程比官方的申请方式简化很多,使用起来非常方便,推荐大家使用。欢迎大家给该工具打星。

安装acme.sh

curl https://get.acme.sh | sh

执行完代码后,acme.sh会被自动安装到~/.acme.sh/中

设置DNS API

目前泛域名证书仅支持DNS验证,acme.sh通过DNS提供商的API自动完成操作,因此需要先设置DNS API,以阿里云为例。

先前往阿里云后台获取App_Key跟App_Secret,在【用户信息管理】-【安全信息管理】创建SecretKey 传送门,然后执行以下脚本

# 替换成从阿里云后台获取的密钥
export Ali_Key="LTA*********uV6"
export Ali_Secret="QKmsZgo*************8Htr6"

这个临时环境变量只需配置这一次,当成功申请证书后,API 信息会被自动保存在~/.acme.sh/account.conf,下次你使用acme.sh的时候会被自动使用

获取证书

# 换成自己的域名
acme.sh --issue --dns dns_ali -d dengtongyu.com -d *.dengtongyu.com

如果acme.sh,提示命令没找到,那就请再执行以下指令:

source ~/.bashrc
acme.sh --issue --dns dns_ali -d dengtongyu.com -d *.dengtongyu.com

或者先cd到acme.sh目录下,再执行文件

cd ~/.acme.sh
./acme.sh --issue --dns dns_ali -d dengtongyu.com -d *.dengtongyu.com

--dns dns_ali参数表示使用 阿里云 的 API,如果是其他解析商,请点这里查看对应的参数

执行完代码后,会有120秒等待DNS生效,所以至少需要等待两分钟,等倒数结束后看到Cert success就是成功了

使用acme.sh 申请 Let's Encrypt 泛域名SSL证书

拷贝证书

前面证书生成以后, 接下来需要把证书 copy 到真正需要用它的地方.

注意, 默认生成的证书都放在安装目录下: ~/.acme.sh/, 请不要直接使用此目录下的文件, 例如: 不要直接让 nginx/apache 的配置文件使用这下面的文件. 这里面的文件都是内部使用, 而且目录结构可能会变化.

正确的使用方法是使用 --installcert 命令,并指定目标位置, 然后证书文件会被copy到相应的位置:

acme.sh  --installcert  -d  dengtongyu.com   \
        --key-file   /etc/nginx/ssl/dengtongyu.key \
        --fullchain-file /etc/nginx/ssl/fullchain.cer \
        --reloadcmd  "service nginx force-reload"

(一个小提醒, 这里用的是 service nginx force-reload, 不是 service nginx reload, 据测试, reload 并不会重新加载证书, 所以用的 force-reload)

在 Nginx 中 配置 Let’s Encrypt 证书

Nginx 配置文件片断:

server {
    server_name xxx.com;
    listen 443 http2 ssl;
    ssl on;
    ssl_certificate /etc/nginx/ssl/fullchain.cer;
    ssl_certificate_key /etc/nginx/ssl/dengtongyu.key;

    location / {
      proxy_pass http://127.0.0.1:8080;
    }
}

证书续期

Let's Encrypt 证书的有效期为三个月,acme.sh会每隔60天自动帮你续期,你无需任何操作

最后,更详细等内容请看官方说明

]]>
333 0 0 0
演唱会随机选座解题思路 http://dengtongyu.com/archives/346.html Sun, 16 Dec 2018 06:07:46 +0000 http://dengtongyu.com/?p=346 最近遇到一个演唱会随机选座的问题,这个问题细想起来确实有趣,正好周末有空,所以我想花点时间分享一下我的解题思路。

演唱会会场分A、B、C、D四个区域,每个区域第一排50个座位,向后每排递增2个座位,最后一排100个座位。一个人可以买1~5张票,系统要随机分配座位,但必须连号,问要怎么分配?

情景图

因为买票的张数不确定性,如果直接随机分配,则有可能出现很多单个位置空出的情况,降低了座位的有效利用率。如果直接顺序出票,那就出现人群扎堆的情况。所以我们要在均衡分布与高利用率之间取一个平衡点。

首先定义座位信息
let item = {
   index: 0,       //下标(索引)
   group: 0,       //分组
   groupName: 'A', //分组名称
   number: 3,      //座位编号
   row: 9,         //第几排
   disable:false   //该座位是否可选
};
把座位和排数用数组保存起来
let front = 2;  //前排座位数
let back = 10;  //后排座位数
let .gap = 2;  //每行座位数差
let group = 4;  //分组数
let lines = (this.back - this.front) / this.gap;  //每个分组有多少排

let index = 0;   //下标(索引)
for (let g = 0; g < this.group; g++) {
    for (let line = this.lines; line >= 0; line--) {
            let rowArray = [];
            for (let seat = 0; seat < (this.back - this.gap * (this.lines - line)); seat++) {
               let item = {
                  index:index++,
                  group: g,
                  groupName: this.groupName(g), //分组名称
                  number: seat,
                  row: line,
                  disable:false
               };
               rowArray.push(item);
               seats.push(item);
               //console.log(item)
            }
            rows.push(rowArray);
    };
}
把符合条件的座位排数筛选出来(即有足够连号的空位的排数)
suitableRows(length) {//length为买票的张数
      let  haveSeatRows = [];
      this.rows.forEach((list) => {
         //可选的座位数组
         let haveSeatList = list.filter((item) => {
            return !item.disable;
         });
         if(haveSeatList.length <= 0) return false;
         
         //有N张连号的排数
         if(this.selectPlace(haveSeatList,length).length > 0) {
            haveSeatRows.push(haveSeatList);
         }
      });
      if(haveSeatRows.length > 0) {
         return haveSeatRows;
      }else{
         return false;
      }
   }
最后把从筛选出来的排数中选出座位
let index =  Math.floor(Math.random() * haveSeats.length);
let places = this.selectPlace(haveSeats[index], length);
   selectPlace(list, length) {
      let places = [];

      for(let i = 0;i < list.length - 1;i++) {
         let end = i + length;
         if(end > list.length) break;

         let selects = list.slice(i, end);
         let flag = false;
         selects.forEach((val, k) => {
            if(k + 1 <= selects.length - 1) {
               if(val.number + 1 == selects[k + 1].number) {
                  flag = true;
               }else{
                  flag = false;
               }
            }
         });

         if(flag) {
            places = selects;
            break;
         }
      }
      return places;
   }

总结起来,基本思路就是把符合条件的行数收集起来,再从所有行数中随机选出一行,顺序出票,从而在均衡分布与高利用率之间取一个平衡点。

demon实例,点击查看!

]]> 346 0 0 0 你也可以成为鉴黄师,nsfwjs鉴黄库初探 http://dengtongyu.com/archives/361.html Sat, 20 Jun 2020 04:11:46 +0000 http://dengtongyu.com/?p=361 首先,NSFW JS 给一张图片鉴定的结果可能会得到如下 5 个分类结果。
  1. 绘画(Drawing)——无害的艺术,或艺术绘画;
  2. 变态(Hentai)——色情艺术,不适合大多数工作环境;
  3. 中立(Neutral)——一般,无害的内容;
  4. 色情(Porn)——不雅的内容和行为,通常涉及生殖器;
  5. 性感(Sexy)——不合时宜的挑衅内容。
最终结果输出一个数组,每个分类都会输出一个概率,按概率从高到低排,所有分类的概率总和是1
[
    {
        "className": "Sexy",
        "probability": 0.35769057273864746
    },
    {
        "className": "Neutral",
        "probability": 0.3514401912689209
    },
    {
        "className": "Porn",
        "probability": 0.2888406813144684
    },
    {
        "className": "Hentai",
        "probability": 0.0012577027082443237
    },
    {
        "className": "Drawing",
        "probability": 0.0007708172197453678
    }
]

安装

NSFW JS是由TensorFlow.js作为对等依赖项提供支持。 所以我们要先安装TensorFlow.js。
yarn add @tensorflow/tfjs
yarn add nsfwjs
// or
npm i @tensorflow/tfjs
npm i nsfwjs

加载模型

然后我们需要加载模型。这个“模型”是用来评估图像的函数。可以在nsfw_model下载它们。这些文件是 4MB 大小的分片,便于在客户端进行缓存。因为我在vue项目中使用,所以把它们放在 /public/model/ 文件夹中。 QQ截图20200620114436

使用

// 导入模块
import * as nsfwjs from "nsfwjs";
// 图片dom节点
const img = document.getElementById('img')
// 载入模型
nsfwjs.load().then(model => {
   // 鉴定图片
   model.classify(img).then(predictions => {
      console.log("Predictions: ", predictions);
   });
});

在demo中测试的结果很惊喜,特意选取了一些干扰性的图片,也能正确识别 微信图片_20200620120800
微信图片_20200620120806
微信图片_20200620120811 最后,这里附上我写的demo,传送门 ]]>
361 0 0 0