
热力图如何在前端实现
关于热力图的实现原理:
一般可大致归纳为以下几个步骤:
1.为每个数据点设置一个从中心向外灰度渐变的圆;
2.利用灰度可以叠加的原理,计算每个像素点数据交叉叠加得到的灰度值;
3.根据每个像素计算得到的灰度值,在一条彩色色带中进行颜色映射,最后对图像进行着色,得到热力图。
当热力图基于前端技术的具体实现时,又可分为以下四个步骤,接下来为大家详细解析:
1.准备热力图数据格式
由于热力图使用场景一般为地图,所以,数据源需要提供经纬度作为位置信息,以及count作为数据点的权重值。
2.在地图上填充数据
基于canvas绘制热力图时,热力图中每个数据点的半径大小会直接影响到热力图的展现效果,所以一般要结合使用地图的缩放级别以及数据精度来进行设置。
3.叠加显示,权重(密度)算法
上面的绘制结果中,因为没有使用到权重值,所以每个数据点圆的中心点灰度值都是1,不能直接用于颜色映射,需要根据离散点缓冲区的叠加来确定热力分布密度。每一个热点都有一个位置和权重,权重越大,则该点越显著,也就代表其渐变的一个衰变因素,此时,我们需要根据不同的count设置出不同的alpha值。本文主要根据count最小值对应alpha0,最大值对应1的映射计算方式,求得每个数据点,从而绘制出alpha:
4.颜色映射
根据画布上每个像素点累计得到的灰度值,可以从彩色映射色带中得到对应位置的颜色。
那么如何得到画布上每个像素点的信息呢?可以使用canvas提供的getImageData()方法,返回 ImageData 对象,该对象拷贝了画布指定矩形的像素数据。需要注意的是,ImageData对象中的每个像素,都包含RGBA四项信息:
关于热力图的实现原理:
一般可大致归纳为以下几个步骤:
1.为每个数据点设置一个从中心向外灰度渐变的圆;
2.利用灰度可以叠加的原理,计算每个像素点数据交叉叠加得到的灰度值;
3.根据每个像素计算得到的灰度值,在一条彩色色带中进行颜色映射,最后对图像进行着色,得到热力图。
当热力图基于前端技术的具体实现时,又可分为以下四个步骤,接下来为大家详细解析:
1.准备热力图数据格式
由于热力图使用场景一般为地图,所以,数据源需要提供经纬度作为位置信息,以及count作为数据点的权重值。
2.在地图上填充数据
基于canvas绘制热力图时,热力图中每个数据点的半径大小会直接影响到热力图的展现效果,所以一般要结合使用地图的缩放级别以及数据精度来进行设置。
3.叠加显示,权重(密度)算法
上面的绘制结果中,因为没有使用到权重值,所以每个数据点圆的中心点灰度值都是1,不能直接用于颜色映射,需要根据离散点缓冲区的叠加来确定热力分布密度。每一个热点都有一个位置和权重,权重越大,则该点越显著,也就代表其渐变的一个衰变因素,此时,我们需要根据不同的count设置出不同的alpha值。本文主要根据count最小值对应alpha0,最大值对应1的映射计算方式,求得每个数据点,从而绘制出alpha:
4.颜色映射
根据画布上每个像素点累计得到的灰度值,可以从彩色映射色带中得到对应位置的颜色。
那么如何得到画布上每个像素点的信息呢?可以使用canvas提供的getImageData()方法,返回 ImageData 对象,该对象拷贝了画布指定矩形的像素数据。需要注意的是,ImageData对象中的每个像素,都包含RGBA四项信息:

mui框架做的粉红风格服装包包商城网站模板
mui框架做的粉红风格服装包包商城网站模板
这个风格时尚美观,比较适合卖女性商品
喜欢的朋友可以下载研究研究
下载地址:http://www.sucaihuo.com/templates/4490.html
mui框架做的粉红风格服装包包商城网站模板
这个风格时尚美观,比较适合卖女性商品
喜欢的朋友可以下载研究研究
下载地址:http://www.sucaihuo.com/templates/4490.html

关于JAVA开发HBuillder的微信支付(获取预支付订单后调起微信支付),经验分享
本项目主要是集成微信支付,android APP请求java服务器获取预支付订单后调起微信支付。代码简单,亲测可用!
源码demo下载地址:
微信支付java服务端demo
主要是用于替换HBuillder H5+模板中的plus/payment.html文件中如下代码
var PAYSERVER='http://demo.dcloud.net.cn/payment/?payid=';
本项目主要是集成微信支付,android APP请求java服务器获取预支付订单后调起微信支付。代码简单,亲测可用!
源码demo下载地址:
微信支付java服务端demo
主要是用于替换HBuillder H5+模板中的plus/payment.html文件中如下代码
var PAYSERVER='http://demo.dcloud.net.cn/payment/?payid=';

