接上一篇:uniapp踩坑(三):调用原生高德地图API,展示路线和marker,以及绘制行政区域边界,并用html2canvas截图分享到微信(一),
已经实现了高德地图的绘制,现在就需对其进行截图并分享了。
截图:采用html2canvas
分享:调用uniapp.share,也可参考我的另一篇文章:uniapp踩坑(二):canvas合成背景图和二维码,并分享给微信好友或微信朋友圈
一、结果展示
截图前手机展示的样式:
截图分享到微信好友后的图片:
二、实现过程(核心代码)
1、重点是引入html2canvas,我这里是引入的cdn,当然,也可以下载到本地引入。
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width">
<title>所有路线展示</title>
<link rel="stylesheet" href="https://a.amap.com/jsapi_demos/static/demo-center/css/demo-center.css" />
<script src="https://cache.amap.com/lbs/static/es5.min.js"></script>
<script type="text/javascript" src="https://js.cdn.aliyun.dcloud.net.cn/dev/uni-app/uni.webview.1.5.2.js"></script>
<!-- 引入html2canvas插件-->
<script src="http://cdn.bootcss.com/html2canvas/0.5.0-beta4/html2canvas.js"></script>
<!-- 引入高德地图-->
<script language="javascript" src="https://webapi.amap.com/maps?v=1.4.15&key=您申请的key值"></script>
<!-- 引入日期插件-->
<script src="https://lib.sinaapp.com/js/jquery/2.0.2/jquery-2.0.2.min.js"></script>
<style>
html,
body,
#container {
width: 100%;
height: 100%;
}
.share_img{
width: 40px;
height: 40px;
right: 35px;
border-radius: 50%;
position: fixed;
top: 35px;
z-index: 1000;
}
</style>
</head>
2、html中截图代码
(1) 地图代码和分享按钮
<div id="container" ></div>
<div class="shareImage" id="shareImage" onclick="shareScreen()">
<img src="./img/share1.png" class="share_img" alt="分享"/>
</div>
(2) 点击分享按钮,进行截图
注意,截取网页后的图片暂放在 img 参数中,然后通过uni.postMessage传给vue页面,代码已给出。
这里使用到web-view 的页面和vue应用内的页面交互。参考:在 web-view 加载的 HTML 中调用 uni 的 API
// /*################ 用户分享截图 ###############*/
function shareScreen(){
document.getElementById("shareImage").style.display="none";//显示
// 接下来对显示的内容进行截图
setTimeout(() =>{
// 获取县区行政区图层的transform属性样式
var transform=$2(".amap-container>div:first>div:first>div:first>canvas:last").css("transform");
var transformOrigin=$2(".amap-container>div:first>div:first>div:first>canvas:last").css("transformOrigin");
let transformWidth = $2(".amap-container>div:first>div:first>div:first>canvas:last").css("width")
let transformHeight = $2(".amap-container>div:first>div:first>div:first>canvas:last").css("height")
var comp=transform.split(","); //split up the transform matrix
var maptop=parseFloat(comp[3]); //get top value
var width = transformWidth.replace("px","")*maptop +'px'
var height = transformHeight.replace("px","")*maptop +'px'
$2(".amap-container>div:first>div:first>div:first>canvas:last").css({
//get the map container. not sure if stable
'position': 'absolute',
'z-index': '110',
'transform-origin': transformOrigin,
'transform': 'none',
'top': '0px',
'left': '0px',
'display': 'block',
'width': width,
'height': height,
})
let opt = {
width: transformWidth, //dom 原始宽度
height: transformHeight, //dom 原始高度
useCORS: true ,// 【重要】开启跨域配置
foreignObjectRendering : true,
allowTaint :false
}
html2canvas(document.body,opt).then(function (canvas) {
// img是截取浏览器后生成的图片
let img = canvas.toDataURL("image/png");
let base=encodeURIComponent(img);//转码
$2(".amap-container>div:first>div:first>div:first>canvas:last").css({
//get the map container. not sure if stable
'position': 'absolute',
'z-index': '110',
'transform-origin': transformOrigin,
'transform': 'none',
'top': '0px',
'left': '0px',
'display': 'block',
'width': width,
'height': height,
})
let postMessage = {
"img":img
}
//向uniapp传值
uni.postMessage({
data: {
img:img
}
});
document.getElementById("shareImage").style.display="block";//显示
}).catch(function (e) {
console.error('error', e);
});
},100)
}
3.vue页面获取到img后,调用uni.share
<script>
export default {
methods:{
message(evt){
// console.log("h5端传过来的值base64")
// h5端传过来的值base64
let canvasbace = evt.detail.data[0].img
// 把base64格式转换成图片文件
let bitmap = new plus.nativeObj.Bitmap("test");
let canvasImg = '';
let show = true;
let _this = this
bitmap.loadBase64Data(canvasbace, function(){
console.log("加载Base64图片数据成功");
uni.showLoading({
title: '加载中...'
})
bitmap.save("_doc/test.png",{
},function(i){
// canvasImg中获取转换后的截图图片文件
canvasImg = JSON.stringify(i.target)
canvasImg= canvasImg.replace(/^\"|\"$/g,'');//去除canvasImg 前后的双引号
bitmap.clear();
uni.hideLoading();
setTimeout(function(){
uni.showModal({
title: '提示',
content: '是否保存图片并分享?',
success: function(res) {
// console.log(res)
if (res.confirm) {
uni.showLoading({
title: '保存中...'
})
// console.log(canvasImg)
uni.saveImageToPhotosAlbum({
filePath: canvasImg,
success: function() {
uni.hideLoading()
uni.showToast({
title: '已经保存到相册,可以分享了',
icon: 'none'
})
// 跳转到服务商
setTimeout(function(){
uni.getProvider({
service: 'share',
success: function(res) {
var provider = res.provider.splice(',')
var newarr = [];
for (var i in provider) {
if (provider[i] == 'weixin') {
newarr[0] = '分享到微信'
newarr[1] = '分享到朋友圈'
}
}
//对服务商列表进行排序分配相应的参数
uni.showActionSheet({
itemList: newarr,
success: function(rest) {
let strProvider = '';
let strScene = '';
if (rest.tapIndex == 0) {
strProvider = 'weixin'
strScene = 'WXSceneSession'
} else if (rest.tapIndex == 1) {
strProvider = 'weixin'
strScene = 'WXSenceTimeline'
}
canvasImg=canvasImg.replace(/^\"|\"$/g,'');//去除canvasImg 前后的双引号
// 调用uni.share进行分享
uni.share({
provider: strProvider,
scene: strScene,
type: 2,
imageUrl: canvasImg,
success: function(res) {
uni.showToast({
title: JSON.stringify(err),
duration: 2000,
icon: 'none'
});
},
fail: function(err) {
console.log("fail:" + JSON.stringify(err));
}
});
},
fail: function(res) {
}
});
}
});
},1000)
},
fail: function(error) {
console.log(error)
uni.hideLoading()
}
})
} else if (res.cancel) {
}
}
});
}, 100)
},function(e){
console.log('保存图片失败:'+JSON.stringify(e));
bitmap.clear();
});
}, function(){
console.log('加载Base64图片数据失败:'+JSON.stringify(e));
bitmap.clear();
});
},
}
}
</script>
到此,vue页面调用高德地图,截图并分享功能就已全部实现。
三、踩坑之处
1、调用html2canvas截图时,一直出现只能截取到一半地图行政区的问题,出现这种情况的原因有两种:
第一个问题是跨域问题,解决办法:useCORS: true。
第二个问题是图片生成不完整。完整的地图是由很多图片碎片组成的。截屏的时候总会少了最右边和最下边的图片碎片。原因是html2canvas,不支持transform。需要将transform转成left和top。如下图:
我也上网搜了很多解决方法,发现很多都是
transform: matrix(1,0,0,1,30,30)这种,这个只是牵扯到平移,并没有对图层进行缩放,这种情况下可参考这篇文章,也是这篇文章对我有了启发。https://blog.csdn.net/bbbzhuzhu/article/details/88862680
但我遇到的是: transform: matrix(0.5,0,0,0.5,0,0)这种,没有进行平移,而是对图层缩小了0.5,基于上面的文章,我做了许多尝试,最后修改代码如上,也成功解决了截图不全的问题。
2.使用html2canvas截取后生成的图片是base64的,vue页面拿到这个图片后要进行分享,那就需要对图片进行转码,改成本地格式方可保存到相册并调用uni.share分享到微信。
解决方法:如上图代码中的
// h5端传过来的值base64
let canvasbace = evt.detail.data[0].img
// 把base64格式转换成图片文件
let bitmap = new plus.nativeObj.Bitmap("test");
bitmap.loadBase64Data(canvasbace, function(){
//此处省略代码,上图有............
}
好了,基本问题都解决了。对了,我这个保存到相册还是有一点点问题,每次保存到手机上的图片会把上一次保存的图片替换掉,这可能是我的保存路径问题,大家如果有好的解决方法,麻烦留言一起讨论。