掘金收割机的年终总结,我用 Three.js 创建了一个"掘金城市" | 2021年终总结征文

简介: 我叫大帅,一个老程序猿。本文会在评论中抽一个幸运鹅获得掘金周边鼠标垫1份

我肝了一周,用Three.js创建了一个"掘金城市"


“肝”货?


先看最终效果


image.png


数据来源


2021我在掘金写了多少篇文章?


我很想知道我这一年究竟在掘金写了多少篇文章,每篇文章多少赞。但掘金没有提供以为单位的接口。不得已呢,我只好使用文章列表接口去遍历,一旦发现创建时间早于2021年1月1日 0时0分0秒的文章则结束遍历,以此来获得今年我发布的全部文章。


//获取指定指针位置的10篇文章
function getArticles(uid,cursor='0'){
  const res = await uniCloud.httpclient.request("https://api.juejin.cn/content_api/v1/article/query_list",{
    data:{
      "cursor": cursor,
      "sort_type": 2,
      "user_id": uid
    },
    headers:{
      "Content-Type":"application/json"
    },
    method:"POST",
    dataType:"json"
  })
  return res.data.data;
}
//获取文章直到xx时间戳
function getArticlesAfter(uid,unixtime){
  let dataByYear = {};
  let cursor = 0;
  async function getNextArticles(){
    let res = await getArticles(uid,cursor);
    console.log(res);
    if(!res)return dataByYear;
    let getTheLast = false;
    for(let i = 0;i<res.length;i++){
      var article_item = res[i];
                        //发现小于时间戳的文章则停止遍历
      if(article_item.article_info.ctime<unixtime){
        console.log('结束了,去年最后一篇是:');
        console.log(article_item.article_info.title);
        getTheLast=true;
        break;
      }else{
                                //发现文章的时间晚于2021年12月31日的话则跳过
                                //2022年还有人访问这个接口,不至于出问题
        if(article_item.article_info.ctime>1640966400)continue;
        var cDate = new Date(parseInt(article_item.article_info.ctime)*1000);
        var month = cDate.getMonth();
        if(!dataByYear[month])dataByYear[month]=[];
                                //用不了那么多字段,重新梳理数据结构
        var sItem = {
          title:article_item.article_info.title,
          author_name:article_item.author_user_info.user_name,
          article_id:article_item.article_info.article_id,
          view_count:article_item.article_info.view_count,
          digg_count:article_item.article_info.digg_count,
          comment_count:article_item.article_info.comment_count,
          ctime:article_item.article_info.ctime
        }
        dataByYear[month].push(sItem);
      }
    }
    cursor+=res.length;
    if(!getTheLast)return getNextArticles();
    else return dataByYear;
  }
  return getNextArticles();
}


然后把所有文章按照月份重新组织数据,最终数据结构如下:


image.png


这个接口我也提供给大家,如果你不满意我的表现形式,也可以自己处理这些数据。

但我不保证接口长期有效哦!


https://e0b75de1-90c7-4c11-9d12-a8bc84c4d081.bspapp.com/http/jjskyline?uid=你的掘金uid


数据的表现形式


原本我是打算直接照抄 skyline.github.com


image.png


结果光一个底座,我就折腾了大半天,完全完全没想到在Three.js里画一个立体梯形结构体还挺麻烦。


最后请教了webgl大佬,他教我用bufferGeometry,需要把梯形体所有的点计算出来,一个梯形体不过8个点,还好算。


囧的是,就在我最后画出来梯形体的时候,我发现打不上光。


因为要接受光照信息,还得计算全部的顶点法线...


头秃!由于代码太长,并且最后也没用上梯形体,我就不贴代码了。


另外,我发现github skyline的表现形式其实也并不适合呈现掘金全年文章数据。

所以干脆原创一个吧!


image.png


这是为掘金社区定制


喂,有没有人买个单呐?


好吧,没有人


就当我闲得蛋疼吧


看着还不赖吧~当然一开始它也不是长这样的,为了让整个城市看起来更“美观”,我可真是揪光了头发。边开发边设计边直播...尝试了各种布局


  • 初版


一开始,我为创建城市设定了以下基本规则


1、每个月是一个区块,一共4x3。
2、每篇文章是一个建筑物,每月最多显示30篇。
3、文章的赞越多则建筑物越高。


image.png


然后我发现有一些文章的点赞数据确实太少了,原封不动的照数据画出来,并不好看。


  • 第二版


接着我设定了创建城市的基本规则2.0


4、建筑物的单层面积由当月文章数量决定。
5、区块内建筑物的排布根据当月文章数量决定。
6、区块内所有建筑物的整体区域与区块面积居中。
7、建筑物的高度有一个基数,确保不会出现太矮的。
复制代码


image.png


现在是不是舒服多了,错落有致,大小不一,但又很整齐。只是当月份是奇数时,最后孤单的建筑让整体看上去不太舒服,所以继续升级。


  • 第三版


创建城市的基本规则3.0


8、区块内建筑物的如果是奇数,最后一个宽度加倍,填满空间


image.png


现在看上去是不是舒服多了?


但是,也叫城市,怕不是个芯片样板?


恰好,网抑云里正在播放一首歌,歌词是这样的


这城市那么空
这回忆那么凶
这街道车水马龙
我能和谁相拥