解决mui下拉刷新使用mui(querySelector).pullRefresh().setStopped(false);禁止和恢复的问题
把你们的mui.min.js的源码部分修改如下
修改前
disablePullupToRefresh: function() {
this._initPullupRefresh(), this.bottomPocket.className = "mui-pull-bottom-pocket " e, window.removeEventListener("dragup", this)
},
enablePullupToRefresh: function() {
this._initPullupRefresh(), this.bottomPocket.classList.remove(e), this.pullCaption.className = g " " h, this.pullCaption.innerHTML = this.options.up.contentdown, b.addEventListener("plusscrollbottom", this), window.addEventListener("dragup", this)
}
修改后
disablePullupToRefresh: function() {
this._initPullupRefresh(), this.topPocket.className = "mui-pull-bottom-pocket " e, window.removeEventListener("dragup", this)
},
enablePullupToRefresh: function() {
this._initPullupRefresh(), this.topPocket.classList.remove(e), this.topCaption.className = g " " h, this.topCaption.innerHTML = this.options.up.contentdown, b.addEventListener("plusscrollbottom", this), window.addEventListener("dragup", this)
}
第一次发帖,有点激动。
把你们的mui.min.js的源码部分修改如下
修改前
disablePullupToRefresh: function() {
this._initPullupRefresh(), this.bottomPocket.className = "mui-pull-bottom-pocket " e, window.removeEventListener("dragup", this)
},
enablePullupToRefresh: function() {
this._initPullupRefresh(), this.bottomPocket.classList.remove(e), this.pullCaption.className = g " " h, this.pullCaption.innerHTML = this.options.up.contentdown, b.addEventListener("plusscrollbottom", this), window.addEventListener("dragup", this)
}
修改后
disablePullupToRefresh: function() {
this._initPullupRefresh(), this.topPocket.className = "mui-pull-bottom-pocket " e, window.removeEventListener("dragup", this)
},
enablePullupToRefresh: function() {
this._initPullupRefresh(), this.topPocket.classList.remove(e), this.topCaption.className = g " " h, this.topCaption.innerHTML = this.options.up.contentdown, b.addEventListener("plusscrollbottom", this), window.addEventListener("dragup", this)
}
第一次发帖,有点激动。
收起阅读 »
关于IOS缓存本地图片读取显示空白的问题解决办法
说一下我的应用场景:
网络加载图片太多,所以考虑使用本地缓存。图片下载到本地后使用本地路径。
用到的接口:
// 检查本地是否已经存储
plus.io.resolveLocalFileSystemURL
// 下载文件
plus.downloader.createDownload
// 下载失败删除文件
plus.io.resolveLocalFileSystemURL
存储地址使用:_downloads/xxx.jpg
得到的结果如楼主一样,安卓可以读取本地文件,iOS返回空白。
在群里问了半天,最后群主说建议使用uni的API
尝试方法:
// 下载文件
uni.downloadFile(OBJECT)
// 保存文件
uni.saveFile(OBJECT)
通过这种方法,确实可以显示图片,但是有一个问题,就是无法自定义文件名,
下载的临时路径,文件名是使用时间戳命名的,存储到本地后也只能是这个文件名,如果我们要监测缓存,就需要去维护一个网络图片与本地图片的map关系,而且缓存删除更新,都需要更新这个map文件,相对复杂。
思考:为什么uni.saveFile返回的路径可以显示,是不是ios的相对路径不一样?
通过打印,发现uni.saveFile存储到路径在_doc/
目录下,尝试把存储路径从_downloads
改为_doc
后,发现,问题解决了!
原来如此。
相关文档 相对路径URL
说一下我的应用场景:
网络加载图片太多,所以考虑使用本地缓存。图片下载到本地后使用本地路径。
用到的接口:
// 检查本地是否已经存储
plus.io.resolveLocalFileSystemURL
// 下载文件
plus.downloader.createDownload
// 下载失败删除文件
plus.io.resolveLocalFileSystemURL
存储地址使用:_downloads/xxx.jpg
得到的结果如楼主一样,安卓可以读取本地文件,iOS返回空白。
在群里问了半天,最后群主说建议使用uni的API
尝试方法:
// 下载文件
uni.downloadFile(OBJECT)
// 保存文件
uni.saveFile(OBJECT)
通过这种方法,确实可以显示图片,但是有一个问题,就是无法自定义文件名,
下载的临时路径,文件名是使用时间戳命名的,存储到本地后也只能是这个文件名,如果我们要监测缓存,就需要去维护一个网络图片与本地图片的map关系,而且缓存删除更新,都需要更新这个map文件,相对复杂。
思考:为什么uni.saveFile返回的路径可以显示,是不是ios的相对路径不一样?
通过打印,发现uni.saveFile存储到路径在_doc/
目录下,尝试把存储路径从_downloads
改为_doc
后,发现,问题解决了!
原来如此。
相关文档 相对路径URL
收起阅读 »
Koa nuxt最佳实践前篇
从demo快速上手
首先我们下载demo
git clone https://github.com/doodooke/doodoo-nuxt-demo.git
进入目录安装依赖和启动
yarn install && npm run dev
访问浏览器http://127.0.0.1:3000
从demo快速上手
首先我们下载demo
git clone https://github.com/doodooke/doodoo-nuxt-demo.git
进入目录安装依赖和启动
yarn install && npm run dev
访问浏览器http://127.0.0.1:3000

