此系列已完结,共3部分:
之前在part2中说的添加自定义主题配色已经开发完成了,除此之外我还添加了一些的3d特效。
最后出来的效果还是蛮炫的。



由于项目一开始就使用的dataV,并且有计划的提取出了颜色值,所以定制主题便不是很麻烦,直接提取改变dataV的color属性即可,其他部分直接使用vue的动态样式绑定。
先在设置组件SetDrawer中预先设置好需要使用的配置信息,包括预设的主题,然后使用vue3的onBeforeMount在挂载组件之前将包含颜色的配置信息用sessionStorage.setItem("config", JSON.stringify(setData.value))先存储到浏览器本地,这样可以防止刷新页面时配置信息丢失重置。
//系统配置
function sysConfig() {
setData.value.sysVer = PK.version//获取系统版本号
process.env.NODE_ENV == "development" ?
setData.value.dataType = dataTypeList[0] ://开发环境使用离线数据
setData.value.dataType = dataTypeList[1];//生产环境使用在线数据
let ss = sessionStorage.getItem("config");//获取缓存配置
//缓存中有配置取出配置,无则使用初始配置
if (ss) {
let cuVer = setData.value.sysVer,//当前版本号
ssVer = JSON.parse(ss).sysVer,//缓存版本号
isUpDate = null;//是否更新缓存
//当前版本号与缓存版本号若不等清除缓存使用当前配置,否则使用缓存配置
(cuVer !== ssVer) ?
(isUpDate = true) :
isUpDate = false;
isUpDate ?
(
(sessionStorage.removeItem("config")),//清除缓存
(sessionStorage.setItem("config", JSON.stringify(setData.value)))//设置缓存配置
) :
(setData.value = JSON.parse(ss));
} else {
sessionStorage.setItem("config", JSON.stringify(setData.value));//设置缓存配置
}
};
值得注意的是,需要在存入配置信息前判断缓存中是否已经存在配置信息,若有,则直接使用缓存配置,若没有则存入预先在代码中写好配置。
在页面加载瞬间就需要获取颜色值的组件中使用onMounted与JSON.parse(sessionStorage.getItem("config") )获取到上一步在缓存中存下的配置信息,从配置信息中获取到颜色值,最后在利用该值将dom渲染出来,dataV的部分支持使用:color="['#fff', '#aaa']"来动态改变颜色,其中数组中第一个值为主色,第二个为副色; 非dataV的部分直接使用vue动态绑定样式的语法:style=“{color:#fff}”来修改配色。

切换主题时直接在设置组件中改变当前使用的配色值然后刷新页面即可,因为我在切换3d球体颜色时偷了一个懒,正常流程是获取球体mesh,改变材质的color值,然后更新的。我直接刷新了浏览器(又不是不能用(*  ̄︿ ̄)),重建了场景、相机、球体等。
我预设了三对主色、副色的颜色值。为了看起来更和谐,建议使用同一颜色的深色与浅色来搭配。

v-for即可渲染出切换按钮。

我也是在无意中发现input的type居然是支持color的。可以直接原生实现取色器,这样就可以用颜色吸管获取屏幕中的任何颜色了:
<input id="colorInp" style="height: 0px;opacity: 0;width: 0px;margin: 0px;padding: 0px;" type="color" />
要使用自己的按钮点击打开取色器,可以直接将input的高宽赋为0,不透明度赋为0,将其隐藏后,再使用按钮绑定事件打开取色器即可:
<el-button class="main-color" :color="setData.sysColor[0]" @click="changeColor(0)">主色</el-button>
function changeColor(type: Number) {
(document.getElementById("colorInp") as any).click();//手动点击取色器
colorType = type;//改变颜色类型
};


项目中一共有七种环形效果:
//创建环
function createRings() {
createEquatorSolidRing(earthSize + 20);//创建赤道实线环
createEquatorFlyline(earthSize + 30);//创建赤道飞线环
createEquatorDottedLineRing(earthSize + 35);//创建赤道虚线环
createSpikes(earthSize + 40);//创建赤道尖刺
createUpDownRing(earthSize - 50, earthSize - 40);//创建南北极环
createExpandRing();//创建爆炸环
createSphereGlow();//创建球体光晕
};
接下来我们详细分析一下。

即为赤道上最靠近球体内层的一层环。
//创建赤道实线环
function createEquatorSolidRing(r: any) {
//创建里层的环
let ringGeometry = new THREE.RingGeometry(r - 2, r + 2, 100);
let ringMaterial = new THREE.MeshBasicMaterial({
color: dvColor.value[0],
opacity: .3,
side: THREE.DoubleSide,
fog: true,
depthWrite: false,
blending: THREE.AdditiveBlending,
});
let ringMesh = new THREE.Mesh(ringGeometry, ringMaterial);
ringMesh.rotation.x = 90 * Math.PI / 180;
earthGroup.add(ringMesh);
};

即为赤道第二靠近球体的环。
//创建赤道飞线
function createEquatorFlyline(r: any) {
const geometry = new THREE.BufferGeometry();
const path = new THREE.Path();
path.arc(0, 0, r, 0, Math.PI * 2);
const points = path.getPoints(100);//切割段数
geometry.setFromPoints(points);
const line = new MeshLine();
// 设置几何体
line.setGeometry(geometry)
const material = new MeshLineMaterial({
color: dvColor.value[0],
lineWidth: 1, // 线条的宽度
dashArray: .5, // 该数值倒数为线段数量
dashRatio: .5, // 不可见与可见比例
transparent: true, // 设置透明度
})
flylineMesh = new THREE.Mesh(line.geometry, material);
flylineMesh.rotation.x = 90 * Math.PI / 180;
earthGroup.add(flylineMesh);
};

即为赤道第三靠近球体的白色虚线环。
//创建赤道虚线环
function createEquatorDottedLineRing(r: any) {
const positions = [];
let ringPointGeometry = new THREE.BufferGeometry(); //环形点几何体
let pointNum = 50;//点的数量
let ringPointAngle = (2 * Math.PI) / pointNum; //环形点角度
for (let o = 0; o < 500; o++) {
let n = new THREE.Vector3(); //点的向量
n.x = r * Math.cos(ringPointAngle * o); //计算点的角度
n.y = 0;
n.z = r * Math.sin(ringPointAngle * o);
positions.push(n.x, n.y, n.z);
}
ringPointGeometry.setAttribute(
"position",
new THREE.Float32BufferAttribute(positions, 3)
);//设置位置属性
let ringPointMaterial = new THREE.PointsMaterial({
//环形点材质
size: 3,
// color: dvColor.value[0],
transparent: false,
blending: THREE.AdditiveBlending,
side: THREE.DoubleSide,
depthWrite: false,
});
dotLineRingMesh = new THREE.Points(
ringPointGeometry,
ringPointMaterial
);
dotLineRingMesh.name = "赤道虚线";
earthGroup.add(dotLineRingMesh);
};

即为赤道环中类似钟表刻度的环形。
//创建赤道尖刺
function createSpikes(spikeRadius: any) {
let spikesVerticesArray = [];
let spikesObject = new THREE.Group(); //创建尖刺的组
spikesObject.name = "赤道尖刺";
earthGroup.add(spikesObject); //将尖刺组添加到旋转组中
//创建尖刺
let spikeNum = 400;//尖刺数量
let o = (2 * Math.PI) / spikeNum;
for (let s = 0; s < spikeNum; s++) {
let r = new THREE.Vector3();
r.x = spikeRadius * Math.cos(o * s);
r.y = 0;
r.z = spikeRadius * Math.sin(o * s);
r.normalize();//归一化,将该向量转化为向量单位
r.multiplyScalar(spikeRadius);
let i = r.clone(); //克隆r至i
(s % 10 == 1) ? i.multiplyScalar(1.1) : i.multiplyScalar(1.05);//每10个计算一次向量与标量相乘
spikesVerticesArray.push(r); //将向量存入尖刺顶点列表
spikesVerticesArray.push(i);
}
let n = new Float32Array(3 * spikesVerticesArray.length); //创建顶点数组
for (let s = 0; s < spikesVerticesArray.length; s++) {
n[3 * s] = spikesVerticesArray[s].x;//给顶点数组设置坐标
n[3 * s + 1] = spikesVerticesArray[s].y;
n[3 * s + 2] = spikesVerticesArray[s].z;
}
//尖刺材质
let spikesMaterial = new THREE.LineBasicMaterial({
// linewidth: 1,//webgl渲染器限制,不能设置宽度,始终为1(three.meshline插件可解决)
// color: "#fff",
color: dvColor.value[0],
transparent: true,
opacity: .5
});
let spikesBufferGeometry = new THREE.BufferGeometry(); //创建尖刺几何体
spikesBufferGeometry.setAttribute(
"position",
new THREE.BufferAttribute(n, 3)
); //添加位置属性
let spikesMesh = new THREE.LineSegments(
spikesBufferGeometry,
spikesMaterial
);
spikesObject.add(spikesMesh); //将网格放进组
};

即为赤道最外面一层环,它会不断的放大渐变,形成类似爆炸冲击波一样的效果。具体原理是这样的。
//创建渐变环
function createExpandRing() {
let ringMaterial = new THREE.MeshBasicMaterial({
map: new THREE.TextureLoader().load(ringImg),
color: new THREE.Color(dvColor.value[0]),//颜色
transparent: true,
opacity: 1,
side: THREE.DoubleSide,
fog: true,
depthWrite: false,
blending: THREE.AdditiveBlending,
});
let ringGeometry = new THREE.PlaneGeometry(earthSize * 2, earthSize * 2, 10, 10);
expandRingMesh = new THREE.Mesh(ringGeometry, ringMaterial);
expandRingMesh.name = "放大环";
expandRingMesh.rotation.x = 90 * Math.PI / 180;
earthGroup.add(expandRingMesh);
};
//创建渐变环动画
function createExpandRingAnimation() {
gsap.isTweening(expandRingMesh.scale) ||//环动画
(gsap.fromTo(
expandRingMesh.scale,//缩放渐变
{ x: 1, y: 1, },
{ x: 2.7, y: 2.7, duration: 1.5 }
),
gsap.fromTo(
expandRingMesh.material,//材质的透明度渐变
{ opacity: 1, },
{ opacity: 0, duration: 1.5 }
))
};


如图,即为球体上下的双层环形。其生成方法与赤道实线环一样,不同之处是需要改变position.y值,使之移动到球体南北极。
//创建上下环
function createUpDownRing(r1: any, r2: any) {
let ringsObject = new THREE.Group(); //创建环的组
ringsObject.name = "南北极环";
earthGroup.add(ringsObject); //将环添加到场景中
//创建内环
let a = new THREE.RingGeometry(r1, r1 - 2, 100); //圆环几何体(内半径,外半径,分段数)
let ringsOuterMaterial = new THREE.MeshBasicMaterial({
color: dvColor.value[0],
transparent: true,
opacity: .3,
side: THREE.DoubleSide,
fog: true,
depthWrite: false,
blending: THREE.AdditiveBlending,
});
let o = new THREE.Mesh(a, ringsOuterMaterial);
o.rotation.x = 90 * Math.PI / 180; //设置旋转
let r = o.clone(); //克隆外环网格o至r
o.position.y = 95; //设置位置
r.position.y = -95;
ringsObject.add(o);
ringsObject.add(r);
//创建外环
let t = new THREE.RingGeometry(r2, r2 - 2, 100);
let ringsInnerMaterial = new THREE.MeshBasicMaterial({
color: dvColor.value[0],
transparent: true,
opacity: .3,
side: THREE.DoubleSide,
fog: true,
depthWrite: false,
blending: THREE.AdditiveBlending,
});
let i = new THREE.Mesh(t, ringsInnerMaterial);
i.rotation.x = 90 * Math.PI / 180;
let n = i.clone();
i.position.y = 100;
n.position.y = -100;
ringsObject.add(i);
ringsObject.add(n);
};

即为球体外部的一层光晕。
//创建球体发光环
function createSphereGlow() {
//SpriteMaterial材质始终朝向平面
let glowMaterial = new THREE.SpriteMaterial({
map: new THREE.TextureLoader().load(earthGlowImg),
color: new THREE.Color(dvColor.value[0]),//颜色
transparent: true,
opacity: 1,
side: THREE.DoubleSide,
fog: true,
depthWrite: false,
blending: THREE.AdditiveBlending,
})
let glowSprite = new THREE.Sprite(glowMaterial);
glowSprite.scale.set(earthSize * 3.2, earthSize * 3.2, 1); //点大小
earthGroup.add(glowSprite);
};
成都的12月份好冷啊ヽ(≧□≦)ノ,手指头开始造反不听使唤了,项目到这里差不多该是告一段落了,本项目仅作为我学习webgl与可视化结合使用的一个demo,项目是完全开源了的,有想使用的可以直接在我的gitee上clone,链接在本文开头(不要忘记star啊大哥们!)。
我即将开始一个将录制和编辑音频文件的项目,我正在寻找一个好的库(最好是Ruby,但会考虑Java或.NET以外的任何库)以进行实时可视化波形。有人知道我应该从哪里开始搜索吗? 最佳答案 要流入浏览器的数据量很大。Flash或Flex图表可能是唯一能提高内存效率的解决方案。Javascript图表往往会因大型数据集而崩溃。 关于ruby-Ruby中的波形可视化,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.c
Unity数据可视化图表插件XCharts3.0发布历时8个多月,业余时间,断断续续,XCharts3.0总算发布了。如果要打个满意度,我给3.0版本来个80分。对于代码框架结构设计的调整改动,基本符合预期,甚是满意。相比之前的1.0和2.0版本,我认为3.0才是一个拿得出手给广大开发者使用的版本。1.0发布的时候,很兴奋,从0.1到1.0,也磨了一年,真的等不及想给大家试用了,还特地写过一篇文章以示庆祝。那个时候,1.0虽然还还不够完善,功能也不够丰富,但它是XCharts的开始,没有1.0,也就没有后面的2.0和3.0。后面的2.0发布,做了很多改进和优化,随着版本迭代,慢慢的发现有不少硬
本人是音乐爱好者,从小就特别喜欢那个随着音乐跳动的方框效果,就是这个:arduino上一大把对,我忍你很久了,我就想用mpy做,全网没有,行我自己研究。果然兴趣是最好的老师,我之前有篇博客专门讲音频,有兴趣的可以回顾一下。提到可视化频谱,必然绕不开fft,大学学过这玩意,当时一心玩,老师讲的一个字都么听进去,网上教程简略扫了一下,大该就是把时域转频域的工具,我大mpy居然没有fft函数,奶奶的,先放着。音频信息如何收集?第一种傻瓜式的ADC,模拟转数字,原始粗暴,第二种,I2S库,我之前博客有讲过,数据是PCM编码。然后又去学PCM编码,一学豁然开朗,舒服,以代码为例:audio_in=I2S
我以前在Laravel4上工作过,它有一个很棒的日志查看器工具laravellogviewer查看demo我正在寻找与Rubyonrails4.2非常相似的东西,如果你们知道Rails4.2的任何好的可视化日志记录GEM,请告诉我..从代码我需要记录不同的日志级别,这个工具应该直观地组织我的日志,谢谢.. 最佳答案 这应该可以帮助您入门https://github.com/shadabahmed/logstasher如其所说Thisgemisheavilyinspiredfromlograge,butit'sfocusedonone
急促的告警铃声响彻寂静的夜晚。对运维人来说,晚间值守耗费更大的精力,往往一个简单的磁盘使用率告警通知,就不得不爬起来进行处理,毕竟告警无小事,对于小问题,运维人也不能心存侥幸心理。虽然有着值班人员和团队的支撑,但频繁的告警还是让运维人员精疲力竭,如何让系统的稳定性提高,减轻一线人员的工作量,减轻一线人员的压力?通过智能运维,实现故障自愈将成为不可避免的选择。故障自愈是提升企业网络系统可用性和降低故障处理的人力投入,实现故障自愈从"人工处理"到"无人值守"的变革。通过实时发现告警,进行预诊断分析,判断告警类型和级别,如果是一般告警,平台进行自动恢复,如果是严重复杂告警则通过告警通知、运维工单等形
数组理论基础数组是存放在连续内存空间上的相同类型数据的集合。数组下标从0开始数组内存空间的地址是连续的c++中vector和array的区别1、vector是顺序容器,其利用连续的内存空间来存储元素,但是其内存空间大小是能够改变的。2、array是顺序容器,其也是利用连续的内存空间来存储元素,但它的内存空间是固定大小的,申请之后就无法改变。3、vector的底层是array实现的二维数组二维数组在内存的空间地址是连续的704|二分查找思路1、把整个数组一分为二;2、判断目标值在左区间还是右区间,若在左区间,则修改右区间指针的位置;若在右区间,则修改新区间的左区间位置3、重复上述过程,直到lef
我想澄清这个原始post的一些事情.答案建议Ruby按以下顺序搜索常量定义:封闭范围任何外部范围(重复直到达到顶层)包含的模块父类(superclass)对象内核所以澄清一下,在第(1-6)步是为legs_in_oyster找到的常量LEGS的值?它来自父类(superclass)Animal吗?类MyAnimals的范围是否因为不被视为封闭范围而被忽略?这是由于明确的MyAnimals::Oyster类定义吗?谢谢!只是想了解。这是代码:classAnimalLEGS=4deflegs_in_animalLEGSendclassNestedAnimaldeflegs_in_neste
我正在使用谷歌可视化API创建堆积面积图。当用户将鼠标悬停在图表内的一个点上时,我希望它显示该位置点的总和,以及这些点的值。第二点,我可以通过指定选项focusTarget:'category'轻松实现。我希望在类似的外观和感觉中,在total的工具提示中多一行。我尝试通过添加一个名为Total的额外列来实现此目的,该列的值为0,但工具提示等于总和。然而,这会向图例和图表本身添加一个空行,这在视觉上并不吸引人。我觉得这应该是开箱即用的东西,但我找不到解决这个问题的方法。如果有人知道解决这个问题的好方法,请回答。提前致谢。 最佳答案
我的工作涉及大量的可视化。我一直在用D3.js和JavaScriptInfovistoolkit我最近了解到Dart如何成为开发Web应用程序的新方法。Q1。Dart是否提供任何用于可视化的库(某种级别的D3.js或JavaScriptInfovistoolkit)?Q2。如果我继续使用Dart,我可以使用D3.js吗?/JavascriptInfovistoolkit与Dart一起?编辑:我在互联网上发现wecanuseJavascriptalongwithDart.我经历了DartFAQ,但无法真正找到与可视化库或D3.js本身相关的任何内容。 最佳答案
我正在使用googlevisulaization绘制饼图。我面临的问题是,我无法捕获饼图上的点击事件。我正在这样做。functiondrawchartfromRe(){dashboard=newgoogle.visualization.Dashboard(document.getElementById('dashboard_div'));//alert("RefuelLength"+totrefuelList.length);//alert("Vehicleid:"+totrefuelList[0].vehicleId);//google.load("visualization","1