咦,街道! 城市那必须得有街道呀!


  • 第四版


纯手绘街道贴图,每一个像素都是我用鼠标在PS里画出来的。


我真是闲得蛋疼,again!


image.png


image.png


TADA!是不是有点感觉了?做到这,我发量已经告急了!


  • 第五版


城里哪有那么清澈的空气!


加点雾(mai)吧~


scene.fog = new THREE.Fog(0xffffff, 0.01, 6);


image.png


  • 第六版


就在我觉得大功告成的时候,我测试一下 @大圣老师 的账号数据。


image.png


嗯,绿化面积很大,证明了他真是摸鱼摸到Lv5的。


得给他整得难看点,谁叫他不写文章的(此句优弧非要加上)


好吧,没有文章的月份就弄一个工地的贴图把


image.png


你看看


城乡结合部的既视感是不是就出来了


  • 第7版(未遂)


方块城市没有感觉,干脆加点建筑物模型吧。我随即打开unity3dassetsstore


image.png


这一套模型太好看了,太合适了吧!


竟然只要9.99!


买它!买它!买它!


就在我准备下单支付的时候


image.png


告别unity3d吧,瞧不起我mainland是怎么滴?


不买了~


就这样吧!没头发揪了~


开发的最后


其实整个原创设计的开发过程远远不止7版,最近几天我都一直在小破站直播写这个小网页,很多朋友是见证了这个开发过程的。


当我还想继续摸鱼,开发这些没用的东西的时候。


被掘金张哥来催稿了


image.png


算了,就开发到这吧...


还是努力写专栏吧~



相关文章
|
人工智能 弹性计算 安全
AMD产品介绍|通用型实例g8a
g8a实例:高性价比X86服务器,搭载最新CIPU架构,提供100G*2网络带宽和eRDMA支持。基于AMD Genoa平台,主频2.7/3.7GHz,专为性能、成本和稳定性需求设计。适用于通用应用、AI推理训练、高清视频处理等场景。实例性能提升25%,性价比提升15%,内置安全芯片,支持可信计算和机密计算。
|
C语言 C++
【C语言】rand()函数(如何生成指定范围随机数)
【C语言】rand()函数(如何生成指定范围随机数)
1017 0
|
6月前
|
人工智能 机器人 物联网
提高商店客流量的智能设备选型指南:从客流分析到数字化运营
实体零售面临客流下滑与运营瓶颈,亟需从“坐商”转向“数据驱动+主动引流”。本文系统解析六大类智能设备技术架构,涵盖客流分析、智能引流、智慧收银、导视系统、数据中台与氛围营造,结合不同业态痛点提供选型策略与实施路径,助力门店实现数字化升级与效率跃迁。
|
6月前
|
机器学习/深度学习 资源调度 网络协议
TSAPINN:用于求解NS方程的新型PINN网络结构
本文提出一种基于可训练正弦激活函数的物理信息神经网络(TSA-PINN),用于高效求解纳维-斯托克斯方程。该方法通过神经元级可调频率的正弦激活机制,动态适应复杂流场特征,显著提升模型表达能力与收敛速度。结合动态斜坡恢复策略,有效缓解梯度问题,增强训练稳定性。在涵盖稳态、振荡及三维湍流等多种挑战性场景的数值实验中,TSA-PINN 在精度和效率上均优于传统PINN,尤其在近壁湍流和多尺度涡旋相互作用等难题中表现突出,为科学计算中的复杂流动模拟提供了新范式。
|
6月前
|
人工智能 JavaScript 搜索推荐
AI Agent MCP 源代码部署Deployment 获得子域名Live URL的0-1教程
本文介绍如何将AI Agent或MCP服务部署上线,获取免费二级域名(如*.aiagenta2z.com),并在ChatGPT、Claude等客户端中直接使用。涵盖代码准备、入口命令配置、GitHub部署及调试全流程,支持Python/Node.js项目,助力开发者快速实现服务托管与集成。
|
存储 安全 C语言
详解C/C++输入输出
详解C/C++输入输出
|
Kubernetes 负载均衡 应用服务中间件
k8s学习--ingress详细解释与应用(nginx ingress controller))
k8s学习--ingress详细解释与应用(nginx ingress controller))
2960 0
|
开发框架 缓存 自然语言处理
HarmonyOS ArkTS声明式UI开发实战教程
本文深入探讨了ArkTS作为HarmonyOS生态中新一代声明式UI开发框架的优势与应用。首先对比了声明式与命令式开发的区别,展示了ArkTS如何通过直观高效的代码提升可维护性。接着分析了其核心三要素:数据驱动、组件化和状态管理,并通过具体案例解析布局体系、交互组件开发技巧及复杂状态管理方案。最后,通过构建完整TODO应用实战,结合调试优化指南,帮助开发者掌握声明式UI设计精髓,感受ArkTS的独特魅力。文章鼓励读者通过“破坏性实验”建立声明式编程思维,共同推动HarmonyOS生态发展。
762 3
|
机器学习/深度学习 人工智能 自然语言处理
深度学习之分子生成
基于深度学习的分子生成是一项结合化学、计算科学与人工智能的新兴领域,旨在利用深度学习模型来生成具有特定性质的分子结构。
524 3