tap点击一次出现2次效果的原因
这个原因有几种,网上看了一下基本上都是说应用了2次js文件
但是我都代码应用了一次 还是出现了这个情况
仔细检查了一下发现了这个问题
mui('.mui-content').on('tap', '.ArticleJump', function() {
});
如果代码存在2个mui-conten类 mui-conten包裹了mui-conten 就会出现2次或者多少次点击效果
这个原因有几种,网上看了一下基本上都是说应用了2次js文件
但是我都代码应用了一次 还是出现了这个情况
仔细检查了一下发现了这个问题
mui('.mui-content').on('tap', '.ArticleJump', function() {
});
如果代码存在2个mui-conten类 mui-conten包裹了mui-conten 就会出现2次或者多少次点击效果
收起阅读 »
多多客小程序开源版一步安装教程
一步安装教程
打开 https://gitee.com/doodooke/doodoo,下载zip压缩包
执行命令
wget https://gitee.com/doodooke/doodoo/raw/master/shell/oneStepInstall.sh && chmod 755 ./oneStepInstall.sh && ./oneStepInstall.sh
1、检测环境
2、自动下载
3、安装依赖
4、系统配置
5、自动启动
一步安装教程
打开 https://gitee.com/doodooke/doodoo,下载zip压缩包
执行命令
wget https://gitee.com/doodooke/doodoo/raw/master/shell/oneStepInstall.sh && chmod 755 ./oneStepInstall.sh && ./oneStepInstall.sh
1、检测环境
2、自动下载
3、安装依赖
4、系统配置
5、自动启动
收起阅读 »
多多客小程序开源版8步快速安装教程(图文版)
1、首先我们打开 https://gitee.com/doodooke/doodoo,下载zip压缩包
2、进入下载的代码目录,打开命令行
3、执行命令安装依赖yarn
4、创建数据库,配置数据库连接
5、执行命令启动项目npm run dev
6、打开浏览器访问http://127.0.0.1:3000,点击开源版下载
7、下载提示完成,执行命令npm run dev重启,打开浏览器访问http://127.0.0.1:3000
8、安装完成,配置.env和.env.web既可以配置完成,系统启动。
1、首先我们打开 https://gitee.com/doodooke/doodoo,下载zip压缩包
2、进入下载的代码目录,打开命令行
3、执行命令安装依赖yarn
4、创建数据库,配置数据库连接
5、执行命令启动项目npm run dev
6、打开浏览器访问http://127.0.0.1:3000,点击开源版下载
7、下载提示完成,执行命令npm run dev重启,打开浏览器访问http://127.0.0.1:3000
8、安装完成,配置.env和.env.web既可以配置完成,系统启动。
收起阅读 »
ios离线打包 集成 视频压缩功能
要想实现更多功能 适应更多应用场景 肯定是要选择离线打包的

