Monthly Archives: 一月 2022

Hello World

cocos加载网络图片

    其实就是个简单的img-src需求,显示指定url地址的图片,刚开始用的cc.loader.load,后来换成cc.assetManager.loadAny,都不好用,最后换成cc.assetManager.loadRemote,问题解决

1
2
3
4
  let imgUrl = 'xxx';//图片地址
  cc.assetManager.loadRemote(imgUrl, {ext: '.png'}, (err, tex: cc.Texture2D) => {
     this.imgNode.getComponent(cc.Sprite).spriteFrame = new cc.SpriteFrame(tex);
  });

——-
转载请注明出处:http://www.jiangkl.com/2022/01/cocos_net_img

Hello World

桑基图的绘制

    首先明确一点,这里说的桑基图,是参照百度echarts的样式的这种桑基图。这种图,既可以标示数量多寡,又可以标示相关之间的关联关系,比单纯的饼图和折线图可以承载更多的信息

    刚开始准备用python来绘制,但搜了很多资料都有些不着边际,好不容易找一个看起来靠谱的里做了一版,绘制出来了,样式却和百度这个差别很大
    于是继续找资料,找到了一个能实现需求的包,装上以后,运行。。。生成的居然是一段html,然后打开看,实际还是调的echarts。。。
    既然逃不过echarts索性改改思路吧:python处理数据,生成数据json串,保存到服务器
    然后用php做一个承接页,读取这个json串
    将承接页的链接加到统计邮件里,点链接打开统计图,还带了交互功能,体验更好,嘿嘿
    示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
//nodes: 所有会出现的节点
//links: 所有的关系线,source是左边节点,target是右边节点
var dataJson = {
  "nodes":[{"name": '玉米'}, {"name": '大豆'}, {"name": '蛋白质'}, {"name": '淀粉'}, {"name": '脂肪'}, {"name": '水'}, {"name": '能量'}],
  "links": [
      {"source": '玉米', "target": '蛋白质', "value": 10},
      {"source": '玉米', "target": '淀粉', "value": 78},
      {"source": '玉米', "target": '水', "value": 2},
      {"source": '玉米', "target": '脂肪', "value": 10},
      {"source": '大豆', "target": '蛋白质', "value": 30},
      {"source": '大豆', "target": '淀粉', "value": 10},
      {"source": '大豆', "target": '脂肪', "value": 57},
      {"source": '大豆', "target": '水', "value": 3},
      {"source": '蛋白质', "target": '能量', "value": 40},
      {"source": '蛋白质', "target": '水', "value": 60},
      {"source": '淀粉', "target": '能量', "value": 60},
      {"source": '淀粉', "target": '水', "value": 40},
      {"source": '脂肪', "target": '能量', "value": 50},
      {"source": '脂肪', "target": '水', "value": 50}
   ]
}
echarts.init(document.getElementById("myChart")).setOption(
    (option = {
      title: {
        text: 'xxxx'
      },
      tooltip: {
        trigger: 'item',
        triggerOn: 'mousemove'
      },
      series: [
        {
          type: 'sankey',
          data: dataJson.nodes,
          links: dataJson.links,
          emphasis: {
            focus: 'adjacency'
          },
          lineStyle: {
            color: 'gradient',
            curveness: 0.5
          }
        }
      ]
    })
  );

交互体验可以直接去echart官网试试:https://echarts.apache.org/examples/zh/editor.html?c=sankey-simple
———-
转载请注明出处:http://www.jiangkl.com/2022/01/sankey

Hello World

h5多图上传功能实现

    这几年,前端技术日新月异,浏览器/h5获得的权限越来越多。这里使用h5页面做一个相册的上传功能,读取手机相册、上传到服务器,要求能够一次选择多张、上传前能看到预览、并能显示各个照片的上传进度。看到这里,有朋友肯定说:这有何难,input-file标签早就已经有multiple属性,加了它就能选多图了。呵呵,看起来简单,实际做起来问题还挺多。这里按顺序列一几个卡主的地方和解决方法:
1. 多图上传
    看到这里,肯定有人说了,不是有multiple属性吗?
    确实有,可实际用起来,不一样的
    iphone好办,全都支持一次选择多张图片
    Android手机有点麻烦,部分手机、部分浏览器不支持一次选多图;而且即便支持选多图,交互方式也不一样。比如我手头这台华为/荣耀,微信内置浏览器只能一次选一张图,改用系统浏览器,虽然可以选多张,但是需要长按,对于不熟悉的用户,可能发现不了这个功能,这就需要在应用里加指引;旁边同事的锤子就还好,微信内置浏览器就能选多图,和iphone的体验类似
2. 上传前的预览
    这个功能说白了,就是怎么拿到本机图片文件、放到img标签的src里。前端浏览器的权限限制一直很严格,对于图片上传当然也是如此,肯定不会把文件路径给你。试了几个方案,最终用的是FileReader读取、转base64显示。第一次用前端的FileReader功能,还算好用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var imgB64Arr = [];
//fileInput是input标签
fileInput.change=function(){
  var files = this.files;
  for(var j = 0; j < files.length; j++){
    var reader = new FileReader();
    reader.readAsDataURL(files[j]);
    reader.onload = function(){
      var v64 = this.result;
      imgB64Arr.push(b64);
      //...预览显示逻辑...
    };
  }
};

    这个方案将图片的base64编码放在了imgB64Arr数组里,以方便后续上传处理。不过考虑到现代手机拍照的大小,和多选功能,如果一次选的图很多,会占用大量的内存,所以这里流畅度待验证,可能需要优化
3. 逐个上传
    分开上传的目的有二:
    1). 递归上传,降低有网络问题带来的上传失败的概率
    2). 分开显示上传进度,这样前端体验会更好
    这里我偷了个懒,没用递归,而是定时轮训imgB64Arr数组,有内容就上传,上传完删掉,呵呵

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
  var uploadingImg = false; //标示当前是否有正在上传的东西
  setInterval(function(){
    if(!uploadingImg && imgB64Arr.length > 0){
      var nowUp = imgB64Arr[0];
      uploadingImg = true;
      var imgName = 'xxx';//文件命名策略
      subimtInageFile(imgName, imgBa64s[nowUp.img], function(retu, err){
        if(err){
          //TODO: 错误处理
          return;
        }
        //上传完成相关数据维护
        imgB64Arr = imgB64Arr.length > 0 ? imgB64Arr.slice(1) : [];
        uploadingImg = false;
        //TODO: 显示更新逻辑
      });
    }
  }, 300);
  function subimtInageFile(imgName, ba64, callback){
    var formData = new FormData();
    formData.append('up_photo', convertBase64UrlToBlon(ba64));
    //这里服务端要留意:没找到怎么把名字写到上传文件里,所以将文件名直接作为单独一个post参数提交
    formData.append('file_name', imgName); 
    $.ajax({
      url: '...',
      type: 'POST',
      data: formData,
      dataType: 'json',
      processData: false, //否则jquery会报错
      contentType: false,
      success: function(sd){
        callback && callback(sd);
      },
      error: function(xhr, err){
        callback && callback(false, err);
      }
    });
  }
  //图片处理,base64欢迎成图片blob
  function convertBase64UrlToBlon(base64Str){
    var bs = window.atob(base64Str.split(',')[1]);
    var ab = new ArrayBuffer(bs.length);
    var ia = new Uint8Array(ab);
    for(var i = 0; i < bs.length; i++) ia[i] = bs.charCodeAt(i);
    var bb = new Blob([ab], {type: 'image/png'});
    return bb;
  }

———-
    写到这里,大概有朋友要说了:这么麻烦干嘛,微信有wx.chooseImage()不香吗?没错,要是能调微信api的需求,当然就不用上面这么麻烦了O(∩_∩)O~
over
转载请注明出处:http://www.jiangkl.com/2022/01/h5_file_multiple