第一步
1.在HBuilder-Hello目录下新建compressVideo文件夹,在改文件夹下新建文件SendVideoView.h和SendVideoView.m
2.SendVideoView.h代码
#include "PGPlugin.h"
#include "PGMethod.h"
@interface SendVideoView : PGPlugin
- (void)compression:(PGMethod*)commands;
- (CGFloat)fileSize:(NSURL*)path;
-(NSString *)getNowTimeTimestamp;
@end
3.SendVideoView.m代码
#import "SendVideoView.h"
#import <AssetsLibrary/AssetsLibrary.h>
#import <AVFoundation/AVFoundation.h>
@implementation SendVideoView
-(NSString *)getNowTimeTimestamp{
NSDateFormatter *formatter = [[NSDateFormatter alloc] init] ;
[formatter setDateStyle:NSDateFormatterMediumStyle];
[formatter setTimeStyle:NSDateFormatterShortStyle];
[formatter setDateFormat:@"YYYY-MM-dd HH:mm:ss"]; // ------ ----设置你想要的格式,hh与HH的区别:分别表示12小时制,24小时制
//设置时区,这个对于时间的处理有时很重要
NSTimeZone* timeZone = [NSTimeZone timeZoneWithName:@"Asia/Shanghai"];
[formatter setTimeZone:timeZone];
NSDate *datenow = [NSDate date];//现在时间,你可以输出来看下是什么格式
NSString *timeSp = [NSString stringWithFormat:@"%ld", (long)[datenow timeIntervalSince1970]];
return timeSp;
}
//计算压缩大小
- (CGFloat)fileSize:(NSURL*)path
{
return [[NSData dataWithContentsOfURL:path] length]/1024.00 /1024.00;
}
//压缩
- (void)compression:(PGMethod*)commands
{
NSString* parameter0 = [commands.arguments objectAtIndex:0];
NSLog(@"parameter=%@",parameter0);
NSString* callFunc = [commands.arguments objectAtIndex:1];
NSURL * url = [NSURL URLWithString:parameter0];
NSLog(@"第一个参数=%@",parameter0);
NSLog(@"压缩前大小 %f MB",[self fileSize:url]);
// 创建AVAsset对象
AVAsset* asset = [AVAsset assetWithURL:url];
/* 创建AVAssetExportSession对象
压缩的质量
AVAssetExportPresetLowQuality 最low的画质最好不要选择实在是看不清楚
AVAssetExportPresetMediumQuality 使用到压缩的话都说用这个
AVAssetExportPresetHighestQuality 最清晰的画质
*/
AVAssetExportSession * session = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetMediumQuality];
//优化网络
session.shouldOptimizeForNetworkUse = YES;
//转换后的格式
//拼接输出文件路径 为了防止同名 可以根据日期拼接名字 或者对名字进行MD5加密
NSString* path = [NSTemporaryDirectory() stringByAppendingPathComponent:[[self getNowTimeTimestamp] stringByAppendingString: @".mp4"]];
//判断文件是否存在,如果已经存在删除
[[NSFileManager defaultManager]removeItemAtPath:path error:nil];
//设置输出路径
session.outputURL = [NSURL fileURLWithPath:path];
//设置输出类型 这里可以更改输出的类型 具体可以看文档描述
session.outputFileType = AVFileTypeMPEG4;
[session exportAsynchronouslyWithCompletionHandler:^{
NSLog(@"%@",[NSThread currentThread]);
//压缩完成
if (session.status==AVAssetExportSessionStatusCompleted) {
//在主线程中刷新UI界面,弹出控制器通知用户压缩完成
dispatch_async(dispatch_get_main_queue(), ^{
NSString* pResultString = [@"file://" stringByAppendingPathComponent:path];
NSLog(@"path=%@",path);
PDRPluginResult *result = [PDRPluginResult resultWithStatus:PDRCommandStatusOK messageAsString:pResultString];
[self toCallback:callFunc withReslut:[result toJSONString]];
NSFileManager* fileManager=[NSFileManager defaultManager];
// 删除沙盒中的视频
BOOL blHave=[[NSFileManager defaultManager] fileExistsAtPath:[parameter0 substringFromIndex:7]];
if(blHave){
BOOL blDele= [fileManager removeItemAtPath:[parameter0 substringFromIndex:7] error:nil];
}
// 以下调试时开起
// NSLog(@"导出完成");
// NSLog(@"压缩完毕,压缩后大小 %f MB",[self fileSize:session.outputURL]);
});
}
}];
}
@end
第二步
1.打开PandoraApi.bundle下的feature.plist文件
- feature.plist文件里加入
<key>compressVideo</key>
<dict>
<key>class</key>
<string>SendVideoView</string>
<key>global</key>
<true/>
<key>autostart</key>
<string>YES</string>
</dict>
第三步
在html 页面 用JS通过 Native.js,调用原生类
var _BARCODE = 'compressVideo'
var B = window.plus.bridge
var compressVideo = {
compression: function (path, successCallback) {
var success = typeof successCallback !== 'function' ? null : function (args) {
successCallback(args)
},
callbackID = B.callbackId(success, null)
return B.exec(_BARCODE, 'compression', [path, callbackID])
}
}
window.plus.compressVideo = compressVideo
就这么多了,不懂的可以加群864017187(dcloud混合开发交流群)
安卓版的视频压缩,改天有空了再写出来
要想实现更多功能 适应更多应用场景 肯定是要选择离线打包的
第一步
1.在HBuilder-Hello目录下新建compressVideo文件夹,在改文件夹下新建文件SendVideoView.h和SendVideoView.m
2.SendVideoView.h代码
#include "PGPlugin.h"
#include "PGMethod.h"
@interface SendVideoView : PGPlugin
- (void)compression:(PGMethod*)commands;
- (CGFloat)fileSize:(NSURL*)path;
-(NSString *)getNowTimeTimestamp;
@end
3.SendVideoView.m代码
#import "SendVideoView.h"
#import <AssetsLibrary/AssetsLibrary.h>
#import <AVFoundation/AVFoundation.h>
@implementation SendVideoView
-(NSString *)getNowTimeTimestamp{
NSDateFormatter *formatter = [[NSDateFormatter alloc] init] ;
[formatter setDateStyle:NSDateFormatterMediumStyle];
[formatter setTimeStyle:NSDateFormatterShortStyle];
[formatter setDateFormat:@"YYYY-MM-dd HH:mm:ss"]; // ------ ----设置你想要的格式,hh与HH的区别:分别表示12小时制,24小时制
//设置时区,这个对于时间的处理有时很重要
NSTimeZone* timeZone = [NSTimeZone timeZoneWithName:@"Asia/Shanghai"];
[formatter setTimeZone:timeZone];
NSDate *datenow = [NSDate date];//现在时间,你可以输出来看下是什么格式
NSString *timeSp = [NSString stringWithFormat:@"%ld", (long)[datenow timeIntervalSince1970]];
return timeSp;
}
//计算压缩大小
- (CGFloat)fileSize:(NSURL*)path
{
return [[NSData dataWithContentsOfURL:path] length]/1024.00 /1024.00;
}
//压缩
- (void)compression:(PGMethod*)commands
{
NSString* parameter0 = [commands.arguments objectAtIndex:0];
NSLog(@"parameter=%@",parameter0);
NSString* callFunc = [commands.arguments objectAtIndex:1];
NSURL * url = [NSURL URLWithString:parameter0];
NSLog(@"第一个参数=%@",parameter0);
NSLog(@"压缩前大小 %f MB",[self fileSize:url]);
// 创建AVAsset对象
AVAsset* asset = [AVAsset assetWithURL:url];
/* 创建AVAssetExportSession对象
压缩的质量
AVAssetExportPresetLowQuality 最low的画质最好不要选择实在是看不清楚
AVAssetExportPresetMediumQuality 使用到压缩的话都说用这个
AVAssetExportPresetHighestQuality 最清晰的画质
*/
AVAssetExportSession * session = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetMediumQuality];
//优化网络
session.shouldOptimizeForNetworkUse = YES;
//转换后的格式
//拼接输出文件路径 为了防止同名 可以根据日期拼接名字 或者对名字进行MD5加密
NSString* path = [NSTemporaryDirectory() stringByAppendingPathComponent:[[self getNowTimeTimestamp] stringByAppendingString: @".mp4"]];
//判断文件是否存在,如果已经存在删除
[[NSFileManager defaultManager]removeItemAtPath:path error:nil];
//设置输出路径
session.outputURL = [NSURL fileURLWithPath:path];
//设置输出类型 这里可以更改输出的类型 具体可以看文档描述
session.outputFileType = AVFileTypeMPEG4;
[session exportAsynchronouslyWithCompletionHandler:^{
NSLog(@"%@",[NSThread currentThread]);
//压缩完成
if (session.status==AVAssetExportSessionStatusCompleted) {
//在主线程中刷新UI界面,弹出控制器通知用户压缩完成
dispatch_async(dispatch_get_main_queue(), ^{
NSString* pResultString = [@"file://" stringByAppendingPathComponent:path];
NSLog(@"path=%@",path);
PDRPluginResult *result = [PDRPluginResult resultWithStatus:PDRCommandStatusOK messageAsString:pResultString];
[self toCallback:callFunc withReslut:[result toJSONString]];
NSFileManager* fileManager=[NSFileManager defaultManager];
// 删除沙盒中的视频
BOOL blHave=[[NSFileManager defaultManager] fileExistsAtPath:[parameter0 substringFromIndex:7]];
if(blHave){
BOOL blDele= [fileManager removeItemAtPath:[parameter0 substringFromIndex:7] error:nil];
}
// 以下调试时开起
// NSLog(@"导出完成");
// NSLog(@"压缩完毕,压缩后大小 %f MB",[self fileSize:session.outputURL]);
});
}
}];
}
@end
第二步
1.打开PandoraApi.bundle下的feature.plist文件
- feature.plist文件里加入
<key>compressVideo</key>
<dict>
<key>class</key>
<string>SendVideoView</string>
<key>global</key>
<true/>
<key>autostart</key>
<string>YES</string>
</dict>
第三步
在html 页面 用JS通过 Native.js,调用原生类
var _BARCODE = 'compressVideo'
var B = window.plus.bridge
var compressVideo = {
compression: function (path, successCallback) {
var success = typeof successCallback !== 'function' ? null : function (args) {
successCallback(args)
},
callbackID = B.callbackId(success, null)
return B.exec(_BARCODE, 'compression', [path, callbackID])
}
}
window.plus.compressVideo = compressVideo
就这么多了,不懂的可以加群864017187(dcloud混合开发交流群)
安卓版的视频压缩,改天有空了再写出来

IOS离线打包集成 阿里云 短视频sdk
要想实现更多功能 适应更多应用场景 肯定是要选择离线打包的
1.基础版: 只有录制和裁剪功能,
- 标准版:可以修改UI
- 专业版: 很复杂的功能
可以参考,阿里云SDK说明
如何没有离线打包过的,可以参考,官方最新的AS 打包教程:
ios离线打包教程
第一步
先下载ios短视频基础版SDK,详见sdk下载页面
1.开发者打开工程,选中目标target,依次选择”General”->”Embededed Binaries”,点击”+”号,点击“Add Other…”,导入QUCore-ThirdParty.framework和AliyunVideoSDK.framework。
2.同时,还需依赖libz.tbd、libc++.tbd、libiconv.tbd、libresolv.tbd、ImageIO.framework、CoreMedia.framework、CoreVideo.framework、SystemConfiguration.framework、Photos.framework、OpenAL.framework、VideoToolbox.framework请一并加上。截图如下
3.配置 Build Setting -- Build Options -- Enable Bitcode 选项为NO
4.配置 Build Setting -- Linking -- Other Linker Flags 添加 -ObjC选项
第二步
1.在HBuilder-Hello下新建文件夹recoredVideo 并在该文件夹下新建RecordVideo.h和RecordVideo.m文件
2.RecordVideo.h代码
include "PGPlugin.h"
include "PGMethod.h"
import <AliyunVideoSDK/AliyunVideoBase.h>
@interface RecordVideo : PGPlugin
- (void)record:(PGMethod*)commands;
- (void)videoBase:(AliyunVideoBase )base recordCompeleteWithRecordViewController:(UIViewController )recordVC videoPath:(NSString )videoPath;
-(NSString )getNowTimeTimestamp;
@end
3.RecordVideo.m代码
import "RecordVideo.h"
import <AliyunVideoSDK/AliyunVideoSDK.h>
import <AliyunVideoSDK/AliyunVideoRecordParam.h>
import <AliyunVideoSDK/AliyunVideoUIConfig.h>
import <AliyunVideoSDK/AliyunVideoBase.h>
import <AliyunVideoSDK/AliyunVideoCropParam.h>
import <AssetsLibrary/AssetsLibrary.h>
@interface RecordVideo()
@property (nonatomic,strong) NSString *callFunc;
@end
@implementation RecordVideo
-
(void)record:(PGMethod)commands
{
AliyunVideoUIConfig config = [[AliyunVideoUIConfig alloc] init];
config.hiddenFlashButton = NO;
config.imageBundleName = @"QPSDK";
config.hiddenImportButton = YES;
[[AliyunVideoBase shared] registerWithAliyunIConfig:config];NSString parameter0 = [commands.arguments objectAtIndex:0];
self.callFunc = [commands.arguments objectAtIndex:1];
NSData data= [parameter0 dataUsingEncoding:NSUTF8StringEncoding];
NSError error = nil;
id jsonObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];
NSDictionary dict = (NSDictionary )jsonObject;
AliyunVideoRecordParam quVideo = [[AliyunVideoRecordParam alloc] init];
quVideo.maxDuration = [[dict objectForKey:@"setMaxDuration"] doubleValue];
quVideo.minDuration = [[dict objectForKey:@"setMinDuration"] doubleValue];
quVideo.videoQuality = AliyunVideoQualityHight;
quVideo.torchMode = AliyunCameraTorchModeOff;
quVideo.size = AliyunVideoVideoSize540P;
quVideo.gop = [[dict objectForKey:@"setGop"] intValue];
quVideo.beautifyStatus = [[dict objectForKey:@"setBeautyStatus"] boolValue];
quVideo.beautifyValue = [[dict objectForKey:@"setBeautyLevel"] intValue];
quVideo.position = AliyunCameraPositionBack;
NSString path = [NSTemporaryDirectory() stringByAppendingPathComponent:[[self getNowTimeTimestamp] stringByAppendingString: @".mp4"]];
quVideo.outputPath = path;
UIViewController recordViewController = [[AliyunVideoBase shared] createRecordViewControllerWithRecordParam:quVideo];
[AliyunVideoBase shared].delegate = (id)self;
[self.rootViewController.navigationController pushViewController:recordViewController animated:YES];
[[UIApplication sharedApplication] setStatusBarHidden:YES];
} -
(void)videoBase:(AliyunVideoBase )base recordCompeleteWithRecordViewController:(UIViewController )recordVC videoPath:(NSString )videoPath {
NSLog(@"录制完成 %@", videoPath);
ALAssetsLibrary library = [[ALAssetsLibrary alloc] init];
[library writeVideoAtPathToSavedPhotosAlbum:[NSURL fileURLWithPath:videoPath]
completionBlock:^(NSURL assetURL, NSError error) {
NSString path = [@"file://" stringByAppendingPathComponent:videoPath];
NSDictionary dict = [NSDictionary dictionaryWithObjectsAndKeys:@"000000",@"code",path,@"path",nil];
PDRPluginResult *result = [PDRPluginResult resultWithStatus:PDRCommandStatusOK messageAsDictionary:dict];
[self toCallback:self.callFunc withReslut:[result toJSONString]];
dispatch_async(dispatch_get_main_queue(), ^{
[recordVC.navigationController popViewControllerAnimated:YES];
});
}];
}
-(void)videoBaseRecordVideoExit {
NSLog(@"退出录制");
[self.rootViewController.navigationController popViewControllerAnimated:YES];
}
-(NSString *)getNowTimeTimestamp{
NSDateFormatter *formatter = [[NSDateFormatter alloc] init] ;
[formatter setDateStyle:NSDateFormatterMediumStyle];
[formatter setTimeStyle:NSDateFormatterShortStyle];
[formatter setDateFormat:@"YYYY-MM-dd HH:mm:ss"]; // ------ ----设置你想要的格式,hh与HH的区别:分别表示12小时制,24小时制
//设置时区,这个对于时间的处理有时很重要
NSTimeZone* timeZone = [NSTimeZone timeZoneWithName:@"Asia/Shanghai"];
[formatter setTimeZone:timeZone];
NSDate *datenow = [NSDate date];//现在时间,你可以输出来看下是什么格式
NSString *timeSp = [NSString stringWithFormat:@"%ld", (long)[datenow timeIntervalSince1970]];
return timeSp;
}
@end
第三步
1.打开PandoraApi.bundle下的feature.plist文件
2.feature.plist文件里加入
<key>RecordVideo</key>
<dict>
<key>class</key>
<string>RecordVideo</string>
<key>global</key>
<true/>
<key>autostart</key>
<string>YES</string>
</dict>
然后在html 页面 用JS通过 Native.js,调用原生类
var RecordVideoIos = function (options) {
this.options = this.extend(
{
setResolutionMode: '540p', // 录制 设置录制分辨率,目前支持360p,480p,540p,720p
setRatioMode: '1/1', // 录制 设置视频比例,目前支持1/1 ,3/4, 9/16
setRecordMode: 'AUTO', // 录制 设置录制模式,目前支持按录:PRESS,点录:TOUCH和混合模式:AUTO
setBeautyLevel: 80, // 录制 设置美颜度,1-100,比率
setBeautyStatus: true, // 录制 设置美颜开关
setCameraType: 'BACK', // 录制 设置前后置摄像头, 后:BACK ,前:FRONT
setFlashType: 'NO', // 录制 设置闪光灯模式,开:NO, 关:OFF, 自动:AUTO
setNeedClip: true, // 录制 设置是否需要支持片段录制
setMaxDuration: 15, // 录制 设置最大录制时长 单位秒
setMinDuration: 2, // 录制 设置最小录制时长 单位秒
setVideoQuality: 'HD', // 录制设置视频质量 4个级别, 低:LD ,中:SD ,高:HD ,极高:SSD
setGop: 125, // 设置关键帧间隔,建议:1-300之间
setMinVideoDuration: 5, // 裁剪 设置过滤的视频最小长度 单位秒
setMaxVideoDuration: 15, // 裁剪 设置过滤的视频最大长度 单位秒
setMinCropDuration: 2, // 裁剪 设置视频最小裁剪时间 单位毫秒
setFrameRate: 25, // 裁剪 设置帧率
setNeedRecord: false, // 设置是否需要开放录制入口,即选择视频的页面,多出一个录制按钮
setResulutionMode: '540p', // 设置裁剪分辨率,目前支持360p,480p,540p,720p
setCropMode: 'cpu' // 设置裁剪方式,是否使用gpu进行裁剪,不设置则默认使用cpu来裁剪
}, options)
this.init()
}
RecordVideoIos.prototype = {
init: function () {
this.event()
},
event: function () {
},
extend: function (obj, obj2) {
for (var k in obj2) {
obj[k] = obj2[k]
}
return obj
},
open: function (fn) {
let B = window.plus.bridge
let success = typeof fn !== 'function' ? null : function (args) {
fn(args)
}
let callbackID = B.callbackId(success, null)
return B.exec('RecordVideo', 'record', [JSON.stringify(this.options), callbackID])
}
}
const option = {
setResolutionMode: '720p', // 录制 设置录制分辨率,目前支持360p,480p,540p,720p
setRatioMode: '1/1', // 录制 设置视频比例,目前支持1/1 ,3/4, 9/16
setRecordMode: 'AUTO', // 录制 设置录制模式,目前支持按录:PRESS,点录:TOUCH和混合模式:AUTO
setBeautyLevel: 60, // 录制 设置美颜度,1-100,比率
setBeautyStatus: true, // 录制 设置美颜开关
setCameraType: 'BACK', // 录制 设置前后置摄像头, 后:BACK ,前:FRONT
setFlashType: 'OFF', // 录制 设置闪光灯模式,开:NO, 关:OFF, 自动:AUTO
setNeedClip: true, // 录制 设置是否需要支持片段录制
setMaxDuration: 15, // 录制 设置最大录制时长 单位秒
setMinDuration: 2, // 录制 设置最小录制时长 单位秒
setVideoQuality: 'HD', // 录制设置视频质量 4个级别, 低:LD ,中:SD ,高:HD ,极高:SSD
setGop: 125, // 设置关键帧间隔,建议:1-300之间
setMinVideoDuration: 5, // 裁剪 设置过滤的视频最小长度 单位秒
setMaxVideoDuration: 15, // 裁剪 设置过滤的视频最大长度 单位秒
setMinCropDuration: 2, // 裁剪 设置视频最小裁剪时间 单位毫秒
setFrameRate: 25, // 裁剪 设置帧率
setNeedRecord: false, // 设置是否需要开放录制入口,即选择视频的页面,多出一个录制按钮
setResulutionMode: '540p', // 设置裁剪分辨率,目前支持360p,480p,540p,720p
setCropMode: 'cpu' // 设置裁剪方式,是否使用gpu进行裁剪,不设置则默认使用cpu来裁剪
}
var recordVideoIos = new RecordVideoIos(option)
if (plus.os.name != 'Android') {
window.plus.recordVideo = recordVideoIos
}
就这么多了,不懂的可以加群864017187(dcloud混合开发交流群)
要想实现更多功能 适应更多应用场景 肯定是要选择离线打包的
1.基础版: 只有录制和裁剪功能,
- 标准版:可以修改UI
- 专业版: 很复杂的功能
可以参考,阿里云SDK说明
如何没有离线打包过的,可以参考,官方最新的AS 打包教程:
ios离线打包教程
第一步
先下载ios短视频基础版SDK,详见sdk下载页面
1.开发者打开工程,选中目标target,依次选择”General”->”Embededed Binaries”,点击”+”号,点击“Add Other…”,导入QUCore-ThirdParty.framework和AliyunVideoSDK.framework。
2.同时,还需依赖libz.tbd、libc++.tbd、libiconv.tbd、libresolv.tbd、ImageIO.framework、CoreMedia.framework、CoreVideo.framework、SystemConfiguration.framework、Photos.framework、OpenAL.framework、VideoToolbox.framework请一并加上。截图如下
3.配置 Build Setting -- Build Options -- Enable Bitcode 选项为NO
4.配置 Build Setting -- Linking -- Other Linker Flags 添加 -ObjC选项
第二步
1.在HBuilder-Hello下新建文件夹recoredVideo 并在该文件夹下新建RecordVideo.h和RecordVideo.m文件
2.RecordVideo.h代码
include "PGPlugin.h"
include "PGMethod.h"
import <AliyunVideoSDK/AliyunVideoBase.h>
@interface RecordVideo : PGPlugin
- (void)record:(PGMethod*)commands;
- (void)videoBase:(AliyunVideoBase )base recordCompeleteWithRecordViewController:(UIViewController )recordVC videoPath:(NSString )videoPath;
-(NSString )getNowTimeTimestamp;
@end
3.RecordVideo.m代码
import "RecordVideo.h"
import <AliyunVideoSDK/AliyunVideoSDK.h>
import <AliyunVideoSDK/AliyunVideoRecordParam.h>
import <AliyunVideoSDK/AliyunVideoUIConfig.h>
import <AliyunVideoSDK/AliyunVideoBase.h>
import <AliyunVideoSDK/AliyunVideoCropParam.h>
import <AssetsLibrary/AssetsLibrary.h>
@interface RecordVideo()
@property (nonatomic,strong) NSString *callFunc;
@end
@implementation RecordVideo
-
(void)record:(PGMethod)commands
{
AliyunVideoUIConfig config = [[AliyunVideoUIConfig alloc] init];
config.hiddenFlashButton = NO;
config.imageBundleName = @"QPSDK";
config.hiddenImportButton = YES;
[[AliyunVideoBase shared] registerWithAliyunIConfig:config];NSString parameter0 = [commands.arguments objectAtIndex:0];
self.callFunc = [commands.arguments objectAtIndex:1];
NSData data= [parameter0 dataUsingEncoding:NSUTF8StringEncoding];
NSError error = nil;
id jsonObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];
NSDictionary dict = (NSDictionary )jsonObject;
AliyunVideoRecordParam quVideo = [[AliyunVideoRecordParam alloc] init];
quVideo.maxDuration = [[dict objectForKey:@"setMaxDuration"] doubleValue];
quVideo.minDuration = [[dict objectForKey:@"setMinDuration"] doubleValue];
quVideo.videoQuality = AliyunVideoQualityHight;
quVideo.torchMode = AliyunCameraTorchModeOff;
quVideo.size = AliyunVideoVideoSize540P;
quVideo.gop = [[dict objectForKey:@"setGop"] intValue];
quVideo.beautifyStatus = [[dict objectForKey:@"setBeautyStatus"] boolValue];
quVideo.beautifyValue = [[dict objectForKey:@"setBeautyLevel"] intValue];
quVideo.position = AliyunCameraPositionBack;
NSString path = [NSTemporaryDirectory() stringByAppendingPathComponent:[[self getNowTimeTimestamp] stringByAppendingString: @".mp4"]];
quVideo.outputPath = path;
UIViewController recordViewController = [[AliyunVideoBase shared] createRecordViewControllerWithRecordParam:quVideo];
[AliyunVideoBase shared].delegate = (id)self;
[self.rootViewController.navigationController pushViewController:recordViewController animated:YES];
[[UIApplication sharedApplication] setStatusBarHidden:YES];
} -
(void)videoBase:(AliyunVideoBase )base recordCompeleteWithRecordViewController:(UIViewController )recordVC videoPath:(NSString )videoPath {
NSLog(@"录制完成 %@", videoPath);
ALAssetsLibrary library = [[ALAssetsLibrary alloc] init];
[library writeVideoAtPathToSavedPhotosAlbum:[NSURL fileURLWithPath:videoPath]
completionBlock:^(NSURL assetURL, NSError error) {
NSString path = [@"file://" stringByAppendingPathComponent:videoPath];
NSDictionary dict = [NSDictionary dictionaryWithObjectsAndKeys:@"000000",@"code",path,@"path",nil];
PDRPluginResult *result = [PDRPluginResult resultWithStatus:PDRCommandStatusOK messageAsDictionary:dict];
[self toCallback:self.callFunc withReslut:[result toJSONString]];
dispatch_async(dispatch_get_main_queue(), ^{
[recordVC.navigationController popViewControllerAnimated:YES];
});
}];
}
-(void)videoBaseRecordVideoExit {
NSLog(@"退出录制");
[self.rootViewController.navigationController popViewControllerAnimated:YES];
}
-(NSString *)getNowTimeTimestamp{
NSDateFormatter *formatter = [[NSDateFormatter alloc] init] ;
[formatter setDateStyle:NSDateFormatterMediumStyle];
[formatter setTimeStyle:NSDateFormatterShortStyle];
[formatter setDateFormat:@"YYYY-MM-dd HH:mm:ss"]; // ------ ----设置你想要的格式,hh与HH的区别:分别表示12小时制,24小时制
//设置时区,这个对于时间的处理有时很重要
NSTimeZone* timeZone = [NSTimeZone timeZoneWithName:@"Asia/Shanghai"];
[formatter setTimeZone:timeZone];
NSDate *datenow = [NSDate date];//现在时间,你可以输出来看下是什么格式
NSString *timeSp = [NSString stringWithFormat:@"%ld", (long)[datenow timeIntervalSince1970]];
return timeSp;
}
@end
第三步
1.打开PandoraApi.bundle下的feature.plist文件
2.feature.plist文件里加入
<key>RecordVideo</key>
<dict>
<key>class</key>
<string>RecordVideo</string>
<key>global</key>
<true/>
<key>autostart</key>
<string>YES</string>
</dict>
然后在html 页面 用JS通过 Native.js,调用原生类
var RecordVideoIos = function (options) {
this.options = this.extend(
{
setResolutionMode: '540p', // 录制 设置录制分辨率,目前支持360p,480p,540p,720p
setRatioMode: '1/1', // 录制 设置视频比例,目前支持1/1 ,3/4, 9/16
setRecordMode: 'AUTO', // 录制 设置录制模式,目前支持按录:PRESS,点录:TOUCH和混合模式:AUTO
setBeautyLevel: 80, // 录制 设置美颜度,1-100,比率
setBeautyStatus: true, // 录制 设置美颜开关
setCameraType: 'BACK', // 录制 设置前后置摄像头, 后:BACK ,前:FRONT
setFlashType: 'NO', // 录制 设置闪光灯模式,开:NO, 关:OFF, 自动:AUTO
setNeedClip: true, // 录制 设置是否需要支持片段录制
setMaxDuration: 15, // 录制 设置最大录制时长 单位秒
setMinDuration: 2, // 录制 设置最小录制时长 单位秒
setVideoQuality: 'HD', // 录制设置视频质量 4个级别, 低:LD ,中:SD ,高:HD ,极高:SSD
setGop: 125, // 设置关键帧间隔,建议:1-300之间
setMinVideoDuration: 5, // 裁剪 设置过滤的视频最小长度 单位秒
setMaxVideoDuration: 15, // 裁剪 设置过滤的视频最大长度 单位秒
setMinCropDuration: 2, // 裁剪 设置视频最小裁剪时间 单位毫秒
setFrameRate: 25, // 裁剪 设置帧率
setNeedRecord: false, // 设置是否需要开放录制入口,即选择视频的页面,多出一个录制按钮
setResulutionMode: '540p', // 设置裁剪分辨率,目前支持360p,480p,540p,720p
setCropMode: 'cpu' // 设置裁剪方式,是否使用gpu进行裁剪,不设置则默认使用cpu来裁剪
}, options)
this.init()
}
RecordVideoIos.prototype = {
init: function () {
this.event()
},
event: function () {
},
extend: function (obj, obj2) {
for (var k in obj2) {
obj[k] = obj2[k]
}
return obj
},
open: function (fn) {
let B = window.plus.bridge
let success = typeof fn !== 'function' ? null : function (args) {
fn(args)
}
let callbackID = B.callbackId(success, null)
return B.exec('RecordVideo', 'record', [JSON.stringify(this.options), callbackID])
}
}
const option = {
setResolutionMode: '720p', // 录制 设置录制分辨率,目前支持360p,480p,540p,720p
setRatioMode: '1/1', // 录制 设置视频比例,目前支持1/1 ,3/4, 9/16
setRecordMode: 'AUTO', // 录制 设置录制模式,目前支持按录:PRESS,点录:TOUCH和混合模式:AUTO
setBeautyLevel: 60, // 录制 设置美颜度,1-100,比率
setBeautyStatus: true, // 录制 设置美颜开关
setCameraType: 'BACK', // 录制 设置前后置摄像头, 后:BACK ,前:FRONT
setFlashType: 'OFF', // 录制 设置闪光灯模式,开:NO, 关:OFF, 自动:AUTO
setNeedClip: true, // 录制 设置是否需要支持片段录制
setMaxDuration: 15, // 录制 设置最大录制时长 单位秒
setMinDuration: 2, // 录制 设置最小录制时长 单位秒
setVideoQuality: 'HD', // 录制设置视频质量 4个级别, 低:LD ,中:SD ,高:HD ,极高:SSD
setGop: 125, // 设置关键帧间隔,建议:1-300之间
setMinVideoDuration: 5, // 裁剪 设置过滤的视频最小长度 单位秒
setMaxVideoDuration: 15, // 裁剪 设置过滤的视频最大长度 单位秒
setMinCropDuration: 2, // 裁剪 设置视频最小裁剪时间 单位毫秒
setFrameRate: 25, // 裁剪 设置帧率
setNeedRecord: false, // 设置是否需要开放录制入口,即选择视频的页面,多出一个录制按钮
setResulutionMode: '540p', // 设置裁剪分辨率,目前支持360p,480p,540p,720p
setCropMode: 'cpu' // 设置裁剪方式,是否使用gpu进行裁剪,不设置则默认使用cpu来裁剪
}
var recordVideoIos = new RecordVideoIos(option)
if (plus.os.name != 'Android') {
window.plus.recordVideo = recordVideoIos
}
就这么多了,不懂的可以加群864017187(dcloud混合开发交流群)
收起阅读 »