添加政府,银行大屏,修改政府前后端代码
This commit is contained in:
1076
datav-bank/src/App.vue
Normal file
1076
datav-bank/src/App.vue
Normal file
File diff suppressed because it is too large
Load Diff
70
datav-bank/src/assets/ningxia.json
Normal file
70
datav-bank/src/assets/ningxia.json
Normal file
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"name": "银川市",
|
||||
"cp": [106.2324, 38.4663]
|
||||
},
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [[
|
||||
[105.8, 38.8], [106.6, 38.8], [106.6, 38.1], [105.8, 38.1], [105.8, 38.8]
|
||||
]]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"name": "石嘴山市",
|
||||
"cp": [106.3586, 39.0133]
|
||||
},
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [[
|
||||
[105.9, 39.4], [106.8, 39.4], [106.8, 38.6], [105.9, 38.6], [105.9, 39.4]
|
||||
]]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"name": "吴忠市",
|
||||
"cp": [106.1993, 37.9972]
|
||||
},
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [[
|
||||
[105.5, 38.2], [107.2, 38.2], [107.2, 37.4], [105.5, 37.4], [105.5, 38.2]
|
||||
]]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"name": "固原市",
|
||||
"cp": [106.2853, 36.0046]
|
||||
},
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [[
|
||||
[105.4, 36.8], [107.1, 36.8], [107.1, 35.2], [105.4, 35.2], [105.4, 36.8]
|
||||
]]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"name": "中卫市",
|
||||
"cp": [105.1896, 37.5149]
|
||||
},
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [[
|
||||
[104.2, 38.0], [106.0, 38.0], [106.0, 36.8], [104.2, 36.8], [104.2, 38.0]
|
||||
]]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
689
datav-bank/src/components/Dashboard.vue
Normal file
689
datav-bank/src/components/Dashboard.vue
Normal file
@@ -0,0 +1,689 @@
|
||||
<template>
|
||||
<div class="dashboard-container">
|
||||
<!-- 顶部标题栏 -->
|
||||
<div class="header">
|
||||
<div class="title">
|
||||
<span class="main-title">宁夏智慧畜牧可视化大屏</span>
|
||||
<span class="sub-title">宁夏回族自治区</span>
|
||||
</div>
|
||||
<div class="time-info">
|
||||
<span class="date">{{ currentDate }}</span>
|
||||
<span class="time">{{ currentTime }}</span>
|
||||
<span class="weather">22°C 晴朗</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 主体内容区域 -->
|
||||
<div class="main-content">
|
||||
<!-- 左侧面板 -->
|
||||
<div class="left-panel">
|
||||
<!-- 畜牧产业基础分析 -->
|
||||
<div class="panel-section">
|
||||
<div class="section-title">
|
||||
<span class="title-icon">📊</span>
|
||||
畜牧产业基础分析
|
||||
</div>
|
||||
<div class="stats-grid">
|
||||
<div class="stat-item">
|
||||
<div class="stat-label">牛存栏</div>
|
||||
<div class="stat-value">200 <span class="unit">万</span></div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-label">羊存栏</div>
|
||||
<div class="stat-value">200 <span class="unit">万</span></div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-label">猪存栏</div>
|
||||
<div class="stat-value">200 <span class="unit">万</span></div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-label">合作社数量</div>
|
||||
<div class="stat-value">200 <span class="unit">个</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 养殖品种分布 -->
|
||||
<div class="panel-section">
|
||||
<div class="section-title">
|
||||
<span class="title-icon">🐄</span>
|
||||
养殖品种分布
|
||||
</div>
|
||||
<div class="chart-container" ref="breedChart"></div>
|
||||
</div>
|
||||
|
||||
<!-- 全年文档管理统计 -->
|
||||
<div class="panel-section">
|
||||
<div class="section-title">
|
||||
<span class="title-icon">📋</span>
|
||||
全年文档管理统计
|
||||
</div>
|
||||
<div class="chart-container" ref="docChart"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 中央地图区域 -->
|
||||
<div class="center-panel">
|
||||
<Map3D />
|
||||
</div>
|
||||
|
||||
<!-- 右侧面板 -->
|
||||
<div class="right-panel">
|
||||
<!-- 流动资源分析 -->
|
||||
<div class="panel-section">
|
||||
<div class="section-title">
|
||||
<span class="title-icon">💰</span>
|
||||
流动资源分析
|
||||
</div>
|
||||
<div class="resource-list">
|
||||
<div class="resource-item">
|
||||
<span class="resource-name">资金</span>
|
||||
<div class="progress-bar">
|
||||
<div class="progress" style="width: 75%;"></div>
|
||||
</div>
|
||||
<span class="resource-value">7500000</span>
|
||||
</div>
|
||||
<div class="resource-item">
|
||||
<span class="resource-name">饲料</span>
|
||||
<div class="progress-bar">
|
||||
<div class="progress" style="width: 60%;"></div>
|
||||
</div>
|
||||
<span class="resource-value">6000000</span>
|
||||
</div>
|
||||
<div class="resource-item">
|
||||
<span class="resource-name">设备</span>
|
||||
<div class="progress-bar">
|
||||
<div class="progress" style="width: 85%;"></div>
|
||||
</div>
|
||||
<span class="resource-value">8500000</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 每日资源统计 -->
|
||||
<div class="panel-section">
|
||||
<div class="section-title">
|
||||
<span class="title-icon">📈</span>
|
||||
每日资源统计
|
||||
</div>
|
||||
<div class="chart-container" ref="dailyChart"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部图表区域 -->
|
||||
<div class="bottom-panel">
|
||||
<div class="chart-section">
|
||||
<div class="section-title">
|
||||
<span class="title-icon">📊</span>
|
||||
全年文档管理统计
|
||||
</div>
|
||||
<div class="chart-container" ref="yearChart"></div>
|
||||
</div>
|
||||
<div class="chart-section">
|
||||
<div class="section-title">
|
||||
<span class="title-icon">📈</span>
|
||||
近七日资源统计
|
||||
</div>
|
||||
<div class="chart-container" ref="weekChart"></div>
|
||||
</div>
|
||||
<div class="chart-section">
|
||||
<div class="section-title">
|
||||
<span class="title-icon">📊</span>
|
||||
每日资源流入
|
||||
</div>
|
||||
<div class="chart-container" ref="inflowChart"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted } from 'vue'
|
||||
import * as echarts from 'echarts'
|
||||
import Map3D from './Map3D.vue'
|
||||
|
||||
// 响应式数据
|
||||
const currentDate = ref('')
|
||||
const currentTime = ref('')
|
||||
|
||||
// 图表引用
|
||||
const breedChart = ref(null)
|
||||
const docChart = ref(null)
|
||||
const dailyChart = ref(null)
|
||||
const yearChart = ref(null)
|
||||
const weekChart = ref(null)
|
||||
const inflowChart = ref(null)
|
||||
|
||||
// 定时器
|
||||
let timeInterval = null
|
||||
|
||||
// 更新时间
|
||||
const updateTime = () => {
|
||||
const now = new Date()
|
||||
currentDate.value = now.toLocaleDateString('zh-CN', {
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit'
|
||||
}).replace(/\//g, '-')
|
||||
currentTime.value = now.toLocaleTimeString('zh-CN', {
|
||||
hour12: false
|
||||
})
|
||||
}
|
||||
|
||||
// 初始化图表
|
||||
const initCharts = () => {
|
||||
// 养殖品种分布饼图
|
||||
if (breedChart.value) {
|
||||
const chart = echarts.init(breedChart.value)
|
||||
chart.setOption({
|
||||
backgroundColor: 'transparent',
|
||||
series: [{
|
||||
type: 'pie',
|
||||
radius: ['40%', '70%'],
|
||||
data: [
|
||||
{ value: 35, name: '牛', itemStyle: { color: '#84acf0' } }, /* 地图顶部材质颜色 */
|
||||
{ value: 25, name: '羊', itemStyle: { color: '#7af4ff' } }, /* 地图光源颜色 */
|
||||
{ value: 20, name: '猪', itemStyle: { color: '#00F6FF' } }, /* 养殖场标签颜色 */
|
||||
{ value: 20, name: '其他', itemStyle: { color: '#123024' } } /* 地图侧面材质颜色 */
|
||||
],
|
||||
label: {
|
||||
color: '#fff',
|
||||
fontSize: 12
|
||||
}
|
||||
}]
|
||||
})
|
||||
}
|
||||
|
||||
// 全年文档管理统计图表
|
||||
if (docChart.value) {
|
||||
const chart = echarts.init(docChart.value)
|
||||
chart.setOption({
|
||||
backgroundColor: 'transparent',
|
||||
grid: {
|
||||
top: 20,
|
||||
right: 20,
|
||||
bottom: 30,
|
||||
left: 40
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: ['1月', '2月', '3月', '4月', '5月', '6月'],
|
||||
axisLabel: { color: '#fff', fontSize: 10 },
|
||||
axisLine: { lineStyle: { color: '#333' } }
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLabel: { color: '#fff', fontSize: 10 },
|
||||
axisLine: { lineStyle: { color: '#333' } },
|
||||
splitLine: { lineStyle: { color: '#333' } }
|
||||
},
|
||||
series: [{
|
||||
type: 'line',
|
||||
data: [50, 80, 65, 90, 120, 100],
|
||||
itemStyle: {
|
||||
color: '#7af4ff'
|
||||
},
|
||||
lineStyle: {
|
||||
color: '#7af4ff'
|
||||
}
|
||||
}]
|
||||
})
|
||||
}
|
||||
|
||||
// 每日资源统计柱状图
|
||||
if (dailyChart.value) {
|
||||
const chart = echarts.init(dailyChart.value)
|
||||
chart.setOption({
|
||||
backgroundColor: 'transparent',
|
||||
grid: {
|
||||
top: 20,
|
||||
right: 20,
|
||||
bottom: 30,
|
||||
left: 40
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
|
||||
axisLabel: { color: '#fff', fontSize: 10 },
|
||||
axisLine: { lineStyle: { color: '#333' } }
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLabel: { color: '#fff', fontSize: 10 },
|
||||
axisLine: { lineStyle: { color: '#333' } },
|
||||
splitLine: { lineStyle: { color: '#333' } }
|
||||
},
|
||||
series: [{
|
||||
type: 'bar',
|
||||
data: [120, 200, 150, 80, 70, 110, 130],
|
||||
itemStyle: {
|
||||
color: '#84acf0' /* 使用地图顶部材质颜色,移除渐变 */
|
||||
}
|
||||
}]
|
||||
})
|
||||
}
|
||||
|
||||
// 底部年度图表
|
||||
if (yearChart.value) {
|
||||
const chart = echarts.init(yearChart.value)
|
||||
chart.setOption({
|
||||
backgroundColor: 'transparent',
|
||||
grid: {
|
||||
top: 20,
|
||||
right: 20,
|
||||
bottom: 30,
|
||||
left: 40
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: ['Q1', 'Q2', 'Q3', 'Q4'],
|
||||
axisLabel: { color: '#fff', fontSize: 10 },
|
||||
axisLine: { lineStyle: { color: '#333' } }
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLabel: { color: '#fff', fontSize: 10 },
|
||||
axisLine: { lineStyle: { color: '#333' } },
|
||||
splitLine: { lineStyle: { color: '#333' } }
|
||||
},
|
||||
series: [{
|
||||
type: 'bar',
|
||||
data: [300, 450, 320, 520],
|
||||
itemStyle: {
|
||||
color: '#00F6FF'
|
||||
}
|
||||
}]
|
||||
})
|
||||
}
|
||||
|
||||
// 近七日资源统计
|
||||
if (weekChart.value) {
|
||||
const chart = echarts.init(weekChart.value)
|
||||
chart.setOption({
|
||||
backgroundColor: 'transparent',
|
||||
grid: {
|
||||
top: 20,
|
||||
right: 20,
|
||||
bottom: 30,
|
||||
left: 40
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: ['1日', '2日', '3日', '4日', '5日', '6日', '7日'],
|
||||
axisLabel: { color: '#fff', fontSize: 10 },
|
||||
axisLine: { lineStyle: { color: '#333' } }
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLabel: { color: '#fff', fontSize: 10 },
|
||||
axisLine: { lineStyle: { color: '#333' } },
|
||||
splitLine: { lineStyle: { color: '#333' } }
|
||||
},
|
||||
series: [{
|
||||
type: 'line',
|
||||
data: [80, 95, 110, 90, 120, 85, 130],
|
||||
itemStyle: {
|
||||
color: '#123024'
|
||||
},
|
||||
lineStyle: {
|
||||
color: '#123024'
|
||||
}
|
||||
}]
|
||||
})
|
||||
}
|
||||
|
||||
// 每日资源流入
|
||||
if (inflowChart.value) {
|
||||
const chart = echarts.init(inflowChart.value)
|
||||
chart.setOption({
|
||||
backgroundColor: 'transparent',
|
||||
series: [{
|
||||
type: 'pie',
|
||||
radius: ['30%', '60%'],
|
||||
data: [
|
||||
{ value: 40, name: '资金流入', itemStyle: { color: '#84acf0' } },
|
||||
{ value: 30, name: '物资流入', itemStyle: { color: '#7af4ff' } },
|
||||
{ value: 20, name: '设备流入', itemStyle: { color: '#00F6FF' } },
|
||||
{ value: 10, name: '其他', itemStyle: { color: '#123024' } }
|
||||
],
|
||||
label: {
|
||||
color: '#fff',
|
||||
fontSize: 10
|
||||
}
|
||||
}]
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
updateTime()
|
||||
timeInterval = setInterval(updateTime, 1000)
|
||||
|
||||
// 延迟初始化图表,确保DOM已渲染
|
||||
setTimeout(() => {
|
||||
initCharts()
|
||||
}, 100)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (timeInterval) {
|
||||
clearInterval(timeInterval)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.dashboard-container {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background: #0c1426; /* 移除渐变,使用地图基础深色 */
|
||||
color: #fff;
|
||||
font-family: 'Microsoft YaHei', sans-serif;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 科技感背景效果 */
|
||||
.dashboard-container::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background:
|
||||
rgba(132, 172, 240, 0.05),
|
||||
rgba(18, 48, 36, 0.05);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* 顶部标题栏 */
|
||||
.header {
|
||||
height: 80px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 40px;
|
||||
background: rgba(132, 172, 240, 0.1); /* 使用地图顶部材质颜色 */
|
||||
border-bottom: 2px solid #84acf0; /* 地图顶部材质颜色 */
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.header::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: -2px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 2px;
|
||||
background: #84acf0; /* 单色替代渐变 */
|
||||
animation: glow 2s ease-in-out infinite alternate;
|
||||
}
|
||||
|
||||
@keyframes glow {
|
||||
from { box-shadow: 0 0 5px rgba(132, 172, 240, 0.5); }
|
||||
to { box-shadow: 0 0 20px rgba(132, 172, 240, 0.8); }
|
||||
}
|
||||
|
||||
.title {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.main-title {
|
||||
font-size: 32px;
|
||||
font-weight: bold;
|
||||
color: #84acf0; /* 使用地图顶部材质颜色 */
|
||||
text-shadow: 0 0 20px rgba(132, 172, 240, 0.5);
|
||||
}
|
||||
|
||||
.sub-title {
|
||||
font-size: 16px;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.time-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 30px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.date, .time {
|
||||
color: #84acf0; /* 使用地图顶部材质颜色 */
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.weather {
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
|
||||
/* 主体内容 */
|
||||
.main-content {
|
||||
height: calc(100vh - 240px);
|
||||
display: flex;
|
||||
padding: 20px;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.left-panel, .right-panel {
|
||||
width: 350px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.center-panel {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* 面板样式 */
|
||||
.panel-section {
|
||||
background: rgba(132, 172, 240, 0.05); /* 使用地图颜色 */
|
||||
border: 1px solid rgba(132, 172, 240, 0.3);
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
backdrop-filter: blur(10px);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.panel-section::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 2px;
|
||||
background: #84acf0; /* 地图顶部材质颜色 */
|
||||
}
|
||||
|
||||
.section-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #84acf0; /* 使用地图顶部材质颜色 */
|
||||
margin-bottom: 15px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid rgba(132, 172, 240, 0.2);
|
||||
}
|
||||
|
||||
.title-icon {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
/* 统计数据网格 */
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
text-align: center;
|
||||
padding: 15px;
|
||||
background: rgba(18, 48, 36, 0.3); /* 使用地图侧面颜色 */
|
||||
border-radius: 6px;
|
||||
border: 1px solid rgba(132, 172, 240, 0.2);
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 12px;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
color: #84acf0; /* 使用地图顶部材质颜色 */
|
||||
}
|
||||
|
||||
.unit {
|
||||
font-size: 14px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
|
||||
/* 图表容器 */
|
||||
.chart-container {
|
||||
height: 200px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* 地图容器 */
|
||||
.map-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(18, 48, 36, 0.2); /* 使用地图侧面颜色 */
|
||||
border: 2px solid rgba(132, 172, 240, 0.3);
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.map-title {
|
||||
text-align: center;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
color: #84acf0; /* 使用地图顶部材质颜色 */
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.map-content {
|
||||
height: calc(100% - 80px);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.map-legend {
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.legend-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.legend-color {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
/* 资源列表 */
|
||||
.resource-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.resource-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.resource-name {
|
||||
width: 60px;
|
||||
font-size: 14px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
flex: 1;
|
||||
height: 8px;
|
||||
background: rgba(18, 48, 36, 0.3); /* 使用地图侧面颜色 */
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.progress {
|
||||
height: 100%;
|
||||
background: #84acf0; /* 单色替代渐变 */
|
||||
border-radius: 4px;
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
.resource-value {
|
||||
font-size: 12px;
|
||||
color: #84acf0; /* 使用地图顶部材质颜色 */
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* 底部面板 */
|
||||
.bottom-panel {
|
||||
height: 160px;
|
||||
display: flex;
|
||||
padding: 0 20px 20px;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.chart-section {
|
||||
flex: 1;
|
||||
background: rgba(132, 172, 240, 0.05); /* 使用地图颜色 */
|
||||
border: 1px solid rgba(132, 172, 240, 0.3);
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.chart-section::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 2px;
|
||||
background: #84acf0; /* 地图顶部材质颜色 */
|
||||
}
|
||||
|
||||
.chart-section .chart-container {
|
||||
height: calc(100% - 40px);
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 1920px) {
|
||||
.main-title { font-size: 28px; }
|
||||
.left-panel, .right-panel { width: 320px; }
|
||||
}
|
||||
|
||||
@media (max-width: 1600px) {
|
||||
.main-title { font-size: 24px; }
|
||||
.left-panel, .right-panel { width: 300px; }
|
||||
.stats-grid { grid-template-columns: 1fr; }
|
||||
}
|
||||
</style>
|
||||
218
datav-bank/src/components/FarmPopup.vue
Normal file
218
datav-bank/src/components/FarmPopup.vue
Normal file
@@ -0,0 +1,218 @@
|
||||
<template>
|
||||
<div v-if="visible" class="farm-popup-overlay" @click="closePopup">
|
||||
<div class="farm-popup" @click.stop>
|
||||
<div class="popup-header">
|
||||
<h3>{{ farm.name }}</h3>
|
||||
<button class="close-btn" @click="closePopup">×</button>
|
||||
</div>
|
||||
<div class="popup-content">
|
||||
<div class="farm-info">
|
||||
<div class="info-item">
|
||||
<!-- <span class="label">养殖类型:</span>
|
||||
<span class="value">{{ farm.type }}</span> -->
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">存栏数量:</span>
|
||||
<span class="value highlight">{{ farm.livestock.toLocaleString() }} 头</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">占地面积:</span>
|
||||
<span class="value">{{ farm.area }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">成立时间:</span>
|
||||
<span class="value">{{ farm.established }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">联系方式:</span>
|
||||
<span class="value">{{ farm.contact }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="popup-actions">
|
||||
<!-- <button class="action-btn primary">查看详情</button>
|
||||
<button class="action-btn secondary">联系养殖场</button> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'FarmPopup',
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
farm: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
emits: ['close'],
|
||||
methods: {
|
||||
closePopup() {
|
||||
this.$emit('close');
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.farm-popup-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 1000;
|
||||
backdrop-filter: blur(5px);
|
||||
}
|
||||
|
||||
.farm-popup {
|
||||
background: rgba(15, 25, 45, 0.95);
|
||||
border: 2px solid #00d4ff;
|
||||
border-radius: 12px;
|
||||
padding: 0;
|
||||
min-width: 400px;
|
||||
max-width: 500px;
|
||||
box-shadow:
|
||||
0 0 30px rgba(0, 212, 255, 0.3),
|
||||
inset 0 1px 0 rgba(255, 255, 255, 0.1);
|
||||
animation: popupSlideIn 0.3s ease-out;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@keyframes popupSlideIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scale(0.8) translateY(-20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scale(1) translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.popup-header {
|
||||
background: #00d4ff;
|
||||
padding: 15px 20px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid rgba(0, 212, 255, 0.3);
|
||||
}
|
||||
|
||||
.popup-header h3 {
|
||||
margin: 0;
|
||||
color: white;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
color: white;
|
||||
font-size: 24px;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.close-btn:hover {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.popup-content {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.farm-info {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 8px 0;
|
||||
border-bottom: 1px solid rgba(0, 212, 255, 0.1);
|
||||
}
|
||||
|
||||
.info-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.label {
|
||||
color: #a0a8b8;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.value {
|
||||
color: #ffffff;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.value.highlight {
|
||||
color: #00d4ff;
|
||||
font-size: 16px;
|
||||
text-shadow: 0 0 10px rgba(0, 212, 255, 0.5);
|
||||
}
|
||||
|
||||
.popup-actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
padding: 10px 20px;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.action-btn.primary {
|
||||
background: #00d4ff;
|
||||
color: white;
|
||||
box-shadow: 0 4px 15px rgba(0, 212, 255, 0.3);
|
||||
}
|
||||
|
||||
.action-btn.primary:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 20px rgba(0, 212, 255, 0.4);
|
||||
}
|
||||
|
||||
.action-btn.secondary {
|
||||
background: transparent;
|
||||
color: #00d4ff;
|
||||
border: 2px solid #00d4ff;
|
||||
}
|
||||
|
||||
.action-btn.secondary:hover {
|
||||
background: #00d4ff;
|
||||
color: white;
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
</style>
|
||||
1298
datav-bank/src/components/Home.vue
Normal file
1298
datav-bank/src/components/Home.vue
Normal file
File diff suppressed because it is too large
Load Diff
935
datav-bank/src/components/Map3D.vue
Normal file
935
datav-bank/src/components/Map3D.vue
Normal file
@@ -0,0 +1,935 @@
|
||||
<template>
|
||||
<div class="map-3d-container">
|
||||
<div id="app-32-map"></div>
|
||||
<FarmPopup
|
||||
:visible="showPopup"
|
||||
:farm="selectedFarmData"
|
||||
@close="closePopup"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Earth3d as BaseEarth } from '@/utils';
|
||||
import TWEEN from '@tweenjs/tween.js';
|
||||
import * as THREE from 'three';
|
||||
import { GUI } from 'three/examples/jsm/libs/lil-gui.module.min.js';
|
||||
import { onBeforeUnmount, onMounted, ref } from 'vue';
|
||||
import { random } from '@/utils';
|
||||
import useFileLoader from '@/hooks/useFileLoader.js';
|
||||
import useCountry from '@/hooks/useCountry.js';
|
||||
import useCoord from '@/hooks/useCoord.js';
|
||||
import useConversionStandardData from '@/hooks/useConversionStandardData.js';
|
||||
import useSequenceFrameAnimate from '@/hooks/useSequenceFrameAnimate';
|
||||
import useCSS2DRender from '@/hooks/useCSS2DRenderer';
|
||||
import { CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer';
|
||||
import FarmPopup from './FarmPopup.vue';
|
||||
|
||||
let centerXY = [106.2581, 38.4681]; // 宁夏回族自治区中心坐标
|
||||
|
||||
// 养殖场数据
|
||||
const farmData = [
|
||||
{
|
||||
id: 1,
|
||||
name: '东方养殖场',
|
||||
position: [106.8581, 38.8681], // 银川市附近
|
||||
livestock: 25234,
|
||||
area: '1200亩',
|
||||
type: '肉牛养殖',
|
||||
established: '2018年',
|
||||
contact: '张经理 138****1234'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: '西部牧场',
|
||||
position: [106.2581, 38.1181], // 吴忠市附近
|
||||
livestock: 32475,
|
||||
area: '1800亩',
|
||||
type: '奶牛养殖',
|
||||
established: '2016年',
|
||||
contact: '李经理 139****5678'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: '南山农场',
|
||||
position: [106.0581, 36.0681], // 固原市附近
|
||||
livestock: 28900,
|
||||
area: '1500亩',
|
||||
type: '肉牛养殖',
|
||||
established: '2019年',
|
||||
contact: '王经理 137****9012'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: '北岭牧业',
|
||||
position: [105.1881, 37.5181], // 中卫市附近
|
||||
livestock: 21100,
|
||||
area: '1000亩',
|
||||
type: '混合养殖',
|
||||
established: '2020年',
|
||||
contact: '赵经理 136****3456'
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: '中心养殖基地',
|
||||
position: [106.2581, 38.4681], // 保持中心位置(银川市中心)
|
||||
livestock: 19000,
|
||||
area: '900亩',
|
||||
type: '肉牛养殖',
|
||||
established: '2017年',
|
||||
contact: '陈经理 135****7890'
|
||||
}
|
||||
];
|
||||
|
||||
export default {
|
||||
name: '3dMap30',
|
||||
components: {
|
||||
FarmPopup
|
||||
},
|
||||
setup() {
|
||||
let baseEarth = null;
|
||||
let farmMarkers = []; // 存储养殖场标记
|
||||
let selectedFarm = null; // 当前选中的养殖场
|
||||
|
||||
// 弹窗状态管理
|
||||
const showPopup = ref(false);
|
||||
const selectedFarmData = ref(null);
|
||||
|
||||
// 重置
|
||||
const resize = () => {
|
||||
baseEarth.resize();
|
||||
};
|
||||
|
||||
const { requestData } = useFileLoader();
|
||||
const { transfromGeoJSON } = useConversionStandardData();
|
||||
const { getBoundingBox, geoSphereCoord } = useCoord();
|
||||
const { createCountryFlatLine } = useCountry();
|
||||
const { initCSS2DRender, create2DTag } = useCSS2DRender();
|
||||
// 序列帧
|
||||
const { createSequenceFrame } = useSequenceFrameAnimate();
|
||||
|
||||
const texture = new THREE.TextureLoader();
|
||||
const textureMap = texture.load('/data/map/gz-map.jpg');
|
||||
const texturefxMap = texture.load('/data/map/gz-map-fx.jpg');
|
||||
const rotatingApertureTexture = texture.load('/data/map/rotatingAperture.png');
|
||||
const rotatingPointTexture = texture.load('/data/map/rotating-point2.png');
|
||||
const circlePoint = texture.load('/data/map/circle-point.png');
|
||||
const sceneBg = texture.load('/data/map/scene-bg2.png');
|
||||
textureMap.wrapS = texturefxMap.wrapS = THREE.RepeatWrapping;
|
||||
textureMap.wrapT = texturefxMap.wrapT = THREE.RepeatWrapping;
|
||||
textureMap.flipY = texturefxMap.flipY = false;
|
||||
textureMap.rotation = texturefxMap.rotation = THREE.MathUtils.degToRad(45);
|
||||
const scale = 0.128;
|
||||
textureMap.repeat.set(scale, scale);
|
||||
texturefxMap.repeat.set(scale, scale);
|
||||
const topFaceMaterial = new THREE.MeshPhongMaterial({
|
||||
map: textureMap,
|
||||
color: '#84acf0',
|
||||
combine: THREE.MultiplyOperation,
|
||||
transparent: true,
|
||||
opacity: 1,
|
||||
});
|
||||
const sideMaterial = new THREE.MeshLambertMaterial({
|
||||
color: 0x123024,
|
||||
transparent: true,
|
||||
opacity: 0.9,
|
||||
});
|
||||
const bottomZ = -0.2;
|
||||
// 初始化gui
|
||||
// const initGui = () => {
|
||||
// const gui = new GUI();
|
||||
// const guiParams = {
|
||||
// topColor: '84acf0',
|
||||
// sideColor: '#123024',
|
||||
// scale:0.1,
|
||||
// };
|
||||
// gui.addColor(guiParams, 'topColor').onChange((val) => {
|
||||
// topFaceMaterial.color = new THREE.Color(val);
|
||||
// });
|
||||
// gui.addColor(guiParams, 'sideColor').onChange((val) => {
|
||||
// sideMaterial.color = new THREE.Color(val);
|
||||
// });
|
||||
// gui.add(guiParams, 'scale', 0, 1).onChange((val) => {
|
||||
// textureMap.repeat.set(val, val);
|
||||
// texturefxMap.repeat.set(val, val);
|
||||
// });
|
||||
// };
|
||||
// 初始化旋转光圈
|
||||
const initRotatingAperture = (scene, width) => {
|
||||
let plane = new THREE.PlaneGeometry(width, width);
|
||||
let material = new THREE.MeshBasicMaterial({
|
||||
map: rotatingApertureTexture,
|
||||
transparent: true,
|
||||
opacity: 1,
|
||||
depthTest: true,
|
||||
});
|
||||
let mesh = new THREE.Mesh(plane, material);
|
||||
mesh.position.set(...centerXY, 0);
|
||||
mesh.scale.set(1.1, 1.1, 1.1);
|
||||
scene.add(mesh);
|
||||
return mesh;
|
||||
};
|
||||
// 初始化旋转点
|
||||
const initRotatingPoint = (scene, width) => {
|
||||
let plane = new THREE.PlaneGeometry(width, width);
|
||||
let material = new THREE.MeshBasicMaterial({
|
||||
map: rotatingPointTexture,
|
||||
transparent: true,
|
||||
opacity: 1,
|
||||
depthTest: true,
|
||||
});
|
||||
let mesh = new THREE.Mesh(plane, material);
|
||||
mesh.position.set(...centerXY, bottomZ - 0.02);
|
||||
mesh.scale.set(1.1, 1.1, 1.1);
|
||||
scene.add(mesh);
|
||||
return mesh;
|
||||
};
|
||||
// 初始化背景
|
||||
const initSceneBg = (scene, width) => {
|
||||
let plane = new THREE.PlaneGeometry(width * 4, width * 4);
|
||||
let material = new THREE.MeshPhongMaterial({
|
||||
// color: 0x061920,
|
||||
color: '#2AF4FC',
|
||||
map: sceneBg,
|
||||
transparent: true,
|
||||
opacity: 1,
|
||||
depthTest: true,
|
||||
});
|
||||
|
||||
let mesh = new THREE.Mesh(plane, material);
|
||||
mesh.position.set(...centerXY, bottomZ - 0.2);
|
||||
scene.add(mesh);
|
||||
};
|
||||
// 初始化原点
|
||||
const initCirclePoint = (scene, width) => {
|
||||
let plane = new THREE.PlaneGeometry(width, width);
|
||||
let material = new THREE.MeshPhongMaterial({
|
||||
color: 0x00ffff,
|
||||
map: circlePoint,
|
||||
transparent: true,
|
||||
opacity: 1,
|
||||
// depthTest: false,
|
||||
});
|
||||
let mesh = new THREE.Mesh(plane, material);
|
||||
mesh.position.set(...centerXY, bottomZ - 0.1);
|
||||
// let mesh2 = mesh.clone()
|
||||
// mesh2.position.set(...centerXY, bottomZ - 0.001)
|
||||
scene.add(mesh);
|
||||
};
|
||||
// 初始化粒子
|
||||
const initParticle = (scene, bound) => {
|
||||
// 获取中心点和中间地图大小
|
||||
let { center, size } = bound;
|
||||
// 构建范围,中间地图的2倍
|
||||
let minX = center.x - size.x;
|
||||
let maxX = center.x + size.x;
|
||||
let minY = center.y - size.y;
|
||||
let maxY = center.y + size.y;
|
||||
let minZ = -6;
|
||||
let maxZ = 6;
|
||||
|
||||
let particleArr = [];
|
||||
for (let i = 0; i < 16; i++) {
|
||||
const particle = createSequenceFrame({
|
||||
image: './data/map/上升粒子1.png',
|
||||
width: 180,
|
||||
height: 189,
|
||||
frame: 9,
|
||||
column: 9,
|
||||
row: 1,
|
||||
speed: 0.5,
|
||||
});
|
||||
let particleScale = random(5, 10) / 1000;
|
||||
particle.scale.set(particleScale, particleScale, particleScale);
|
||||
particle.rotation.x = Math.PI / 2;
|
||||
let x = random(minX, maxX);
|
||||
let y = random(minY, maxY);
|
||||
let z = random(minZ, maxZ);
|
||||
particle.position.set(x, y, z);
|
||||
particleArr.push(particle);
|
||||
}
|
||||
scene.add(...particleArr);
|
||||
return particleArr;
|
||||
};
|
||||
// 创建顶部底部边线
|
||||
const initBorderLine = (data, mapGroup) => {
|
||||
let lineTop = createCountryFlatLine(
|
||||
data,
|
||||
{
|
||||
color: 0xffffff,
|
||||
linewidth: 0.0015,
|
||||
transparent: true,
|
||||
depthTest: false,
|
||||
},
|
||||
'Line2'
|
||||
);
|
||||
lineTop.position.z += 0.305;
|
||||
let lineBottom = createCountryFlatLine(
|
||||
data,
|
||||
{
|
||||
color: 0x61fbfd,
|
||||
linewidth: 0.002,
|
||||
// transparent: true,
|
||||
depthTest: false,
|
||||
},
|
||||
'Line2'
|
||||
);
|
||||
lineBottom.position.z -= 0.1905;
|
||||
// 添加边线
|
||||
mapGroup.add(lineTop);
|
||||
mapGroup.add(lineBottom);
|
||||
};
|
||||
|
||||
// 创建各市区边界线
|
||||
const initCityBorderLines = (data, mapGroup) => {
|
||||
// 为不同城市定义不同颜色
|
||||
const cityColors = {
|
||||
'银川市': 0x00ffff, // 青色
|
||||
'石嘴山市': 0xff6600, // 橙色
|
||||
'吴忠市': 0x0066ff, // 蓝色
|
||||
'固原市': 0xff0066, // 粉红色
|
||||
'中卫市': 0xffff00 // 黄色
|
||||
};
|
||||
|
||||
// console.log('开始创建城市边界线,数据:', data);
|
||||
|
||||
if (!data || !data.features) {
|
||||
// console.log('没有找到城市数据');
|
||||
return;
|
||||
}
|
||||
|
||||
data.features.forEach((feature, index) => {
|
||||
if (feature.geometry && feature.geometry.coordinates && feature.properties) {
|
||||
const cityName = feature.properties.name;
|
||||
const color = 0xffffff; // 统一设置为白色
|
||||
|
||||
// console.log(`创建城市边界线: ${cityName}`);
|
||||
|
||||
try {
|
||||
// 手动创建边界线,使用与地图相同的坐标处理方式
|
||||
const borderGroup = new THREE.Group();
|
||||
const coordinates = feature.geometry.coordinates;
|
||||
|
||||
coordinates.forEach((multiPolygon) => {
|
||||
multiPolygon.forEach((polygon) => {
|
||||
const points = [];
|
||||
|
||||
// 提取坐标点,与地图处理方式一致
|
||||
for (let i = 0; i < polygon.length; i++) {
|
||||
let [x, y] = polygon[i];
|
||||
points.push(new THREE.Vector3(x, y, 0.31)); // 设置z坐标稍高于地面
|
||||
}
|
||||
|
||||
if (points.length > 1) {
|
||||
// 创建线条几何体
|
||||
const geometry = new THREE.BufferGeometry().setFromPoints(points);
|
||||
const material = new THREE.LineBasicMaterial({
|
||||
color: color,
|
||||
transparent: true,
|
||||
opacity: 1.0,
|
||||
linewidth: 5
|
||||
});
|
||||
|
||||
const line = new THREE.Line(geometry, material);
|
||||
borderGroup.add(line);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (borderGroup.children.length > 0) {
|
||||
borderGroup.name = `cityBorder_${cityName}`;
|
||||
mapGroup.add(borderGroup);
|
||||
// console.log(`已添加城市边界线: ${cityName}, 线条数量: ${borderGroup.children.length}`);
|
||||
}
|
||||
} catch (error) {
|
||||
// console.error(`创建城市边界线时出错: ${cityName}`, error);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// console.log('城市边界线创建完成,mapGroup子对象数量:', mapGroup.children.length);
|
||||
};
|
||||
// 已移除光柱功能,使用养殖场标记点替代
|
||||
|
||||
// 初始化养殖场标记
|
||||
const initFarmMarkers = (mapGroup) => {
|
||||
console.log('开始初始化养殖场标记,数据:', farmData);
|
||||
|
||||
farmData.forEach((farm, index) => {
|
||||
const [lng, lat] = farm.position;
|
||||
console.log(`创建养殖场标记 ${index + 1}: ${farm.name}, 坐标: [${lng}, ${lat}]`);
|
||||
|
||||
// 创建球体几何体作为标记点
|
||||
const geometry = new THREE.SphereGeometry(0.1, 32, 32); // 显著增大球体尺寸
|
||||
const material = new THREE.MeshBasicMaterial({
|
||||
|
||||
color: 0x00F6FF, // 红色
|
||||
transparent: false,
|
||||
side: THREE.DoubleSide // 确保双面渲染
|
||||
});
|
||||
|
||||
const farmMarker = new THREE.Mesh(geometry, material);
|
||||
|
||||
// 使用与边界线相同的坐标处理方式
|
||||
farmMarker.position.set(lng, lat, 0.5); // 设置较高的z值确保可见
|
||||
|
||||
// 设置用户数据
|
||||
farmMarker.userData = { ...farm, type: 'farmMarker' };
|
||||
|
||||
// 添加到场景
|
||||
mapGroup.add(farmMarker);
|
||||
farmMarkers.push(farmMarker);
|
||||
|
||||
// 创建养殖场名称标签
|
||||
const labelDiv = document.createElement('div');
|
||||
labelDiv.className = 'farm-label';
|
||||
labelDiv.textContent = farm.name;
|
||||
labelDiv.style.cssText = `
|
||||
font-size: 18px;
|
||||
color: #00F6FF;
|
||||
font-weight: bold;
|
||||
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.8);
|
||||
background: rgba(0, 0, 0, 0.9);
|
||||
padding: 8px 16px;
|
||||
border-radius: 8px;
|
||||
border: 2px solid #00F6FF;
|
||||
white-space: nowrap;
|
||||
pointer-events: none;
|
||||
z-index: 10000;
|
||||
position: absolute;
|
||||
display: block !important;
|
||||
visibility: visible !important;
|
||||
opacity: 1 !important;
|
||||
transform: translate(-50%, -100%);
|
||||
`;
|
||||
|
||||
const label = new CSS2DObject(labelDiv);
|
||||
label.position.copy(farmMarker.position);
|
||||
label.position.z += 0.3; // 使用Z轴提升标签高度
|
||||
label.visible = true;
|
||||
|
||||
mapGroup.add(label);
|
||||
|
||||
console.log(`养殖场标签 ${index + 1} 创建:`, {
|
||||
name: farm.name,
|
||||
position: label.position,
|
||||
visible: label.visible,
|
||||
element: labelDiv,
|
||||
elementStyle: labelDiv.style.cssText
|
||||
});
|
||||
|
||||
console.log(`养殖场标记点和标签 ${index + 1} 已添加: ${farm.name},位置: [${lng}, ${lat}, 0.5]`);
|
||||
});
|
||||
|
||||
console.log(`养殖场标记初始化完成,共创建 ${farmData.length} 个标记点`);
|
||||
console.log('farmMarkers数组:', farmMarkers);
|
||||
|
||||
// 强制触发一次CSS2D渲染
|
||||
if (baseEarth && baseEarth.css2dRender && baseEarth.scene && baseEarth.camera) {
|
||||
console.log('强制触发CSS2D渲染器渲染');
|
||||
baseEarth.css2dRender.render(baseEarth.scene, baseEarth.camera);
|
||||
}
|
||||
|
||||
// 创建一个测试CSS2D标签
|
||||
const testLabelDiv = document.createElement('div');
|
||||
testLabelDiv.textContent = '测试标签';
|
||||
testLabelDiv.style.cssText = `
|
||||
font-size: 20px;
|
||||
color: #ff0000;
|
||||
font-weight: bold;
|
||||
background: rgba(255,255,255,0.9);
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
border: 2px solid #ff0000;
|
||||
pointer-events: none;
|
||||
`;
|
||||
|
||||
const testLabel = new CSS2DObject(testLabelDiv);
|
||||
testLabel.position.set(0, 0, 2); // 设置在场景中心上方
|
||||
testLabel.visible = true;
|
||||
|
||||
if (baseEarth && baseEarth.scene) {
|
||||
baseEarth.scene.add(testLabel);
|
||||
console.log('测试标签已添加到场景');
|
||||
}
|
||||
|
||||
// 在页面上显示调试信息
|
||||
const debugInfo = document.createElement('div');
|
||||
debugInfo.style.cssText = `
|
||||
position: fixed;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
background: rgba(0,0,0,0.8);
|
||||
color: white;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
font-size: 12px;
|
||||
z-index: 20000;
|
||||
max-width: 300px;
|
||||
`;
|
||||
// debugInfo.innerHTML = `
|
||||
// <div>养殖场标记数量: ${farmData.length}</div>
|
||||
// <div>mapGroup子对象数量: ${mapGroup.children.length}</div>
|
||||
// <div>CSS2D渲染器: ${baseEarth && baseEarth.css2dRender ? '已初始化' : '未初始化'}</div>
|
||||
// <div>测试标签已添加</div>
|
||||
// `;
|
||||
document.body.appendChild(debugInfo);
|
||||
|
||||
// 10秒后移除调试信息和测试标签
|
||||
setTimeout(() => {
|
||||
if (debugInfo.parentNode) {
|
||||
debugInfo.parentNode.removeChild(debugInfo);
|
||||
}
|
||||
if (baseEarth && baseEarth.scene && testLabel) {
|
||||
baseEarth.scene.remove(testLabel);
|
||||
}
|
||||
}, 10000);
|
||||
};
|
||||
|
||||
// 初始化养殖场点击事件处理
|
||||
const initFarmClickHandler = () => {
|
||||
console.log('开始初始化点击事件处理器');
|
||||
console.log('baseEarth:', baseEarth);
|
||||
console.log('baseEarth.container:', baseEarth.container);
|
||||
console.log('farmMarkers数量:', farmMarkers.length);
|
||||
|
||||
const raycaster = new THREE.Raycaster();
|
||||
const mouse = new THREE.Vector2();
|
||||
|
||||
const onMouseClick = (event) => {
|
||||
console.log('点击事件触发');
|
||||
|
||||
// 计算鼠标位置
|
||||
const rect = baseEarth.container.getBoundingClientRect();
|
||||
mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
|
||||
mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
|
||||
|
||||
console.log('鼠标坐标:', mouse.x, mouse.y);
|
||||
|
||||
// 设置射线
|
||||
raycaster.setFromCamera(mouse, baseEarth.camera);
|
||||
|
||||
// 检测与养殖场标记的交集
|
||||
const intersects = raycaster.intersectObjects(farmMarkers);
|
||||
|
||||
console.log('射线检测结果数量:', intersects.length);
|
||||
|
||||
if (intersects.length > 0) {
|
||||
const clickedMarker = intersects[0].object;
|
||||
console.log('点击了养殖场标记:', clickedMarker.userData.name);
|
||||
|
||||
if (clickedMarker.userData && clickedMarker.userData.type === 'farmMarker') {
|
||||
selectedFarm = clickedMarker.userData;
|
||||
showFarmPopup(clickedMarker.userData);
|
||||
}
|
||||
} else {
|
||||
console.log('未检测到养殖场标记点击');
|
||||
}
|
||||
};
|
||||
|
||||
baseEarth.container.addEventListener('click', onMouseClick);
|
||||
console.log('点击事件监听器已添加');
|
||||
};
|
||||
|
||||
// 显示养殖场弹窗
|
||||
const showFarmPopup = (farm) => {
|
||||
console.log('显示养殖场弹窗:', farm.name);
|
||||
selectedFarmData.value = farm;
|
||||
showPopup.value = true;
|
||||
};
|
||||
|
||||
// 关闭弹窗
|
||||
const closePopup = () => {
|
||||
showPopup.value = false;
|
||||
selectedFarmData.value = null;
|
||||
};
|
||||
// 创建标签
|
||||
const initLabel = (properties, scene) => {
|
||||
if(!properties.centroid && !properties.center && !properties.cp){
|
||||
// console.log('标签创建失败:缺少center、centroid或cp属性', properties.name);
|
||||
return false
|
||||
}
|
||||
// 设置标签的显示内容和位置
|
||||
let labelCenter = properties.center || properties.centroid || properties.cp;
|
||||
// console.log(`创建标签: ${properties.name}, 位置:`, labelCenter);
|
||||
|
||||
// 创建标签(使用简单参数,类似122222项目)
|
||||
var label = create2DTag(properties.name, 'map-32-label');
|
||||
scene.add(label);
|
||||
|
||||
// 调用show方法显示标签(参考122222项目的实现)
|
||||
label.show(properties.name, new THREE.Vector3(...labelCenter, 0.8));
|
||||
|
||||
// console.log(`标签创建并显示成功: ${properties.name}`);
|
||||
};
|
||||
onMounted(async () => {
|
||||
console.log('=== Map3D组件已挂载 ===');
|
||||
console.log('farmData:', farmData);
|
||||
// 等待DOM完全渲染
|
||||
await new Promise(resolve => setTimeout(resolve, 50));
|
||||
|
||||
// 检查容器尺寸但不阻止初始化
|
||||
const container = document.getElementById('app-32-map');
|
||||
// console.log('容器尺寸:', container ? `${container.offsetWidth}x${container.offsetHeight}` : '容器不存在');
|
||||
|
||||
if (container && (container.offsetWidth === 0 || container.offsetHeight === 0)) {
|
||||
// console.log('容器尺寸为0,但继续初始化...');
|
||||
// 减少等待时间,不阻止初始化
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
}
|
||||
|
||||
// 宁夏回族自治区数据
|
||||
let provinceData;
|
||||
try {
|
||||
provinceData = await requestData('./data/map/宁夏回族自治区.json');
|
||||
provinceData = transfromGeoJSON(provinceData);
|
||||
} catch (error) {
|
||||
// console.error('地图数据加载失败:', error);
|
||||
return; // 如果数据加载失败,直接返回
|
||||
}
|
||||
|
||||
class CurrentEarth extends BaseEarth {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.particleArr = []; // 初始化粒子数组
|
||||
}
|
||||
initCamera() {
|
||||
let { width, height } = this.options;
|
||||
let rate = width / height;
|
||||
// 设置45°的透视相机,更符合人眼观察
|
||||
this.camera = new THREE.PerspectiveCamera(45, rate, 0.001, 90000000);
|
||||
this.camera.up.set(0, 0, 1);
|
||||
// 宁夏
|
||||
this.camera.position.set(106.27777217804006, 35.660260562607277, 8.029548316292933); //相机在Three.js坐标系中的位置
|
||||
this.camera.lookAt(...centerXY, 0);
|
||||
}
|
||||
initModel() {
|
||||
try {
|
||||
// 创建组
|
||||
this.mapGroup = new THREE.Group();
|
||||
// 标签 初始化 - 确保使用有效的尺寸
|
||||
const validOptions = {
|
||||
...this.options,
|
||||
width: Math.max(this.options.width || this.container.offsetWidth || 800, 800),
|
||||
height: Math.max(this.options.height || this.container.offsetHeight || 600, 600)
|
||||
};
|
||||
this.css2dRender = initCSS2DRender(validOptions, this.container);
|
||||
|
||||
// 确保CSS2D渲染器的DOM元素有正确的样式
|
||||
this.css2dRender.domElement.style.zIndex = '10000'; // 确保在WebGL canvas之上
|
||||
this.css2dRender.domElement.style.pointerEvents = 'none';
|
||||
|
||||
console.log('CSS2D渲染器初始化完成:', {
|
||||
renderer: this.css2dRender,
|
||||
domElement: this.css2dRender.domElement,
|
||||
containerChildren: this.container.children.length
|
||||
});
|
||||
|
||||
// console.log('开始处理省份数据,features数量:', provinceData.features.length);
|
||||
provinceData.features.forEach((elem, index) => {
|
||||
// console.log(`处理第${index + 1}个feature:`, elem.properties.name);
|
||||
|
||||
// 定一个省份对象
|
||||
const province = new THREE.Object3D();
|
||||
// 坐标
|
||||
const coordinates = elem.geometry.coordinates;
|
||||
// city 属性
|
||||
const properties = elem.properties;
|
||||
|
||||
|
||||
// 循环坐标
|
||||
coordinates.forEach((multiPolygon) => {
|
||||
multiPolygon.forEach((polygon) => {
|
||||
|
||||
const shape = new THREE.Shape();
|
||||
// 绘制shape
|
||||
for (let i = 0; i < polygon.length; i++) {
|
||||
|
||||
let [x, y] = polygon[i];
|
||||
if (i === 0) {
|
||||
shape.moveTo(x, y);
|
||||
}
|
||||
shape.lineTo(x, y);
|
||||
}
|
||||
// 拉伸设置
|
||||
const extrudeSettings = {
|
||||
depth: 0.2,
|
||||
bevelEnabled: true,
|
||||
bevelSegments: 1,
|
||||
bevelThickness: 0.1,
|
||||
};
|
||||
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
|
||||
const mesh = new THREE.Mesh(geometry, [topFaceMaterial, sideMaterial]);
|
||||
province.add(mesh);
|
||||
});
|
||||
});
|
||||
this.mapGroup.add(province);
|
||||
// 创建标点和标签
|
||||
|
||||
initLabel(properties, this.scene);
|
||||
});
|
||||
// 创建上下边框
|
||||
initBorderLine(provinceData, this.mapGroup);
|
||||
|
||||
// 创建各市区边界线
|
||||
initCityBorderLines(provinceData, this.mapGroup);
|
||||
|
||||
let earthGroupBound = getBoundingBox(this.mapGroup);
|
||||
centerXY = [earthGroupBound.center.x, earthGroupBound.center.y];
|
||||
let { size } = earthGroupBound;
|
||||
let width = size.x < size.y ? size.y + 1 : size.x + 1;
|
||||
// 添加背景,修饰元素
|
||||
this.rotatingApertureMesh = initRotatingAperture(this.scene, width);
|
||||
this.rotatingPointMesh = initRotatingPoint(this.scene, width - 2);
|
||||
initCirclePoint(this.scene, width);
|
||||
initSceneBg(this.scene, width);
|
||||
|
||||
// 将组添加到场景中
|
||||
// console.log('将mapGroup添加到场景中,mapGroup子对象数量:', this.mapGroup.children.length);
|
||||
this.scene.add(this.mapGroup);
|
||||
// console.log('场景中对象数量:', this.scene.children.length);
|
||||
this.particleArr = initParticle(this.scene, earthGroupBound);
|
||||
// console.log('粒子系统初始化完成');
|
||||
|
||||
// 养殖场标记将在baseEarth.run()完成后初始化
|
||||
|
||||
// 更新相机目标到新的中心点
|
||||
this.camera.lookAt(...centerXY, 0);
|
||||
if (this.controls) {
|
||||
this.controls.target.set(...centerXY, 0);
|
||||
this.controls.update();
|
||||
}
|
||||
|
||||
initGui();
|
||||
} catch (error) {
|
||||
// console.log(error);
|
||||
}
|
||||
}
|
||||
getDataRenderMap() {}
|
||||
|
||||
destroy() {}
|
||||
initControls() {
|
||||
super.initControls();
|
||||
this.controls.target = new THREE.Vector3(...centerXY, 0);
|
||||
}
|
||||
initLight() {
|
||||
// 平行光1 - 主光源
|
||||
let directionalLight1 = new THREE.DirectionalLight(0x7af4ff, 1.2);
|
||||
directionalLight1.position.set(...centerXY, 50);
|
||||
directionalLight1.castShadow = false;
|
||||
|
||||
// 平行光2 - 辅助光源
|
||||
let directionalLight2 = new THREE.DirectionalLight(0x7af4ff, 0.8);
|
||||
directionalLight2.position.set(centerXY[0] + 20, centerXY[1] + 20, 40);
|
||||
directionalLight2.castShadow = false;
|
||||
|
||||
// 平行光3 - 顶部光源,增强边界线可见性
|
||||
let directionalLight3 = new THREE.DirectionalLight(0xffffff, 0.6);
|
||||
directionalLight3.position.set(...centerXY, 80);
|
||||
directionalLight3.castShadow = false;
|
||||
|
||||
// 环境光 - 增强整体亮度
|
||||
let ambientLight = new THREE.AmbientLight(0x7af4ff, 1.5);
|
||||
|
||||
// 将光源添加到场景中
|
||||
this.addObject(directionalLight1);
|
||||
this.addObject(directionalLight2);
|
||||
this.addObject(directionalLight3);
|
||||
this.addObject(ambientLight);
|
||||
}
|
||||
initRenderer() {
|
||||
super.initRenderer();
|
||||
// this.renderer.outputEncoding = THREE.sRGBEncoding
|
||||
}
|
||||
loop() {
|
||||
this.animationStop = window.requestAnimationFrame(() => {
|
||||
this.loop();
|
||||
});
|
||||
// 检查渲染器是否存在
|
||||
if (!this.renderer || !this.scene || !this.camera) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查渲染器尺寸是否有效(放宽检查条件)
|
||||
if (this.renderer.domElement && (this.renderer.domElement.width === 0 || this.renderer.domElement.height === 0)) {
|
||||
// 只在连续多帧都是0尺寸时才跳过渲染
|
||||
if (!this.zeroSizeFrameCount) this.zeroSizeFrameCount = 0;
|
||||
this.zeroSizeFrameCount++;
|
||||
if (this.zeroSizeFrameCount > 10) {
|
||||
// console.warn('渲染器canvas尺寸持续为0,跳过渲染');
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
this.zeroSizeFrameCount = 0;
|
||||
}
|
||||
|
||||
// 检查CSS2D渲染器是否有效(只检查是否存在,不检查尺寸)
|
||||
// CSS2DRenderer的domElement可能不会有正确的offsetWidth/offsetHeight
|
||||
|
||||
// 这里是你自己业务上需要的code
|
||||
this.renderer.render(this.scene, this.camera);
|
||||
// 控制相机旋转缩放的更新
|
||||
if (this.options.controls.visibel && this.controls) {
|
||||
this.controls.update();
|
||||
}
|
||||
// 统计更新 - 添加更严格的检查
|
||||
if (this.options.statsVisibel && this.stats && this.stats.dom) {
|
||||
// 检查Stats内部canvas是否有效
|
||||
const canvas = this.stats.dom.querySelector('canvas');
|
||||
if (canvas && canvas.width > 0 && canvas.height > 0) {
|
||||
this.stats.update();
|
||||
}
|
||||
}
|
||||
if (this.rotatingApertureMesh) {
|
||||
this.rotatingApertureMesh.rotation.z += 0.0005;
|
||||
}
|
||||
if (this.rotatingPointMesh) {
|
||||
this.rotatingPointMesh.rotation.z -= 0.0005;
|
||||
}
|
||||
// 渲染标签 - 使用CSS2D渲染器
|
||||
if (this.css2dRender && this.scene && this.camera) {
|
||||
this.css2dRender.render(this.scene, this.camera);
|
||||
// 每100帧输出一次调试信息
|
||||
if (this.frameCount === undefined) this.frameCount = 0;
|
||||
this.frameCount++;
|
||||
if (this.frameCount % 100 === 0) {
|
||||
console.log('CSS2D渲染器状态:', {
|
||||
renderer: !!this.css2dRender,
|
||||
scene: !!this.scene,
|
||||
camera: !!this.camera,
|
||||
sceneChildren: this.scene.children.length
|
||||
});
|
||||
}
|
||||
}
|
||||
// 粒子上升
|
||||
if (this.particleArr.length) {
|
||||
for (let i = 0; i < this.particleArr.length; i++) {
|
||||
this.particleArr[i].updateSequenceFrame();
|
||||
this.particleArr[i].position.z += 0.01;
|
||||
if (this.particleArr[i].position.z >= 6) {
|
||||
this.particleArr[i].position.z = -6;
|
||||
}
|
||||
}
|
||||
}
|
||||
TWEEN.update();
|
||||
}
|
||||
resize() {
|
||||
super.resize();
|
||||
|
||||
// 确保尺寸有效
|
||||
const validWidth = Math.max(this.options.width || 800, 800);
|
||||
const validHeight = Math.max(this.options.height || 600, 600);
|
||||
|
||||
// 更新options中的尺寸
|
||||
this.options.width = validWidth;
|
||||
this.options.height = validHeight;
|
||||
|
||||
// 确保渲染器已准备就绪再执行渲染
|
||||
if (this.renderer && this.scene && this.camera) {
|
||||
// 重新设置渲染器尺寸
|
||||
this.renderer.setSize(validWidth, validHeight);
|
||||
this.renderer.setPixelRatio(window.devicePixelRatio);
|
||||
// 这里是你自己业务上需要的code
|
||||
this.renderer.render(this.scene, this.camera);
|
||||
}
|
||||
|
||||
if (this.css2dRender) {
|
||||
this.css2dRender.setSize(validWidth, validHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
// console.log('开始创建Earth实例...');
|
||||
baseEarth = new CurrentEarth({
|
||||
container: '#app-32-map',
|
||||
axesVisibel: false,
|
||||
controls: {
|
||||
enableDamping: true, // 阻尼
|
||||
maxPolarAngle: (Math.PI / 2) * 0.98,
|
||||
},
|
||||
});
|
||||
// console.log('Earth实例创建完成,开始运行...');
|
||||
baseEarth.run();
|
||||
// console.log('Earth实例运行完成');
|
||||
|
||||
// 将CSS2D渲染器赋值给baseEarth实例,确保渲染循环中能正确访问
|
||||
if (baseEarth && baseEarth.css2dRender) {
|
||||
// CSS2D渲染器已经在CurrentEarth类中初始化了
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 初始化养殖场标记
|
||||
console.log('准备调用initFarmMarkers,mapGroup:', baseEarth.mapGroup);
|
||||
initFarmMarkers(baseEarth.mapGroup);
|
||||
console.log('initFarmMarkers调用完成,mapGroup子对象数量:', baseEarth.mapGroup.children.length);
|
||||
|
||||
// 初始化养殖场点击事件监听器
|
||||
initFarmClickHandler();
|
||||
|
||||
window.addEventListener('resize', resize);
|
||||
});
|
||||
|
||||
return {
|
||||
showPopup,
|
||||
selectedFarmData,
|
||||
closePopup,
|
||||
initFarmMarkers
|
||||
};
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener('resize', resize);
|
||||
if (baseEarth) {
|
||||
// 清理Three.js资源
|
||||
if (baseEarth.renderer) {
|
||||
baseEarth.renderer.dispose();
|
||||
}
|
||||
if (baseEarth.scene) {
|
||||
baseEarth.scene.clear();
|
||||
}
|
||||
// 停止动画循环
|
||||
if (baseEarth.animationStop) {
|
||||
cancelAnimationFrame(baseEarth.animationStop);
|
||||
}
|
||||
baseEarth = null;
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.map-3d-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#app-32-map {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.map-32-label {
|
||||
font-size: 10px;
|
||||
color: #fff;
|
||||
z-index: 10;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.farm-label {
|
||||
font-size: 16px;
|
||||
color: #00F6FF;
|
||||
font-weight: bold;
|
||||
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.8);
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
padding: 6px 12px;
|
||||
border-radius: 6px;
|
||||
border: 2px solid #00F6FF;
|
||||
white-space: nowrap;
|
||||
pointer-events: none;
|
||||
z-index: 1000;
|
||||
position: relative;
|
||||
display: block;
|
||||
visibility: visible !important;
|
||||
}
|
||||
</style>
|
||||
223
datav-bank/src/hooks/map/useMapMarkedLightPillar.js
Normal file
223
datav-bank/src/hooks/map/useMapMarkedLightPillar.js
Normal file
@@ -0,0 +1,223 @@
|
||||
import * as THREE from 'three'
|
||||
import TWEEN from '@tweenjs/tween.js'
|
||||
import useCoord from '@/hooks/useCoord'
|
||||
import { deepMerge, random } from '@/utils'
|
||||
/**
|
||||
*
|
||||
* @param {object} {
|
||||
* pointTextureUrl:标记点的图片url
|
||||
* lightHaloTextureUrl:光圈的URL
|
||||
* lightPillarUrl:光柱的URL
|
||||
* scaleFactor:1 缩放系数,用来调整标记点和光圈的缩放大小
|
||||
* }
|
||||
*
|
||||
* @returns
|
||||
*/
|
||||
export default function useMarkedLightPillar(options) {
|
||||
const { geoSphereCoord } = useCoord()
|
||||
// 默认参数
|
||||
let defaultOptions = {
|
||||
pointTextureUrl: './assets/texture/标注.png',
|
||||
lightHaloTextureUrl: './assets/texture/标注光圈.png',
|
||||
lightPillarUrl: './assets/texture/光柱.png',
|
||||
scaleFactor: 1, // 缩放系数
|
||||
}
|
||||
defaultOptions = deepMerge(defaultOptions, options)
|
||||
// 纹理加载器
|
||||
const textureLoader = new THREE.TextureLoader()
|
||||
// 射线拾取对象
|
||||
const raycaster = new THREE.Raycaster()
|
||||
let containerWidth = window.width
|
||||
let containerHeight = window.height
|
||||
// 对象属性
|
||||
let getBoundingClientRect = null
|
||||
/**
|
||||
* 创建标记点
|
||||
* @param {*} R 地球半径,根据R来进行缩放
|
||||
* @returns
|
||||
*/
|
||||
const createPointMesh = () => {
|
||||
// 标记点:几何体,材质,
|
||||
const geometry = new THREE.PlaneBufferGeometry(1, 1)
|
||||
const material = new THREE.MeshBasicMaterial({
|
||||
map: textureLoader.load(defaultOptions.pointTextureUrl),
|
||||
color: 0x00ffff,
|
||||
side: THREE.DoubleSide,
|
||||
transparent: true,
|
||||
depthWrite: false, //禁止写入深度缓冲区数据
|
||||
})
|
||||
let mesh = new THREE.Mesh(geometry, material)
|
||||
mesh.name = 'createPointMesh'
|
||||
// 缩放
|
||||
const scale = 0.15 * defaultOptions.scaleFactor
|
||||
mesh.scale.set(scale, scale, scale)
|
||||
return mesh
|
||||
}
|
||||
/**
|
||||
* 创建光圈
|
||||
* @param {*} R 地球半径,根据R来进行缩放
|
||||
* @returns
|
||||
*/
|
||||
const createLightHalo = () => {
|
||||
// 标记点:几何体,材质,
|
||||
const geometry = new THREE.PlaneBufferGeometry(1, 1)
|
||||
const material = new THREE.MeshBasicMaterial({
|
||||
map: textureLoader.load(defaultOptions.lightHaloTextureUrl),
|
||||
color: 0x00ffff,
|
||||
side: THREE.DoubleSide,
|
||||
opacity: 0,
|
||||
transparent: true,
|
||||
depthWrite: false, //禁止写入深度缓冲区数据
|
||||
})
|
||||
let mesh = new THREE.Mesh(geometry, material)
|
||||
mesh.name = 'createLightHalo'
|
||||
// 缩放
|
||||
const scale = 0.3 * defaultOptions.scaleFactor
|
||||
mesh.scale.set(scale, scale, scale)
|
||||
// 动画延迟时间
|
||||
const delay = random(0, 2000)
|
||||
// 动画:透明度缩放动画
|
||||
mesh.tween1 = new TWEEN.Tween({ scale: scale, opacity: 0 })
|
||||
.to({ scale: scale * 1.5, opacity: 1 }, 1000)
|
||||
.delay(delay)
|
||||
.onUpdate(params => {
|
||||
let { scale, opacity } = params
|
||||
mesh.scale.set(scale, scale, scale)
|
||||
mesh.material.opacity = opacity
|
||||
})
|
||||
mesh.tween2 = new TWEEN.Tween({ scale: scale * 1.5, opacity: 1 })
|
||||
.to({ scale: scale * 2, opacity: 0 }, 1000)
|
||||
.onUpdate(params => {
|
||||
let { scale, opacity } = params
|
||||
mesh.scale.set(scale, scale, scale)
|
||||
mesh.material.opacity = opacity
|
||||
})
|
||||
mesh.tween1.chain(mesh.tween2)
|
||||
mesh.tween2.chain(mesh.tween1)
|
||||
mesh.tween1.start()
|
||||
return mesh
|
||||
}
|
||||
/**
|
||||
* 创建光柱
|
||||
* @param {*} lon
|
||||
* @param {*} lat
|
||||
* @param {*} heightScaleFactor 光柱高度的缩放系数
|
||||
* @returns
|
||||
*/
|
||||
const createLightPillar = (lon, lat, heightScaleFactor = 1) => {
|
||||
let group = new THREE.Group()
|
||||
// 柱体高度
|
||||
const height = heightScaleFactor
|
||||
// 柱体的geo,6.19=柱体图片高度/宽度的倍数
|
||||
const geometry = new THREE.PlaneBufferGeometry(height / 6.219, height)
|
||||
// 柱体旋转90度,垂直于Y轴
|
||||
geometry.rotateX(Math.PI / 2)
|
||||
// 柱体的z轴移动高度一半对齐中心点
|
||||
geometry.translate(0, 0, height / 2)
|
||||
// 柱子材质
|
||||
const material = new THREE.MeshBasicMaterial({
|
||||
map: textureLoader.load(defaultOptions.lightPillarUrl),
|
||||
color: 0x00ffff,
|
||||
transparent: true,
|
||||
depthWrite: false,
|
||||
side: THREE.DoubleSide,
|
||||
})
|
||||
// 光柱01
|
||||
let light01 = new THREE.Mesh(geometry, material)
|
||||
light01.name = 'createLightPillar01'
|
||||
// 光柱02:复制光柱01
|
||||
let light02 = light01.clone()
|
||||
light02.name = 'createLightPillar02'
|
||||
// 光柱02,旋转90°,跟 光柱01交叉
|
||||
light02.rotateZ(Math.PI / 2)
|
||||
// 创建底部标点
|
||||
const bottomMesh = createPointMesh()
|
||||
// 创建光圈
|
||||
const lightHalo = createLightHalo()
|
||||
// 将光柱和标点添加到组里
|
||||
group.add(bottomMesh, lightHalo, light01, light02)
|
||||
// 设置组对象的姿态
|
||||
// group = setMeshQuaternion(group, R, lon, lat)
|
||||
group.position.set(lon, lat, 0)
|
||||
return group
|
||||
}
|
||||
/**
|
||||
* 设置光柱颜色
|
||||
* @param {*} group
|
||||
* @param {*} color
|
||||
*/
|
||||
const setLightPillarColor = (group, color) => {
|
||||
group.children.forEach(item => {
|
||||
item.material.color = new THREE.Color(color)
|
||||
})
|
||||
}
|
||||
/**
|
||||
* 设置网格的位置及姿态
|
||||
* @param {*} mesh
|
||||
* @param {*} R
|
||||
* @param {*} lon
|
||||
* @param {*} lat
|
||||
* @returns
|
||||
*/
|
||||
const setMeshQuaternion = (mesh, R, lon, lat) => {
|
||||
const { x, y, z } = geoSphereCoord(R, lon, lat)
|
||||
mesh.position.set(x, y, z)
|
||||
// 姿态设置
|
||||
// mesh在球面上的法线方向(球心和球面坐标构成的方向向量)
|
||||
let meshVector = new THREE.Vector3(x, y, z).normalize()
|
||||
// mesh默认在XOY平面上,法线方向沿着z轴new THREE.Vector3(0, 0, 1)
|
||||
let normal = new THREE.Vector3(0, 0, 1)
|
||||
// 四元数属性.quaternion表示mesh的角度状态
|
||||
//.setFromUnitVectors();计算两个向量之间构成的四元数值
|
||||
mesh.quaternion.setFromUnitVectors(normal, meshVector)
|
||||
return mesh
|
||||
}
|
||||
/**
|
||||
* 射线拾取,返回选中的mesh
|
||||
* @param {*} event
|
||||
* @param {*} container
|
||||
* @param {*} camera
|
||||
* @param {*} mesh // 光柱group
|
||||
* @returns
|
||||
*/
|
||||
const getRaycasterObj = (event, container, camera, mesh) => {
|
||||
//屏幕坐标转WebGL标准设备坐标
|
||||
if (!getBoundingClientRect) {
|
||||
getBoundingClientRect = container.getBoundingClientRect()
|
||||
containerWidth = container.offsetWidth
|
||||
containerHeight = container.offsetHeight
|
||||
}
|
||||
var x = ((event.clientX - getBoundingClientRect.left) / containerWidth) * 2 - 1
|
||||
var y = -((event.clientY - getBoundingClientRect.top) / containerHeight) * 2 + 1
|
||||
|
||||
//通过鼠标单击位置标准设备坐标和相机参数计算射线投射器`Raycaster`的射线属性.ray
|
||||
raycaster.setFromCamera(new THREE.Vector2(x, y), camera)
|
||||
//返回.intersectObjects()参数中射线选中的网格模型对象
|
||||
// 未选中对象返回空数组[],选中一个数组1个元素,选中两个数组两个元素
|
||||
var intersects = raycaster.intersectObjects(mesh)
|
||||
return intersects
|
||||
}
|
||||
/**
|
||||
* 选择光柱,返回选择的对象
|
||||
* @param {*} event
|
||||
* @param {*} container
|
||||
* @param {*} camera
|
||||
* @param {*} mesh
|
||||
* @returns 返回选择的对象
|
||||
*/
|
||||
const chooseLightPillar = (event, container, camera, mesh) => {
|
||||
event.preventDefault()
|
||||
// 获取拾取的对象数组
|
||||
let intersects = getRaycasterObj(event, container, camera, mesh)
|
||||
// 大于0说明,说明选中了mesh,返回对象
|
||||
if (intersects.length > 0) {
|
||||
return intersects[0]
|
||||
}
|
||||
return null
|
||||
}
|
||||
return {
|
||||
createLightPillar,
|
||||
setLightPillarColor,
|
||||
chooseLightPillar,
|
||||
}
|
||||
}
|
||||
80
datav-bank/src/hooks/useCSS2DRenderer.js
Normal file
80
datav-bank/src/hooks/useCSS2DRenderer.js
Normal file
@@ -0,0 +1,80 @@
|
||||
import { CSS2DObject, CSS2DRenderer } from 'three/examples/jsm/renderers/CSS2DRenderer'
|
||||
|
||||
export default function useCSS2DRender() {
|
||||
/**
|
||||
* 初始化CSS2D渲染器
|
||||
* @param {Object} options - 配置选项
|
||||
* @param {HTMLElement} container - 容器元素
|
||||
* @returns {CSS2DRenderer} CSS2D渲染器实例
|
||||
*/
|
||||
const initCSS2DRender = (options, container) => {
|
||||
const { width, height } = options
|
||||
|
||||
// 确保尺寸有效,避免Canvas尺寸为0的错误
|
||||
const validWidth = Math.max(width || 800, 1)
|
||||
const validHeight = Math.max(height || 600, 1)
|
||||
|
||||
let css2dRender = new CSS2DRenderer() // 实例化css2d渲染器
|
||||
css2dRender.setSize(validWidth, validHeight) // 设置渲染器的尺寸
|
||||
css2dRender.domElement.style.position = 'absolute' // 设置定位位置
|
||||
css2dRender.domElement.style.left = '0px'
|
||||
css2dRender.domElement.style.top = '0px'
|
||||
css2dRender.domElement.style.width = validWidth + 'px'
|
||||
css2dRender.domElement.style.height = validHeight + 'px'
|
||||
css2dRender.domElement.style.zIndex = '10000' // 确保在WebGL canvas之上
|
||||
css2dRender.domElement.style.pointerEvents = 'none' // 设置不能背选中
|
||||
css2dRender.domElement.style.overflow = 'visible' // 确保内容可见
|
||||
container.appendChild(css2dRender.domElement) // 插入到容器当中
|
||||
console.log('CSS2D渲染器DOM元素已插入容器');
|
||||
console.log('容器尺寸:', validWidth, 'x', validHeight);
|
||||
console.log('DOM元素样式:', css2dRender.domElement.style.cssText);
|
||||
return css2dRender
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建2d标签
|
||||
* @param {*} name 标签内容
|
||||
* @param {*} className 标签class
|
||||
* @returns
|
||||
*/
|
||||
const create2DTag = (name = '', className = '') => {
|
||||
let tag = document.createElement('div')
|
||||
tag.innerHTML = name
|
||||
tag.className = className
|
||||
tag.style.pointerEvents = 'none'
|
||||
tag.style.visibility = 'hidden'
|
||||
tag.style.position = 'absolute'
|
||||
// 如果className不存在,用以下样式
|
||||
if (!className) {
|
||||
tag.style.padding = '10px'
|
||||
tag.style.color = '#fff'
|
||||
tag.style.fontSize = '12px'
|
||||
tag.style.textAlign = 'center'
|
||||
tag.style.background = 'rgba(0,0,0,0.6)'
|
||||
tag.style.borderRadius = '4px'
|
||||
}
|
||||
let label = new CSS2DObject(tag)
|
||||
/**
|
||||
* 标签显示,
|
||||
* @param {*} name 显示内容
|
||||
* @param {*} point 显示坐标
|
||||
*/
|
||||
label.show = (name, point) => {
|
||||
label.element.innerHTML = name
|
||||
label.element.style.visibility = 'visible'
|
||||
label.position.copy(point)
|
||||
}
|
||||
/**
|
||||
* 隐藏
|
||||
*/
|
||||
label.hide = () => {
|
||||
label.element.style.visibility = 'hidden'
|
||||
}
|
||||
return label
|
||||
}
|
||||
|
||||
return {
|
||||
initCSS2DRender,
|
||||
create2DTag
|
||||
}
|
||||
}
|
||||
68
datav-bank/src/hooks/useConversionStandardData.js
Normal file
68
datav-bank/src/hooks/useConversionStandardData.js
Normal file
@@ -0,0 +1,68 @@
|
||||
export default function useConversionStandardData() {
|
||||
/**
|
||||
* 转换GeoJSON数据格式
|
||||
* 将Polygon类型转换为MultiPolygon格式
|
||||
* @param {Object} geoData - GeoJSON数据
|
||||
* @returns {Object} 转换后的数据
|
||||
*/
|
||||
const transfromGeoJSON = (geoData) => {
|
||||
if (!geoData || !geoData.features) {
|
||||
return geoData;
|
||||
}
|
||||
|
||||
const transformedFeatures = geoData.features.map(feature => {
|
||||
if (feature.geometry && feature.geometry.type === 'Polygon') {
|
||||
// 将Polygon转换为MultiPolygon格式
|
||||
return {
|
||||
...feature,
|
||||
geometry: {
|
||||
...feature.geometry,
|
||||
coordinates: [feature.geometry.coordinates] // 包装在数组中
|
||||
}
|
||||
};
|
||||
}
|
||||
return feature;
|
||||
});
|
||||
|
||||
return {
|
||||
...geoData,
|
||||
features: transformedFeatures
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* 转换道路GeoJSON数据格式
|
||||
* 将LineString类型转换为MultiLineString格式
|
||||
* @param {Object} geoData - GeoJSON道路数据
|
||||
* @returns {Object} 转换后的数据
|
||||
*/
|
||||
const transformGeoRoad = (geoData) => {
|
||||
if (!geoData || !geoData.features) {
|
||||
return geoData;
|
||||
}
|
||||
|
||||
const transformedFeatures = geoData.features.map(feature => {
|
||||
if (feature.geometry && feature.geometry.type === 'LineString') {
|
||||
// 将LineString转换为MultiLineString格式
|
||||
return {
|
||||
...feature,
|
||||
geometry: {
|
||||
...feature.geometry,
|
||||
coordinates: [feature.geometry.coordinates] // 包装在数组中
|
||||
}
|
||||
};
|
||||
}
|
||||
return feature;
|
||||
});
|
||||
|
||||
return {
|
||||
...geoData,
|
||||
features: transformedFeatures
|
||||
};
|
||||
};
|
||||
|
||||
return {
|
||||
transfromGeoJSON,
|
||||
transformGeoRoad
|
||||
};
|
||||
}
|
||||
92
datav-bank/src/hooks/useCoord.js
Normal file
92
datav-bank/src/hooks/useCoord.js
Normal file
@@ -0,0 +1,92 @@
|
||||
import * as THREE from 'three'
|
||||
const useCoord = () => {
|
||||
/**
|
||||
* 生成墨卡托坐标
|
||||
* @param {*} longitude 经度
|
||||
* @param {*} latitude 纬度
|
||||
* @returns
|
||||
*/
|
||||
// 墨卡托坐标系:展开地球,赤道作为x轴,向东为x轴正方,本初子午线作为y轴,向北为y轴正方向。
|
||||
// 数字20037508.34是地球赤道周长的一半:地球半径6378137米,赤道周长2*PI*r = 2 * 20037508.3427892,墨卡托坐标x轴区间[-20037508.3427892,20037508.3427892]
|
||||
const geoMercatorCoord = (longitude, latitude) => {
|
||||
var E = longitude
|
||||
var N = latitude
|
||||
var x = (E * 20037508.34) / 180
|
||||
var y = Math.log(Math.tan(((90 + N) * Math.PI) / 360)) / (Math.PI / 180)
|
||||
y = (y * 20037508.34) / 180
|
||||
return {
|
||||
x: x, //墨卡托x坐标——对应经度
|
||||
y: y, //墨卡托y坐标——对应维度
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 生成球面坐标
|
||||
* @param {*} R 球半径
|
||||
* @param {*} longitude 经度
|
||||
* @param {*} latitude 纬度
|
||||
* @returns
|
||||
*/
|
||||
const geoSphereCoord = (R, longitude, latitude) => {
|
||||
var lon = (longitude * Math.PI) / 180 //转弧度值
|
||||
var lat = (latitude * Math.PI) / 180 //转弧度值
|
||||
lon = -lon // three.js坐标系z坐标轴对应经度-90度,而不是90度
|
||||
|
||||
// 经纬度坐标转球面坐标计算公式
|
||||
var x = R * Math.cos(lat) * Math.cos(lon)
|
||||
var y = R * Math.sin(lat)
|
||||
var z = R * Math.cos(lat) * Math.sin(lon)
|
||||
// 返回球面坐标
|
||||
return {
|
||||
x: x,
|
||||
y: y,
|
||||
z: z,
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 计算包围盒
|
||||
* @param {*} group
|
||||
* @returns
|
||||
*/
|
||||
const getBoundingBox = group => {
|
||||
// 包围盒计算模型对象的大小和位置
|
||||
var box3 = new THREE.Box3()
|
||||
box3.expandByObject(group) // 计算模型包围盒
|
||||
var size = new THREE.Vector3()
|
||||
box3.getSize(size) // 计算包围盒尺寸
|
||||
var center = new THREE.Vector3()
|
||||
box3.getCenter(center) // 计算一个层级模型对应包围盒的几何体中心坐标
|
||||
return {
|
||||
box3,
|
||||
center,
|
||||
size,
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 设置网格的位置及姿态
|
||||
* @param {*} mesh
|
||||
* @param {*} R
|
||||
* @param {*} lon
|
||||
* @param {*} lat
|
||||
* @returns
|
||||
*/
|
||||
const setMeshQuaternion = (mesh, R, lon, lat) => {
|
||||
const { x, y, z } = geoSphereCoord(R, lon, lat)
|
||||
mesh.position.set(x, y, z)
|
||||
// 姿态设置
|
||||
// mesh在球面上的法线方向(球心和球面坐标构成的方向向量)
|
||||
let meshVector = new THREE.Vector3(x, y, z).normalize()
|
||||
// mesh默认在XOY平面上,法线方向沿着z轴new THREE.Vector3(0, 0, 1)
|
||||
let normal = new THREE.Vector3(0, 0, 1)
|
||||
// 四元数属性.quaternion表示mesh的角度状态
|
||||
//.setFromUnitVectors();计算两个向量之间构成的四元数值
|
||||
mesh.quaternion.setFromUnitVectors(normal, meshVector)
|
||||
return mesh
|
||||
}
|
||||
return {
|
||||
geoMercatorCoord,
|
||||
geoSphereCoord,
|
||||
getBoundingBox,
|
||||
setMeshQuaternion,
|
||||
}
|
||||
}
|
||||
export default useCoord
|
||||
143
datav-bank/src/hooks/useCountry.js
Normal file
143
datav-bank/src/hooks/useCountry.js
Normal file
@@ -0,0 +1,143 @@
|
||||
import * as THREE from 'three';
|
||||
import { Line2 } from 'three/examples/jsm/lines/Line2.js';
|
||||
import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial.js';
|
||||
import { LineGeometry } from 'three/examples/jsm/lines/LineGeometry.js';
|
||||
|
||||
export default function useCountry() {
|
||||
/**
|
||||
* 创建国家边界线
|
||||
* @param {Object} data - GeoJSON数据
|
||||
* @param {Object} options - 线条样式选项
|
||||
* @param {string} lineType - 线条类型 ('Line', 'LineLoop', 'LineSegments', 'Line2')
|
||||
* @returns {THREE.Object3D} 线条对象
|
||||
*/
|
||||
const createCountryFlatLine = (data, options = {}, lineType = 'Line') => {
|
||||
const group = new THREE.Group();
|
||||
|
||||
if (!data || !data.features) {
|
||||
return group;
|
||||
}
|
||||
|
||||
data.features.forEach(feature => {
|
||||
if (feature.geometry && feature.geometry.coordinates) {
|
||||
const coordinates = feature.geometry.coordinates;
|
||||
|
||||
coordinates.forEach(multiPolygon => {
|
||||
multiPolygon.forEach(polygon => {
|
||||
const points = [];
|
||||
|
||||
// 提取坐标点
|
||||
polygon.forEach(coord => {
|
||||
if (Array.isArray(coord) && coord.length >= 2) {
|
||||
points.push(new THREE.Vector3(coord[0], coord[1], 0));
|
||||
}
|
||||
});
|
||||
|
||||
if (points.length > 0) {
|
||||
const line = createLine(points, options, lineType);
|
||||
if (line) {
|
||||
group.add(line);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return group;
|
||||
};
|
||||
|
||||
/**
|
||||
* 创建线条对象
|
||||
* @param {Array<THREE.Vector3>} points - 点数组
|
||||
* @param {Object} options - 样式选项
|
||||
* @param {string} lineType - 线条类型
|
||||
* @returns {THREE.Object3D} 线条对象
|
||||
*/
|
||||
const createLine = (points, options = {}, lineType = 'Line') => {
|
||||
if (!points || points.length < 2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const defaultOptions = {
|
||||
color: 0xffffff,
|
||||
linewidth: 0.001,
|
||||
transparent: true,
|
||||
opacity: 1,
|
||||
depthTest: true
|
||||
};
|
||||
|
||||
const finalOptions = { ...defaultOptions, ...options };
|
||||
|
||||
try {
|
||||
switch (lineType) {
|
||||
case 'Line2': {
|
||||
// 使用Line2创建更高质量的线条
|
||||
const geometry = new LineGeometry();
|
||||
const positions = [];
|
||||
|
||||
points.forEach(point => {
|
||||
positions.push(point.x, point.y, point.z);
|
||||
});
|
||||
|
||||
geometry.setPositions(positions);
|
||||
|
||||
const material = new LineMaterial({
|
||||
color: finalOptions.color,
|
||||
linewidth: finalOptions.linewidth,
|
||||
transparent: finalOptions.transparent,
|
||||
opacity: finalOptions.opacity,
|
||||
depthTest: finalOptions.depthTest
|
||||
});
|
||||
|
||||
// 设置分辨率
|
||||
material.resolution.set(window.innerWidth, window.innerHeight);
|
||||
|
||||
return new Line2(geometry, material);
|
||||
}
|
||||
|
||||
case 'LineLoop': {
|
||||
const geometry = new THREE.BufferGeometry().setFromPoints(points);
|
||||
const material = new THREE.LineBasicMaterial({
|
||||
color: finalOptions.color,
|
||||
transparent: finalOptions.transparent,
|
||||
opacity: finalOptions.opacity,
|
||||
depthTest: finalOptions.depthTest
|
||||
});
|
||||
return new THREE.LineLoop(geometry, material);
|
||||
}
|
||||
|
||||
case 'LineSegments': {
|
||||
const geometry = new THREE.BufferGeometry().setFromPoints(points);
|
||||
const material = new THREE.LineBasicMaterial({
|
||||
color: finalOptions.color,
|
||||
transparent: finalOptions.transparent,
|
||||
opacity: finalOptions.opacity,
|
||||
depthTest: finalOptions.depthTest
|
||||
});
|
||||
return new THREE.LineSegments(geometry, material);
|
||||
}
|
||||
|
||||
default: // 'Line'
|
||||
case 'Line': {
|
||||
const geometry = new THREE.BufferGeometry().setFromPoints(points);
|
||||
const material = new THREE.LineBasicMaterial({
|
||||
color: finalOptions.color,
|
||||
transparent: finalOptions.transparent,
|
||||
opacity: finalOptions.opacity,
|
||||
depthTest: finalOptions.depthTest
|
||||
});
|
||||
return new THREE.Line(geometry, material);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error creating line:', error);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
createCountryFlatLine,
|
||||
createLine
|
||||
};
|
||||
}
|
||||
60
datav-bank/src/hooks/useFileLoader.js
Normal file
60
datav-bank/src/hooks/useFileLoader.js
Normal file
@@ -0,0 +1,60 @@
|
||||
import { ref } from 'vue';
|
||||
import * as THREE from 'three';
|
||||
|
||||
export default function useFileLoader() {
|
||||
const loading = ref(false);
|
||||
const progress = ref(0);
|
||||
const error = ref(null);
|
||||
|
||||
const requestData = async (url) => {
|
||||
loading.value = true;
|
||||
error.value = null;
|
||||
progress.value = 0;
|
||||
|
||||
try {
|
||||
const loader = new THREE.FileLoader();
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
loader.load(
|
||||
url,
|
||||
// onLoad
|
||||
(data) => {
|
||||
try {
|
||||
const jsonData = JSON.parse(data);
|
||||
loading.value = false;
|
||||
progress.value = 100;
|
||||
resolve(jsonData);
|
||||
} catch (parseError) {
|
||||
error.value = parseError;
|
||||
loading.value = false;
|
||||
reject(parseError);
|
||||
}
|
||||
},
|
||||
// onProgress
|
||||
(progressEvent) => {
|
||||
if (progressEvent.lengthComputable) {
|
||||
progress.value = (progressEvent.loaded / progressEvent.total) * 100;
|
||||
}
|
||||
},
|
||||
// onError
|
||||
(err) => {
|
||||
error.value = err;
|
||||
loading.value = false;
|
||||
reject(err);
|
||||
}
|
||||
);
|
||||
});
|
||||
} catch (err) {
|
||||
error.value = err;
|
||||
loading.value = false;
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
loading,
|
||||
progress,
|
||||
error,
|
||||
requestData
|
||||
};
|
||||
}
|
||||
234
datav-bank/src/hooks/useMapMarkedLightPillar.js
Normal file
234
datav-bank/src/hooks/useMapMarkedLightPillar.js
Normal file
@@ -0,0 +1,234 @@
|
||||
import * as THREE from 'three';
|
||||
import TWEEN from '@tweenjs/tween.js';
|
||||
|
||||
export default function useMapMarkedLightPillar(options = {}) {
|
||||
const defaultOptions = {
|
||||
scaleFactor: 1.0,
|
||||
color: 0x00ffff,
|
||||
opacity: 0.8
|
||||
};
|
||||
|
||||
const config = { ...defaultOptions, ...options };
|
||||
|
||||
/**
|
||||
* 创建标记点网格
|
||||
* @param {number} x - X坐标
|
||||
* @param {number} y - Y坐标
|
||||
* @param {number} scaleFactor - 缩放因子
|
||||
* @returns {THREE.Mesh} 标记点网格
|
||||
*/
|
||||
const createPointMesh = (x, y, scaleFactor = 1) => {
|
||||
const geometry = new THREE.SphereGeometry(0.05, 16, 16);
|
||||
const material = new THREE.MeshBasicMaterial({
|
||||
color: config.color,
|
||||
transparent: true,
|
||||
opacity: config.opacity
|
||||
});
|
||||
|
||||
const mesh = new THREE.Mesh(geometry, material);
|
||||
mesh.position.set(x, y, 0);
|
||||
mesh.scale.set(scaleFactor, scaleFactor, scaleFactor);
|
||||
|
||||
return mesh;
|
||||
};
|
||||
|
||||
/**
|
||||
* 创建光晕效果
|
||||
* @param {number} x - X坐标
|
||||
* @param {number} y - Y坐标
|
||||
* @param {number} scaleFactor - 缩放因子
|
||||
* @returns {THREE.Mesh} 光晕网格
|
||||
*/
|
||||
const createLightHalo = (x, y, scaleFactor = 1) => {
|
||||
// 创建光晕纹理 - 使用单色替代渐变
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = 256;
|
||||
canvas.height = 256;
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
// 绘制圆形光晕,中心实色,边缘透明
|
||||
ctx.fillStyle = 'rgba(0, 255, 255, 0.6)';
|
||||
ctx.beginPath();
|
||||
ctx.arc(128, 128, 64, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
|
||||
// 外圈较淡的圆
|
||||
ctx.fillStyle = 'rgba(0, 255, 255, 0.2)';
|
||||
ctx.beginPath();
|
||||
ctx.arc(128, 128, 100, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
|
||||
const texture = new THREE.CanvasTexture(canvas);
|
||||
|
||||
const geometry = new THREE.PlaneGeometry(0.5, 0.5);
|
||||
const material = new THREE.MeshBasicMaterial({
|
||||
map: texture,
|
||||
transparent: true,
|
||||
opacity: 0.6,
|
||||
depthTest: false
|
||||
});
|
||||
|
||||
const mesh = new THREE.Mesh(geometry, material);
|
||||
mesh.position.set(x, y, 0.01);
|
||||
mesh.scale.set(scaleFactor, scaleFactor, scaleFactor);
|
||||
|
||||
// 添加缩放动画
|
||||
const animate = () => {
|
||||
new TWEEN.Tween(mesh.scale)
|
||||
.to({ x: scaleFactor * 1.5, y: scaleFactor * 1.5, z: scaleFactor * 1.5 }, 2000)
|
||||
.easing(TWEEN.Easing.Sinusoidal.InOut)
|
||||
.yoyo(true)
|
||||
.repeat(Infinity)
|
||||
.start();
|
||||
};
|
||||
|
||||
animate();
|
||||
|
||||
return mesh;
|
||||
};
|
||||
|
||||
/**
|
||||
* 创建光柱
|
||||
* @param {number} x - X坐标
|
||||
* @param {number} y - Y坐标
|
||||
* @param {number} heightScaleFactor - 高度缩放因子
|
||||
* @returns {THREE.Group} 光柱组
|
||||
*/
|
||||
const createLightPillar = (x, y, heightScaleFactor = 1) => {
|
||||
const group = new THREE.Group();
|
||||
|
||||
// 创建光柱纹理 - 使用单色替代渐变
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = 64;
|
||||
canvas.height = 256;
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
// 绘制实色光柱,中部较亮
|
||||
ctx.fillStyle = 'rgba(0, 255, 255, 0.8)';
|
||||
ctx.fillRect(0, 25, 64, 206); // 中部主体
|
||||
|
||||
// 上下边缘稍淡
|
||||
ctx.fillStyle = 'rgba(0, 255, 255, 0.4)';
|
||||
ctx.fillRect(0, 0, 64, 25); // 顶部
|
||||
ctx.fillRect(0, 231, 64, 25); // 底部
|
||||
|
||||
const texture = new THREE.CanvasTexture(canvas);
|
||||
|
||||
// 创建两个相交的平面形成光柱
|
||||
const height = 2 * heightScaleFactor;
|
||||
const width = 0.1;
|
||||
|
||||
// 第一个平面
|
||||
const geometry1 = new THREE.PlaneGeometry(width, height);
|
||||
const material = new THREE.MeshBasicMaterial({
|
||||
map: texture,
|
||||
transparent: true,
|
||||
opacity: 0.8,
|
||||
depthTest: false,
|
||||
side: THREE.DoubleSide
|
||||
});
|
||||
|
||||
const plane1 = new THREE.Mesh(geometry1, material);
|
||||
plane1.position.set(x, y, height / 2);
|
||||
|
||||
// 第二个平面(旋转90度)
|
||||
const plane2 = plane1.clone();
|
||||
plane2.rotation.z = Math.PI / 2;
|
||||
|
||||
// 底部光点
|
||||
const bottomMesh = createPointMesh(x, y, config.scaleFactor);
|
||||
|
||||
// 光晕效果
|
||||
const halo = createLightHalo(x, y, config.scaleFactor);
|
||||
|
||||
group.add(plane1);
|
||||
group.add(plane2);
|
||||
group.add(bottomMesh);
|
||||
group.add(halo);
|
||||
|
||||
return group;
|
||||
};
|
||||
|
||||
/**
|
||||
* 设置光柱颜色
|
||||
* @param {THREE.Group} lightPillar - 光柱组
|
||||
* @param {number} color - 颜色值
|
||||
*/
|
||||
const setLightPillarColor = (lightPillar, color) => {
|
||||
lightPillar.children.forEach(child => {
|
||||
if (child.material) {
|
||||
child.material.color.setHex(color);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 设置网格四元数(用于球面定位)
|
||||
* @param {THREE.Object3D} mesh - 网格对象
|
||||
* @param {number} lng - 经度
|
||||
* @param {number} lat - 纬度
|
||||
* @param {number} radius - 半径
|
||||
*/
|
||||
const setMeshQuaternion = (mesh, lng, lat, radius = 1) => {
|
||||
const phi = (90 - lat) * (Math.PI / 180);
|
||||
const theta = (lng + 180) * (Math.PI / 180);
|
||||
|
||||
const x = -(radius * Math.sin(phi) * Math.cos(theta));
|
||||
const z = radius * Math.sin(phi) * Math.sin(theta);
|
||||
const y = radius * Math.cos(phi);
|
||||
|
||||
mesh.position.set(x, y, z);
|
||||
mesh.lookAt(0, 0, 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取射线检测对象
|
||||
* @param {THREE.Camera} camera - 相机
|
||||
* @param {THREE.Vector2} mouse - 鼠标位置
|
||||
* @param {Array} objects - 检测对象数组
|
||||
* @returns {Array} 相交对象数组
|
||||
*/
|
||||
const getRaycasterObj = (camera, mouse, objects) => {
|
||||
const raycaster = new THREE.Raycaster();
|
||||
raycaster.setFromCamera(mouse, camera);
|
||||
return raycaster.intersectObjects(objects, true);
|
||||
};
|
||||
|
||||
/**
|
||||
* 选择光柱
|
||||
* @param {Event} event - 鼠标事件
|
||||
* @param {THREE.Camera} camera - 相机
|
||||
* @param {Array} lightPillars - 光柱数组
|
||||
* @param {HTMLElement} container - 容器元素
|
||||
* @returns {Object|null} 选中的光柱信息
|
||||
*/
|
||||
const chooseLightPillar = (event, camera, lightPillars, container) => {
|
||||
const rect = container.getBoundingClientRect();
|
||||
const mouse = new THREE.Vector2();
|
||||
|
||||
mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
|
||||
mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
|
||||
|
||||
const intersects = getRaycasterObj(camera, mouse, lightPillars);
|
||||
|
||||
if (intersects.length > 0) {
|
||||
return {
|
||||
object: intersects[0].object,
|
||||
point: intersects[0].point,
|
||||
distance: intersects[0].distance
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
return {
|
||||
createPointMesh,
|
||||
createLightHalo,
|
||||
createLightPillar,
|
||||
setLightPillarColor,
|
||||
setMeshQuaternion,
|
||||
getRaycasterObj,
|
||||
chooseLightPillar
|
||||
};
|
||||
}
|
||||
182
datav-bank/src/hooks/useSequenceFrameAnimate.js
Normal file
182
datav-bank/src/hooks/useSequenceFrameAnimate.js
Normal file
@@ -0,0 +1,182 @@
|
||||
import * as THREE from 'three';
|
||||
|
||||
export default function useSequenceFrameAnimate() {
|
||||
/**
|
||||
* 创建序列帧动画
|
||||
* @param {Object} options - 配置选项
|
||||
* @param {string} options.image - 图片路径
|
||||
* @param {number} options.width - 图片宽度
|
||||
* @param {number} options.height - 图片高度
|
||||
* @param {number} options.frame - 总帧数
|
||||
* @param {number} options.column - 列数
|
||||
* @param {number} options.row - 行数
|
||||
* @param {number} options.speed - 播放速度
|
||||
* @returns {THREE.Mesh} 序列帧网格对象
|
||||
*/
|
||||
const createSequenceFrame = (options = {}) => {
|
||||
const {
|
||||
image,
|
||||
width = 256,
|
||||
height = 256,
|
||||
frame = 16,
|
||||
column = 4,
|
||||
row = 4,
|
||||
speed = 1
|
||||
} = options;
|
||||
|
||||
// 创建几何体
|
||||
const geometry = new THREE.PlaneGeometry(1, 1);
|
||||
|
||||
// 加载纹理
|
||||
const texture = new THREE.TextureLoader().load(image);
|
||||
texture.wrapS = THREE.RepeatWrapping;
|
||||
texture.wrapT = THREE.RepeatWrapping;
|
||||
|
||||
// 计算单帧的UV偏移
|
||||
const frameWidth = 1 / column;
|
||||
const frameHeight = 1 / row;
|
||||
|
||||
// 设置初始UV偏移
|
||||
texture.repeat.set(frameWidth, frameHeight);
|
||||
texture.offset.set(0, 1 - frameHeight); // 从顶部开始
|
||||
|
||||
// 创建材质
|
||||
const material = new THREE.MeshBasicMaterial({
|
||||
map: texture,
|
||||
transparent: true,
|
||||
alphaTest: 0.1,
|
||||
side: THREE.DoubleSide
|
||||
});
|
||||
|
||||
// 创建网格
|
||||
const mesh = new THREE.Mesh(geometry, material);
|
||||
|
||||
// 添加动画属性
|
||||
mesh.currentFrame = 0;
|
||||
mesh.frameCount = frame;
|
||||
mesh.column = column;
|
||||
mesh.row = row;
|
||||
mesh.speed = speed;
|
||||
mesh.frameWidth = frameWidth;
|
||||
mesh.frameHeight = frameHeight;
|
||||
mesh.frameTimer = 0;
|
||||
|
||||
// 更新序列帧的方法
|
||||
mesh.updateSequenceFrame = function() {
|
||||
this.frameTimer += this.speed;
|
||||
|
||||
if (this.frameTimer >= 60 / this.frameCount) { // 假设60FPS
|
||||
this.frameTimer = 0;
|
||||
this.currentFrame = (this.currentFrame + 1) % this.frameCount;
|
||||
|
||||
// 计算当前帧在纹理中的位置
|
||||
const col = this.currentFrame % this.column;
|
||||
const row = Math.floor(this.currentFrame / this.column);
|
||||
|
||||
// 更新UV偏移
|
||||
this.material.map.offset.set(
|
||||
col * this.frameWidth,
|
||||
1 - (row + 1) * this.frameHeight // 从顶部开始
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// 设置帧的方法
|
||||
mesh.setFrame = function(frameIndex) {
|
||||
if (frameIndex >= 0 && frameIndex < this.frameCount) {
|
||||
this.currentFrame = frameIndex;
|
||||
|
||||
const col = frameIndex % this.column;
|
||||
const row = Math.floor(frameIndex / this.column);
|
||||
|
||||
this.material.map.offset.set(
|
||||
col * this.frameWidth,
|
||||
1 - (row + 1) * this.frameHeight
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// 播放动画的方法
|
||||
mesh.play = function() {
|
||||
this.isPlaying = true;
|
||||
};
|
||||
|
||||
// 暂停动画的方法
|
||||
mesh.pause = function() {
|
||||
this.isPlaying = false;
|
||||
};
|
||||
|
||||
// 停止动画的方法
|
||||
mesh.stop = function() {
|
||||
this.isPlaying = false;
|
||||
this.currentFrame = 0;
|
||||
this.setFrame(0);
|
||||
};
|
||||
|
||||
// 设置播放速度的方法
|
||||
mesh.setSpeed = function(newSpeed) {
|
||||
this.speed = newSpeed;
|
||||
};
|
||||
|
||||
// 默认开始播放
|
||||
mesh.isPlaying = true;
|
||||
|
||||
return mesh;
|
||||
};
|
||||
|
||||
/**
|
||||
* 创建简单的粒子序列帧动画
|
||||
* @param {Object} options - 配置选项
|
||||
* @returns {THREE.Mesh} 粒子网格对象
|
||||
*/
|
||||
const createParticleSequenceFrame = (options = {}) => {
|
||||
const {
|
||||
color = 0x00ffff,
|
||||
size = 0.1,
|
||||
opacity = 0.8
|
||||
} = options;
|
||||
|
||||
// 创建简单的粒子几何体
|
||||
const geometry = new THREE.SphereGeometry(size, 8, 8);
|
||||
|
||||
// 创建材质
|
||||
const material = new THREE.MeshBasicMaterial({
|
||||
color: color,
|
||||
transparent: true,
|
||||
opacity: opacity
|
||||
});
|
||||
|
||||
// 创建网格
|
||||
const mesh = new THREE.Mesh(geometry, material);
|
||||
|
||||
// 添加简单的闪烁动画
|
||||
mesh.animationTimer = 0;
|
||||
mesh.baseOpacity = opacity;
|
||||
|
||||
mesh.updateSequenceFrame = function() {
|
||||
this.animationTimer += 0.1;
|
||||
const opacity = this.baseOpacity * (0.5 + 0.5 * Math.sin(this.animationTimer));
|
||||
this.material.opacity = opacity;
|
||||
};
|
||||
|
||||
return mesh;
|
||||
};
|
||||
|
||||
/**
|
||||
* 批量更新序列帧动画
|
||||
* @param {Array<THREE.Mesh>} meshes - 网格数组
|
||||
*/
|
||||
const updateSequenceFrames = (meshes) => {
|
||||
meshes.forEach(mesh => {
|
||||
if (mesh.updateSequenceFrame && mesh.isPlaying !== false) {
|
||||
mesh.updateSequenceFrame();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
createSequenceFrame,
|
||||
createParticleSequenceFrame,
|
||||
updateSequenceFrames
|
||||
};
|
||||
}
|
||||
4
datav-bank/src/main.js
Normal file
4
datav-bank/src/main.js
Normal file
@@ -0,0 +1,4 @@
|
||||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
|
||||
createApp(App).mount('#app')
|
||||
302
datav-bank/src/utils/Earth.js
Normal file
302
datav-bank/src/utils/Earth.js
Normal file
@@ -0,0 +1,302 @@
|
||||
import * as THREE from 'three';
|
||||
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
|
||||
import Stats from 'three/examples/jsm/libs/stats.module';
|
||||
import TWEEN from '@tweenjs/tween.js';
|
||||
import { deepMerge, isType } from '@/utils';
|
||||
|
||||
export default class Earth3d {
|
||||
constructor(options = {}) {
|
||||
let defaultOptions = {
|
||||
isFull: true,
|
||||
container: null,
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight,
|
||||
bgColor: 0x000000,
|
||||
materialColor: 0xff0000,
|
||||
controls: {
|
||||
visibel: true, // 是否开启
|
||||
enableDamping: true, // 阻尼
|
||||
autoRotate: false, // 自动旋转
|
||||
maxPolarAngle: Math.PI, // 相机垂直旋转角度的上限
|
||||
},
|
||||
statsVisibel: true,
|
||||
axesVisibel: true,
|
||||
axesHelperSize: 250, // 左边尺寸
|
||||
};
|
||||
this.options = deepMerge(defaultOptions, options);
|
||||
this.container = document.querySelector(this.options.container);
|
||||
|
||||
// 确保容器尺寸有效,避免Canvas尺寸为0的错误
|
||||
this.options.width = Math.max(this.container.offsetWidth, 800);
|
||||
this.options.height = Math.max(this.container.offsetHeight, 600);
|
||||
|
||||
// 如果容器尺寸仍然为0,使用默认值
|
||||
if (this.options.width === 0 || this.options.height === 0) {
|
||||
this.options.width = 800;
|
||||
this.options.height = 600;
|
||||
}
|
||||
this.scene = new THREE.Scene(); // 场景
|
||||
this.camera = null; // 相机
|
||||
this.renderer = null; // 渲染器
|
||||
this.mesh = null; // 网格
|
||||
this.animationStop = null; // 用于停止动画
|
||||
this.controls = null; // 轨道控制器
|
||||
this.stats = null; // 统计
|
||||
|
||||
this.init();
|
||||
}
|
||||
init() {
|
||||
this.initStats();
|
||||
this.initCamera();
|
||||
this.initModel();
|
||||
this.initRenderer(); // 异步初始化,其他组件在continueInit中初始化
|
||||
}
|
||||
async initModel() {}
|
||||
|
||||
/**
|
||||
* 运行
|
||||
*/
|
||||
run() {
|
||||
// 如果渲染器已经准备好,直接开始循环
|
||||
if (this.renderer) {
|
||||
this.loop();
|
||||
} else {
|
||||
// 否则标记需要启动,等待渲染器创建完成
|
||||
this.shouldStart = true;
|
||||
}
|
||||
}
|
||||
// 循环
|
||||
loop() {
|
||||
// 检查渲染器是否存在
|
||||
if (!this.renderer) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.animationStop = window.requestAnimationFrame(() => {
|
||||
this.loop();
|
||||
});
|
||||
// 这里是你自己业务上需要的code
|
||||
this.renderer.render(this.scene, this.camera);
|
||||
// 控制相机旋转缩放的更新
|
||||
if (this.options.controls.visibel) this.controls.update();
|
||||
// 统计更新
|
||||
if (this.options.statsVisibel) this.stats.update();
|
||||
|
||||
TWEEN.update();
|
||||
}
|
||||
initCamera() {
|
||||
let { width, height } = this.options;
|
||||
let rate = width / height;
|
||||
// 设置45°的透视相机,更符合人眼观察
|
||||
this.camera = new THREE.PerspectiveCamera(45, rate, 0.1, 1500);
|
||||
// this.camera.position.set(-428.88, 861.97, -1438.0)
|
||||
this.camera.position.set(270.27, 173.24, 257.54);
|
||||
// this.camera.position.set(-102, 205, -342)
|
||||
|
||||
this.camera.lookAt(0, 0, 0);
|
||||
}
|
||||
/**
|
||||
* 初始化渲染器
|
||||
*/
|
||||
initRenderer() {
|
||||
let { width, height, bgColor } = this.options;
|
||||
|
||||
// 强制清理所有WebGL上下文
|
||||
if (this.renderer) {
|
||||
this.renderer.dispose();
|
||||
this.renderer.forceContextLoss();
|
||||
this.renderer = null;
|
||||
}
|
||||
|
||||
// 清理容器中现有的所有子元素
|
||||
while (this.container.firstChild) {
|
||||
this.container.removeChild(this.container.firstChild);
|
||||
}
|
||||
|
||||
// 强制垃圾回收
|
||||
if (window.gc) {
|
||||
window.gc();
|
||||
}
|
||||
|
||||
// 延迟创建新的渲染器,确保上下文完全释放
|
||||
setTimeout(() => {
|
||||
try {
|
||||
// 重新获取容器尺寸,确保有效
|
||||
const containerWidth = this.container.offsetWidth || window.innerWidth;
|
||||
const containerHeight = this.container.offsetHeight || window.innerHeight;
|
||||
|
||||
// 确保尺寸有效
|
||||
const validWidth = Math.max(containerWidth, 800);
|
||||
const validHeight = Math.max(containerHeight, 600);
|
||||
|
||||
// 更新options中的尺寸
|
||||
this.options.width = validWidth;
|
||||
this.options.height = validHeight;
|
||||
|
||||
// 创建一个新的canvas元素
|
||||
const canvas = document.createElement('canvas');
|
||||
let renderer = new THREE.WebGLRenderer({
|
||||
canvas: canvas,
|
||||
antialias: true,
|
||||
preserveDrawingBuffer: false,
|
||||
powerPreference: "high-performance"
|
||||
});
|
||||
|
||||
// 设置canvas的分辨率
|
||||
renderer.setPixelRatio(window.devicePixelRatio);
|
||||
// 设置canvas 的尺寸大小
|
||||
renderer.setSize(validWidth, validHeight);
|
||||
// 设置背景色
|
||||
renderer.setClearColor(bgColor, 1);
|
||||
// 设置canvas的z-index,确保CSS2D渲染器在其之上
|
||||
renderer.domElement.style.zIndex = '1';
|
||||
renderer.domElement.style.position = 'absolute';
|
||||
// 插入到dom中
|
||||
this.container.appendChild(renderer.domElement);
|
||||
this.renderer = renderer;
|
||||
|
||||
// 继续初始化其他组件
|
||||
this.continueInit();
|
||||
} catch (error) {
|
||||
console.error('WebGL渲染器创建失败:', error);
|
||||
// 创建一个错误提示
|
||||
const errorDiv = document.createElement('div');
|
||||
errorDiv.innerHTML = '3D渲染器初始化失败,请刷新页面重试';
|
||||
errorDiv.style.cssText = 'color: #ff6b6b; text-align: center; padding: 50px; font-size: 16px;';
|
||||
this.container.appendChild(errorDiv);
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
|
||||
continueInit() {
|
||||
// 原来在init方法中renderer初始化后的逻辑
|
||||
this.initLight();
|
||||
this.initStats();
|
||||
this.initControls();
|
||||
this.initAxes();
|
||||
|
||||
// 如果之前调用了run方法,现在启动循环
|
||||
if (this.shouldStart) {
|
||||
this.shouldStart = false;
|
||||
this.loop();
|
||||
}
|
||||
}
|
||||
initLight() {
|
||||
// 平行光1
|
||||
let directionalLight1 = new THREE.DirectionalLight(0xffffff, 0.6);
|
||||
directionalLight1.position.set(400, 200, 200);
|
||||
// 平行光2
|
||||
let directionalLight2 = new THREE.DirectionalLight(0xffffff, 0.6);
|
||||
directionalLight2.position.set(-400, -200, -300);
|
||||
// 环境光
|
||||
let ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
|
||||
// 将光源添加到场景中
|
||||
this.addObject(directionalLight1);
|
||||
this.addObject(directionalLight2);
|
||||
this.addObject(ambientLight);
|
||||
}
|
||||
|
||||
initStats() {
|
||||
if (!this.options.statsVisibel) return false;
|
||||
|
||||
// 确保容器有有效的尺寸
|
||||
if (!this.container || this.container.offsetWidth === 0 || this.container.offsetHeight === 0) {
|
||||
console.warn('Container not ready for stats initialization, skipping...');
|
||||
return false;
|
||||
}
|
||||
|
||||
this.stats = new Stats();
|
||||
|
||||
// 确保stats的DOM元素有正确的尺寸
|
||||
if (this.stats.dom) {
|
||||
this.stats.dom.style.position = 'absolute';
|
||||
this.stats.dom.style.top = '0px';
|
||||
this.stats.dom.style.left = '0px';
|
||||
this.stats.dom.style.zIndex = '100';
|
||||
}
|
||||
|
||||
this.container.appendChild(this.stats.dom);
|
||||
}
|
||||
initControls() {
|
||||
try {
|
||||
let {
|
||||
controls: { enableDamping, autoRotate, visibel, maxPolarAngle },
|
||||
} = this.options;
|
||||
if (!visibel) return false;
|
||||
// 轨道控制器,使相机围绕目标进行轨道运动(旋转|缩放|平移)
|
||||
this.controls = new OrbitControls(this.camera, this.renderer.domElement);
|
||||
this.controls.maxPolarAngle = maxPolarAngle;
|
||||
this.controls.autoRotate = autoRotate;
|
||||
this.controls.enableDamping = enableDamping;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
initAxes() {
|
||||
if (!this.options.axesVisibel) return false;
|
||||
var axes = new THREE.AxesHelper(this.options.axesHelperSize);
|
||||
this.addObject(axes);
|
||||
}
|
||||
|
||||
// 清空dom
|
||||
empty(elem) {
|
||||
while (elem && elem.lastChild) elem.removeChild(elem.lastChild);
|
||||
}
|
||||
/**
|
||||
* 添加对象到场景
|
||||
* @param {*} object {} []
|
||||
*/
|
||||
addObject(object) {
|
||||
if (isType('Array', object)) {
|
||||
this.scene.add(...object);
|
||||
} else {
|
||||
this.scene.add(object);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 移除对象
|
||||
* @param {*} object {} []
|
||||
*/
|
||||
removeObject(object) {
|
||||
if (isType('Array', object)) {
|
||||
object.map((item) => {
|
||||
item.geometry.dispose();
|
||||
});
|
||||
this.scene.remove(...object);
|
||||
} else {
|
||||
object.geometry.dispose();
|
||||
this.scene.remove(object);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 重置
|
||||
*/
|
||||
resize() {
|
||||
// 重新设置宽高
|
||||
let newWidth = this.container.offsetWidth || window.innerWidth;
|
||||
let newHeight = this.container.offsetHeight || window.innerHeight;
|
||||
|
||||
// 确保尺寸有效
|
||||
this.options.width = Math.max(newWidth, 800);
|
||||
this.options.height = Math.max(newHeight, 600);
|
||||
|
||||
if (this.renderer) {
|
||||
this.renderer.setSize(this.options.width, this.options.height);
|
||||
}
|
||||
// 重新设置相机的位置
|
||||
let rate = this.options.width / this.options.height;
|
||||
|
||||
// 必須設置相機的比例,重置的時候才不会变形
|
||||
this.camera.aspect = rate;
|
||||
|
||||
// 渲染器执行render方法的时候会读取相机对象的投影矩阵属性projectionMatrix
|
||||
// 但是不会每渲染一帧,就通过相机的属性计算投影矩阵(节约计算资源)
|
||||
// 如果相机的一些属性发生了变化,需要执行updateProjectionMatrix ()方法更新相机的投影矩阵
|
||||
this.camera.updateProjectionMatrix();
|
||||
|
||||
// 如果stats还没有初始化(可能之前容器尺寸为0),现在重新尝试初始化
|
||||
if (this.options.statsVisibel && !this.stats) {
|
||||
this.initStats();
|
||||
}
|
||||
}
|
||||
}
|
||||
292
datav-bank/src/utils/api-auth-guide.js
Normal file
292
datav-bank/src/utils/api-auth-guide.js
Normal file
@@ -0,0 +1,292 @@
|
||||
/**
|
||||
* API认证问题的解决指南
|
||||
* 本文件提供了解决API认证问题的常见方法和实现示例
|
||||
*/
|
||||
|
||||
/**
|
||||
* 一、常见的API认证机制
|
||||
*
|
||||
* 1. HTTP Basic Authentication(基本认证)
|
||||
* - 最简单的认证方式,将用户名和密码用Base64编码后放在请求头中
|
||||
* - 优点:实现简单
|
||||
* - 缺点:安全性较低,凭证容易被截获和解码
|
||||
* - 使用场景:内部系统或测试环境
|
||||
*
|
||||
* 2. Bearer Token(令牌认证)
|
||||
* - 服务器颁发一个令牌(通常是JWT格式),客户端在请求头中携带此令牌
|
||||
* - 优点:安全性较高,可以设置过期时间和权限范围
|
||||
* - 使用场景:大多数现代API
|
||||
*
|
||||
* 3. OAuth 2.0
|
||||
* - 授权框架,允许第三方应用在用户授权的情况下访问资源
|
||||
* - 包含多种授权流程:授权码、隐式授权、客户端凭证、密码凭证等
|
||||
* - 优点:安全性高,支持复杂的授权场景
|
||||
* - 使用场景:需要第三方应用访问用户数据的场景
|
||||
*
|
||||
* 4. API Key认证
|
||||
* - 客户端使用预先分配的API Key来标识自己
|
||||
* - 优点:实现简单,易于追踪使用情况
|
||||
* - 缺点:API Key如果泄露可能导致安全问题
|
||||
* - 使用场景:公开API或内部系统
|
||||
*/
|
||||
|
||||
/**
|
||||
* 二、Bearer Token认证的实现示例
|
||||
*
|
||||
* 在实际项目中,Bearer Token是最常用的认证方式之一。
|
||||
* 以下是一个完整的实现流程:
|
||||
*/
|
||||
|
||||
/**
|
||||
* 获取认证令牌
|
||||
* @param {string} username - 用户名
|
||||
* @param {string} password - 密码
|
||||
* @returns {Promise<string>} 认证令牌
|
||||
*/
|
||||
export async function getAuthToken(username, password) {
|
||||
try {
|
||||
const response = await fetch('https://ad.ningmuyun.com/bank/api/auth/login', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
username,
|
||||
password
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`登录失败: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
// 假设API返回的令牌字段为token
|
||||
return data.token;
|
||||
} catch (error) {
|
||||
console.error('获取认证令牌失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用Bearer Token调用API
|
||||
* @param {string} url - API地址
|
||||
* @param {string} token - 认证令牌
|
||||
* @param {Object} options - fetch选项
|
||||
* @returns {Promise<any>} API响应数据
|
||||
*/
|
||||
export async function fetchWithAuth(url, token, options = {}) {
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
...options,
|
||||
headers: {
|
||||
...options.headers,
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
credentials: 'include' // 包含Cookie(如果需要)
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
if (response.status === 401) {
|
||||
throw new Error('认证失败,请重新登录');
|
||||
}
|
||||
throw new Error(`API请求失败: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error('带认证的API请求失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 三、CORS跨域问题的处理方案
|
||||
*
|
||||
* 当API请求遇到CORS(跨域资源共享)问题时,可以采取以下解决方案:
|
||||
*/
|
||||
|
||||
/**
|
||||
* 1. 服务器端设置CORS头
|
||||
* 服务器需要在响应中添加以下头信息:
|
||||
* - Access-Control-Allow-Origin: 指定允许的源(域名)
|
||||
* - Access-Control-Allow-Methods: 指定允许的HTTP方法
|
||||
* - Access-Control-Allow-Headers: 指定允许的请求头
|
||||
* - Access-Control-Allow-Credentials: 是否允许携带凭证(如Cookie)
|
||||
*
|
||||
* 2. 使用代理服务器
|
||||
* - 在开发环境中,可以配置Vite、Webpack等构建工具的代理
|
||||
* - 在生产环境中,可以使用Nginx、Apache等服务器设置反向代理
|
||||
*
|
||||
* 3. 处理预检请求(OPTIONS请求)
|
||||
* - 对于复杂请求,浏览器会先发送OPTIONS请求检查服务器是否允许跨域
|
||||
* - 服务器需要正确响应OPTIONS请求
|
||||
*/
|
||||
|
||||
/**
|
||||
* Vite开发服务器代理配置示例
|
||||
* 在vite.config.js中添加以下配置:
|
||||
*
|
||||
* export default defineConfig({
|
||||
* server: {
|
||||
* proxy: {
|
||||
* '/api': {
|
||||
* target: 'https://ad.ningmuyun.com',
|
||||
* changeOrigin: true,
|
||||
* rewrite: (path) => path.replace(/^\/api/, '')
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* })
|
||||
*
|
||||
* 然后将API调用改为相对路径:
|
||||
* fetch('/api/bank/api/projects?page=1&limit=12&search=&status=')
|
||||
*/
|
||||
|
||||
/**
|
||||
* 四、实际项目中的最佳实践
|
||||
*/
|
||||
|
||||
export const apiAuthBestPractices = {
|
||||
// 1. 安全存储认证信息
|
||||
secureStorage: [
|
||||
'不要将令牌存储在本地存储(localStorage)中,容易受到XSS攻击',
|
||||
'使用HttpOnly Cookie存储令牌,防止JavaScript访问',
|
||||
'或者使用内存存储,并在页面刷新时重新获取令牌'
|
||||
],
|
||||
|
||||
// 2. 令牌管理
|
||||
tokenManagement: [
|
||||
'实现令牌过期自动刷新机制',
|
||||
'设置合理的令牌过期时间',
|
||||
'定期清理过期令牌'
|
||||
],
|
||||
|
||||
// 3. 请求处理
|
||||
requestHandling: [
|
||||
'为所有API请求添加超时处理',
|
||||
'实现请求重试机制',
|
||||
'添加请求进度显示'
|
||||
],
|
||||
|
||||
// 4. 错误处理
|
||||
errorHandling: [
|
||||
'统一处理认证错误(如401状态码)',
|
||||
'为用户提供清晰的错误提示',
|
||||
'记录详细的错误日志以便排查'
|
||||
]
|
||||
};
|
||||
|
||||
/**
|
||||
* 五、临时解决方案(当无法修改服务器配置时)
|
||||
*
|
||||
* 如果API提供者无法或不愿意修改CORS和认证配置,可以采取以下临时解决方案:
|
||||
*/
|
||||
|
||||
export const temporarySolutions = {
|
||||
// 1. 使用模拟数据
|
||||
mockData: '创建与API返回格式一致的模拟数据,用于开发和测试',
|
||||
|
||||
// 2. 使用公共代理服务
|
||||
publicProxy: '使用如cors-anywhere、https://api.allorigins.win等公共代理服务',
|
||||
|
||||
// 3. 浏览器插件
|
||||
browserExtensions: '开发环境下可以使用Allow CORS等浏览器插件临时解决跨域问题',
|
||||
|
||||
// 4. 本地代理服务器
|
||||
localProxy: '在本地启动一个简单的Node.js服务器作为代理,转发API请求'
|
||||
};
|
||||
|
||||
/**
|
||||
* 六、完整的认证流程示例
|
||||
*
|
||||
* 以下是一个在Vue应用中使用的完整认证流程示例:
|
||||
*/
|
||||
|
||||
/**
|
||||
* Vue应用中的认证服务示例
|
||||
*/
|
||||
export class AuthService {
|
||||
constructor() {
|
||||
this.token = null;
|
||||
this.tokenKey = 'auth_token';
|
||||
}
|
||||
|
||||
// 初始化认证服务
|
||||
init() {
|
||||
// 尝试从安全存储中恢复令牌
|
||||
const storedToken = this.getStoredToken();
|
||||
if (storedToken) {
|
||||
this.token = storedToken;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取存储的令牌(这里简化处理,实际应使用更安全的存储方式)
|
||||
getStoredToken() {
|
||||
try {
|
||||
return sessionStorage.getItem(this.tokenKey);
|
||||
} catch (error) {
|
||||
console.error('获取存储的令牌失败:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 存储令牌
|
||||
storeToken(token) {
|
||||
try {
|
||||
sessionStorage.setItem(this.tokenKey, token);
|
||||
this.token = token;
|
||||
} catch (error) {
|
||||
console.error('存储令牌失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// 清除令牌
|
||||
clearToken() {
|
||||
sessionStorage.removeItem(this.tokenKey);
|
||||
this.token = null;
|
||||
}
|
||||
|
||||
// 检查是否已认证
|
||||
isAuthenticated() {
|
||||
return !!this.token;
|
||||
}
|
||||
|
||||
// 登录
|
||||
async login(username, password) {
|
||||
try {
|
||||
const token = await getAuthToken(username, password);
|
||||
this.storeToken(token);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('登录失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// 登出
|
||||
logout() {
|
||||
this.clearToken();
|
||||
}
|
||||
|
||||
// 带认证的API请求
|
||||
async request(url, options = {}) {
|
||||
if (!this.token) {
|
||||
throw new Error('未认证,请先登录');
|
||||
}
|
||||
|
||||
try {
|
||||
return await fetchWithAuth(url, this.token, options);
|
||||
} catch (error) {
|
||||
// 处理认证失败
|
||||
if (error.message.includes('认证失败')) {
|
||||
this.clearToken();
|
||||
// 可以在这里触发重新登录流程
|
||||
throw new Error('认证已过期,请重新登录');
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
121
datav-bank/src/utils/index.js
Normal file
121
datav-bank/src/utils/index.js
Normal file
@@ -0,0 +1,121 @@
|
||||
// 引入Three.js
|
||||
export { default as Earth3d } from './Earth.js';
|
||||
|
||||
/**
|
||||
* 经纬度坐标转球面坐标
|
||||
* @param {地球半径} R
|
||||
* @param {经度(角度值)} longitude
|
||||
* @param {维度(角度值)} latitude
|
||||
*/
|
||||
export function lon2xyz(R, longitude, latitude) {
|
||||
var lon = (longitude * Math.PI) / 180; //转弧度值
|
||||
var lat = (latitude * Math.PI) / 180; //转弧度值
|
||||
lon = -lon; // three.js坐标系z坐标轴对应经度-90度,而不是90度
|
||||
|
||||
// 经纬度坐标转球面坐标计算公式
|
||||
var x = R * Math.cos(lat) * Math.cos(lon);
|
||||
var y = R * Math.sin(lat);
|
||||
var z = R * Math.cos(lat) * Math.sin(lon);
|
||||
// 返回球面坐标
|
||||
return {
|
||||
x: x,
|
||||
y: y,
|
||||
z: z,
|
||||
};
|
||||
}
|
||||
|
||||
export const isType = function (type, value) {
|
||||
return Object.prototype.toString.call(value) === `[object ${type}]`;
|
||||
};
|
||||
/**
|
||||
* 判断是否为对象
|
||||
*/
|
||||
export const isObject = function (value) {
|
||||
return isType('Object', value);
|
||||
};
|
||||
/**
|
||||
* @description deepClone() 深拷贝-最终版:解决循环引用的问题
|
||||
* @param {*} target 对象
|
||||
* @example
|
||||
* const obj1 = {
|
||||
* a: 1,
|
||||
* b: ["e", "f", "g"],
|
||||
* c: { h: { i: 2 } },
|
||||
* };
|
||||
* obj1.b.push(obj1.c);
|
||||
* obj1.c.j = obj1.b;
|
||||
*
|
||||
* const obj2 = deepClone(obj1);
|
||||
* obj2.b.push("h");
|
||||
* console.log(obj1, obj2);
|
||||
* console.log(obj2.c === obj1.c);
|
||||
*/
|
||||
export function deepClone(target, map = new Map()) {
|
||||
// target 不能为空,并且是一个对象
|
||||
if (target != null && isObject(target)) {
|
||||
// 在克隆数据前,进行判断是否克隆过,已克隆就返回克隆的值
|
||||
let cache = map.get(target);
|
||||
if (cache) {
|
||||
return cache;
|
||||
}
|
||||
// 判断是否为数组
|
||||
const isArray = Array.isArray(target);
|
||||
let result = isArray ? [] : {};
|
||||
// 将新结果存入缓存中
|
||||
cache = map.set(target, result);
|
||||
// 如果是数组
|
||||
if (isArray) {
|
||||
// 循环数组,
|
||||
target.forEach((item, index) => {
|
||||
// 如果item是对象,再次递归
|
||||
result[index] = deepClone(item, cache);
|
||||
});
|
||||
} else {
|
||||
// 如果是对象
|
||||
Object.keys(target).forEach((key) => {
|
||||
if (isObject(result[key])) {
|
||||
result[key] = deepClone(target[key], cache);
|
||||
} else {
|
||||
result[key] = target[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
return target;
|
||||
}
|
||||
}
|
||||
|
||||
export function deepMerge(target, source) {
|
||||
target = deepClone(target);
|
||||
for (let key in source) {
|
||||
if (key in target) {
|
||||
// 对象的处理
|
||||
if (isObject(source[key])) {
|
||||
if (!isObject(target[key])) {
|
||||
target[key] = source[key];
|
||||
} else {
|
||||
target[key] = deepMerge(target[key], source[key]);
|
||||
}
|
||||
} else {
|
||||
target[key] = source[key];
|
||||
}
|
||||
} else {
|
||||
target[key] = source[key];
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
// 随机数
|
||||
export const random = function (min, max) {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
};
|
||||
/**
|
||||
* 获取样式
|
||||
* @param {*} el
|
||||
* @param {*} ruleName
|
||||
* @returns
|
||||
*/
|
||||
export function getStyle(el, ruleName) {
|
||||
return window.getComputedStyle(el)[ruleName];
|
||||
}
|
||||
7
datav-bank/src/utils/lodash/_DataView.js
Normal file
7
datav-bank/src/utils/lodash/_DataView.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import getNative from './_getNative.js';
|
||||
import root from './_root.js';
|
||||
|
||||
/* Built-in method references that are verified to be native. */
|
||||
var DataView = getNative(root, 'DataView');
|
||||
|
||||
export default DataView;
|
||||
32
datav-bank/src/utils/lodash/_Hash.js
Normal file
32
datav-bank/src/utils/lodash/_Hash.js
Normal file
@@ -0,0 +1,32 @@
|
||||
import hashClear from './_hashClear.js';
|
||||
import hashDelete from './_hashDelete.js';
|
||||
import hashGet from './_hashGet.js';
|
||||
import hashHas from './_hashHas.js';
|
||||
import hashSet from './_hashSet.js';
|
||||
|
||||
/**
|
||||
* Creates a hash object.
|
||||
*
|
||||
* @private
|
||||
* @constructor
|
||||
* @param {Array} [entries] The key-value pairs to cache.
|
||||
*/
|
||||
function Hash(entries) {
|
||||
var index = -1,
|
||||
length = entries == null ? 0 : entries.length;
|
||||
|
||||
this.clear();
|
||||
while (++index < length) {
|
||||
var entry = entries[index];
|
||||
this.set(entry[0], entry[1]);
|
||||
}
|
||||
}
|
||||
|
||||
// Add methods to `Hash`.
|
||||
Hash.prototype.clear = hashClear;
|
||||
Hash.prototype['delete'] = hashDelete;
|
||||
Hash.prototype.get = hashGet;
|
||||
Hash.prototype.has = hashHas;
|
||||
Hash.prototype.set = hashSet;
|
||||
|
||||
export default Hash;
|
||||
28
datav-bank/src/utils/lodash/_LazyWrapper.js
Normal file
28
datav-bank/src/utils/lodash/_LazyWrapper.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import baseCreate from './_baseCreate.js';
|
||||
import baseLodash from './_baseLodash.js';
|
||||
|
||||
/** Used as references for the maximum length and index of an array. */
|
||||
var MAX_ARRAY_LENGTH = 4294967295;
|
||||
|
||||
/**
|
||||
* Creates a lazy wrapper object which wraps `value` to enable lazy evaluation.
|
||||
*
|
||||
* @private
|
||||
* @constructor
|
||||
* @param {*} value The value to wrap.
|
||||
*/
|
||||
function LazyWrapper(value) {
|
||||
this.__wrapped__ = value;
|
||||
this.__actions__ = [];
|
||||
this.__dir__ = 1;
|
||||
this.__filtered__ = false;
|
||||
this.__iteratees__ = [];
|
||||
this.__takeCount__ = MAX_ARRAY_LENGTH;
|
||||
this.__views__ = [];
|
||||
}
|
||||
|
||||
// Ensure `LazyWrapper` is an instance of `baseLodash`.
|
||||
LazyWrapper.prototype = baseCreate(baseLodash.prototype);
|
||||
LazyWrapper.prototype.constructor = LazyWrapper;
|
||||
|
||||
export default LazyWrapper;
|
||||
32
datav-bank/src/utils/lodash/_ListCache.js
Normal file
32
datav-bank/src/utils/lodash/_ListCache.js
Normal file
@@ -0,0 +1,32 @@
|
||||
import listCacheClear from './_listCacheClear.js';
|
||||
import listCacheDelete from './_listCacheDelete.js';
|
||||
import listCacheGet from './_listCacheGet.js';
|
||||
import listCacheHas from './_listCacheHas.js';
|
||||
import listCacheSet from './_listCacheSet.js';
|
||||
|
||||
/**
|
||||
* Creates an list cache object.
|
||||
*
|
||||
* @private
|
||||
* @constructor
|
||||
* @param {Array} [entries] The key-value pairs to cache.
|
||||
*/
|
||||
function ListCache(entries) {
|
||||
var index = -1,
|
||||
length = entries == null ? 0 : entries.length;
|
||||
|
||||
this.clear();
|
||||
while (++index < length) {
|
||||
var entry = entries[index];
|
||||
this.set(entry[0], entry[1]);
|
||||
}
|
||||
}
|
||||
|
||||
// Add methods to `ListCache`.
|
||||
ListCache.prototype.clear = listCacheClear;
|
||||
ListCache.prototype['delete'] = listCacheDelete;
|
||||
ListCache.prototype.get = listCacheGet;
|
||||
ListCache.prototype.has = listCacheHas;
|
||||
ListCache.prototype.set = listCacheSet;
|
||||
|
||||
export default ListCache;
|
||||
22
datav-bank/src/utils/lodash/_LodashWrapper.js
Normal file
22
datav-bank/src/utils/lodash/_LodashWrapper.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import baseCreate from './_baseCreate.js';
|
||||
import baseLodash from './_baseLodash.js';
|
||||
|
||||
/**
|
||||
* The base constructor for creating `lodash` wrapper objects.
|
||||
*
|
||||
* @private
|
||||
* @param {*} value The value to wrap.
|
||||
* @param {boolean} [chainAll] Enable explicit method chain sequences.
|
||||
*/
|
||||
function LodashWrapper(value, chainAll) {
|
||||
this.__wrapped__ = value;
|
||||
this.__actions__ = [];
|
||||
this.__chain__ = !!chainAll;
|
||||
this.__index__ = 0;
|
||||
this.__values__ = undefined;
|
||||
}
|
||||
|
||||
LodashWrapper.prototype = baseCreate(baseLodash.prototype);
|
||||
LodashWrapper.prototype.constructor = LodashWrapper;
|
||||
|
||||
export default LodashWrapper;
|
||||
7
datav-bank/src/utils/lodash/_Map.js
Normal file
7
datav-bank/src/utils/lodash/_Map.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import getNative from './_getNative.js';
|
||||
import root from './_root.js';
|
||||
|
||||
/* Built-in method references that are verified to be native. */
|
||||
var Map = getNative(root, 'Map');
|
||||
|
||||
export default Map;
|
||||
32
datav-bank/src/utils/lodash/_MapCache.js
Normal file
32
datav-bank/src/utils/lodash/_MapCache.js
Normal file
@@ -0,0 +1,32 @@
|
||||
import mapCacheClear from './_mapCacheClear.js';
|
||||
import mapCacheDelete from './_mapCacheDelete.js';
|
||||
import mapCacheGet from './_mapCacheGet.js';
|
||||
import mapCacheHas from './_mapCacheHas.js';
|
||||
import mapCacheSet from './_mapCacheSet.js';
|
||||
|
||||
/**
|
||||
* Creates a map cache object to store key-value pairs.
|
||||
*
|
||||
* @private
|
||||
* @constructor
|
||||
* @param {Array} [entries] The key-value pairs to cache.
|
||||
*/
|
||||
function MapCache(entries) {
|
||||
var index = -1,
|
||||
length = entries == null ? 0 : entries.length;
|
||||
|
||||
this.clear();
|
||||
while (++index < length) {
|
||||
var entry = entries[index];
|
||||
this.set(entry[0], entry[1]);
|
||||
}
|
||||
}
|
||||
|
||||
// Add methods to `MapCache`.
|
||||
MapCache.prototype.clear = mapCacheClear;
|
||||
MapCache.prototype['delete'] = mapCacheDelete;
|
||||
MapCache.prototype.get = mapCacheGet;
|
||||
MapCache.prototype.has = mapCacheHas;
|
||||
MapCache.prototype.set = mapCacheSet;
|
||||
|
||||
export default MapCache;
|
||||
7
datav-bank/src/utils/lodash/_Promise.js
Normal file
7
datav-bank/src/utils/lodash/_Promise.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import getNative from './_getNative.js';
|
||||
import root from './_root.js';
|
||||
|
||||
/* Built-in method references that are verified to be native. */
|
||||
var Promise = getNative(root, 'Promise');
|
||||
|
||||
export default Promise;
|
||||
7
datav-bank/src/utils/lodash/_Set.js
Normal file
7
datav-bank/src/utils/lodash/_Set.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import getNative from './_getNative.js';
|
||||
import root from './_root.js';
|
||||
|
||||
/* Built-in method references that are verified to be native. */
|
||||
var Set = getNative(root, 'Set');
|
||||
|
||||
export default Set;
|
||||
27
datav-bank/src/utils/lodash/_SetCache.js
Normal file
27
datav-bank/src/utils/lodash/_SetCache.js
Normal file
@@ -0,0 +1,27 @@
|
||||
import MapCache from './_MapCache.js';
|
||||
import setCacheAdd from './_setCacheAdd.js';
|
||||
import setCacheHas from './_setCacheHas.js';
|
||||
|
||||
/**
|
||||
*
|
||||
* Creates an array cache object to store unique values.
|
||||
*
|
||||
* @private
|
||||
* @constructor
|
||||
* @param {Array} [values] The values to cache.
|
||||
*/
|
||||
function SetCache(values) {
|
||||
var index = -1,
|
||||
length = values == null ? 0 : values.length;
|
||||
|
||||
this.__data__ = new MapCache;
|
||||
while (++index < length) {
|
||||
this.add(values[index]);
|
||||
}
|
||||
}
|
||||
|
||||
// Add methods to `SetCache`.
|
||||
SetCache.prototype.add = SetCache.prototype.push = setCacheAdd;
|
||||
SetCache.prototype.has = setCacheHas;
|
||||
|
||||
export default SetCache;
|
||||
27
datav-bank/src/utils/lodash/_Stack.js
Normal file
27
datav-bank/src/utils/lodash/_Stack.js
Normal file
@@ -0,0 +1,27 @@
|
||||
import ListCache from './_ListCache.js';
|
||||
import stackClear from './_stackClear.js';
|
||||
import stackDelete from './_stackDelete.js';
|
||||
import stackGet from './_stackGet.js';
|
||||
import stackHas from './_stackHas.js';
|
||||
import stackSet from './_stackSet.js';
|
||||
|
||||
/**
|
||||
* Creates a stack cache object to store key-value pairs.
|
||||
*
|
||||
* @private
|
||||
* @constructor
|
||||
* @param {Array} [entries] The key-value pairs to cache.
|
||||
*/
|
||||
function Stack(entries) {
|
||||
var data = this.__data__ = new ListCache(entries);
|
||||
this.size = data.size;
|
||||
}
|
||||
|
||||
// Add methods to `Stack`.
|
||||
Stack.prototype.clear = stackClear;
|
||||
Stack.prototype['delete'] = stackDelete;
|
||||
Stack.prototype.get = stackGet;
|
||||
Stack.prototype.has = stackHas;
|
||||
Stack.prototype.set = stackSet;
|
||||
|
||||
export default Stack;
|
||||
6
datav-bank/src/utils/lodash/_Symbol.js
Normal file
6
datav-bank/src/utils/lodash/_Symbol.js
Normal file
@@ -0,0 +1,6 @@
|
||||
import root from './_root.js';
|
||||
|
||||
/** Built-in value references. */
|
||||
var Symbol = root.Symbol;
|
||||
|
||||
export default Symbol;
|
||||
6
datav-bank/src/utils/lodash/_Uint8Array.js
Normal file
6
datav-bank/src/utils/lodash/_Uint8Array.js
Normal file
@@ -0,0 +1,6 @@
|
||||
import root from './_root.js';
|
||||
|
||||
/** Built-in value references. */
|
||||
var Uint8Array = root.Uint8Array;
|
||||
|
||||
export default Uint8Array;
|
||||
7
datav-bank/src/utils/lodash/_WeakMap.js
Normal file
7
datav-bank/src/utils/lodash/_WeakMap.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import getNative from './_getNative.js';
|
||||
import root from './_root.js';
|
||||
|
||||
/* Built-in method references that are verified to be native. */
|
||||
var WeakMap = getNative(root, 'WeakMap');
|
||||
|
||||
export default WeakMap;
|
||||
21
datav-bank/src/utils/lodash/_apply.js
Normal file
21
datav-bank/src/utils/lodash/_apply.js
Normal file
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* A faster alternative to `Function#apply`, this function invokes `func`
|
||||
* with the `this` binding of `thisArg` and the arguments of `args`.
|
||||
*
|
||||
* @private
|
||||
* @param {Function} func The function to invoke.
|
||||
* @param {*} thisArg The `this` binding of `func`.
|
||||
* @param {Array} args The arguments to invoke `func` with.
|
||||
* @returns {*} Returns the result of `func`.
|
||||
*/
|
||||
function apply(func, thisArg, args) {
|
||||
switch (args.length) {
|
||||
case 0: return func.call(thisArg);
|
||||
case 1: return func.call(thisArg, args[0]);
|
||||
case 2: return func.call(thisArg, args[0], args[1]);
|
||||
case 3: return func.call(thisArg, args[0], args[1], args[2]);
|
||||
}
|
||||
return func.apply(thisArg, args);
|
||||
}
|
||||
|
||||
export default apply;
|
||||
22
datav-bank/src/utils/lodash/_arrayAggregator.js
Normal file
22
datav-bank/src/utils/lodash/_arrayAggregator.js
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* A specialized version of `baseAggregator` for arrays.
|
||||
*
|
||||
* @private
|
||||
* @param {Array} [array] The array to iterate over.
|
||||
* @param {Function} setter The function to set `accumulator` values.
|
||||
* @param {Function} iteratee The iteratee to transform keys.
|
||||
* @param {Object} accumulator The initial aggregated object.
|
||||
* @returns {Function} Returns `accumulator`.
|
||||
*/
|
||||
function arrayAggregator(array, setter, iteratee, accumulator) {
|
||||
var index = -1,
|
||||
length = array == null ? 0 : array.length;
|
||||
|
||||
while (++index < length) {
|
||||
var value = array[index];
|
||||
setter(accumulator, value, iteratee(value), array);
|
||||
}
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
export default arrayAggregator;
|
||||
22
datav-bank/src/utils/lodash/_arrayEach.js
Normal file
22
datav-bank/src/utils/lodash/_arrayEach.js
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* A specialized version of `_.forEach` for arrays without support for
|
||||
* iteratee shorthands.
|
||||
*
|
||||
* @private
|
||||
* @param {Array} [array] The array to iterate over.
|
||||
* @param {Function} iteratee The function invoked per iteration.
|
||||
* @returns {Array} Returns `array`.
|
||||
*/
|
||||
function arrayEach(array, iteratee) {
|
||||
var index = -1,
|
||||
length = array == null ? 0 : array.length;
|
||||
|
||||
while (++index < length) {
|
||||
if (iteratee(array[index], index, array) === false) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
export default arrayEach;
|
||||
21
datav-bank/src/utils/lodash/_arrayEachRight.js
Normal file
21
datav-bank/src/utils/lodash/_arrayEachRight.js
Normal file
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* A specialized version of `_.forEachRight` for arrays without support for
|
||||
* iteratee shorthands.
|
||||
*
|
||||
* @private
|
||||
* @param {Array} [array] The array to iterate over.
|
||||
* @param {Function} iteratee The function invoked per iteration.
|
||||
* @returns {Array} Returns `array`.
|
||||
*/
|
||||
function arrayEachRight(array, iteratee) {
|
||||
var length = array == null ? 0 : array.length;
|
||||
|
||||
while (length--) {
|
||||
if (iteratee(array[length], length, array) === false) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
export default arrayEachRight;
|
||||
23
datav-bank/src/utils/lodash/_arrayEvery.js
Normal file
23
datav-bank/src/utils/lodash/_arrayEvery.js
Normal file
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* A specialized version of `_.every` for arrays without support for
|
||||
* iteratee shorthands.
|
||||
*
|
||||
* @private
|
||||
* @param {Array} [array] The array to iterate over.
|
||||
* @param {Function} predicate The function invoked per iteration.
|
||||
* @returns {boolean} Returns `true` if all elements pass the predicate check,
|
||||
* else `false`.
|
||||
*/
|
||||
function arrayEvery(array, predicate) {
|
||||
var index = -1,
|
||||
length = array == null ? 0 : array.length;
|
||||
|
||||
while (++index < length) {
|
||||
if (!predicate(array[index], index, array)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export default arrayEvery;
|
||||
25
datav-bank/src/utils/lodash/_arrayFilter.js
Normal file
25
datav-bank/src/utils/lodash/_arrayFilter.js
Normal file
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* A specialized version of `_.filter` for arrays without support for
|
||||
* iteratee shorthands.
|
||||
*
|
||||
* @private
|
||||
* @param {Array} [array] The array to iterate over.
|
||||
* @param {Function} predicate The function invoked per iteration.
|
||||
* @returns {Array} Returns the new filtered array.
|
||||
*/
|
||||
function arrayFilter(array, predicate) {
|
||||
var index = -1,
|
||||
length = array == null ? 0 : array.length,
|
||||
resIndex = 0,
|
||||
result = [];
|
||||
|
||||
while (++index < length) {
|
||||
var value = array[index];
|
||||
if (predicate(value, index, array)) {
|
||||
result[resIndex++] = value;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export default arrayFilter;
|
||||
17
datav-bank/src/utils/lodash/_arrayIncludes.js
Normal file
17
datav-bank/src/utils/lodash/_arrayIncludes.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import baseIndexOf from './_baseIndexOf.js';
|
||||
|
||||
/**
|
||||
* A specialized version of `_.includes` for arrays without support for
|
||||
* specifying an index to search from.
|
||||
*
|
||||
* @private
|
||||
* @param {Array} [array] The array to inspect.
|
||||
* @param {*} target The value to search for.
|
||||
* @returns {boolean} Returns `true` if `target` is found, else `false`.
|
||||
*/
|
||||
function arrayIncludes(array, value) {
|
||||
var length = array == null ? 0 : array.length;
|
||||
return !!length && baseIndexOf(array, value, 0) > -1;
|
||||
}
|
||||
|
||||
export default arrayIncludes;
|
||||
22
datav-bank/src/utils/lodash/_arrayIncludesWith.js
Normal file
22
datav-bank/src/utils/lodash/_arrayIncludesWith.js
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* This function is like `arrayIncludes` except that it accepts a comparator.
|
||||
*
|
||||
* @private
|
||||
* @param {Array} [array] The array to inspect.
|
||||
* @param {*} target The value to search for.
|
||||
* @param {Function} comparator The comparator invoked per element.
|
||||
* @returns {boolean} Returns `true` if `target` is found, else `false`.
|
||||
*/
|
||||
function arrayIncludesWith(array, value, comparator) {
|
||||
var index = -1,
|
||||
length = array == null ? 0 : array.length;
|
||||
|
||||
while (++index < length) {
|
||||
if (comparator(value, array[index])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export default arrayIncludesWith;
|
||||
49
datav-bank/src/utils/lodash/_arrayLikeKeys.js
Normal file
49
datav-bank/src/utils/lodash/_arrayLikeKeys.js
Normal file
@@ -0,0 +1,49 @@
|
||||
import baseTimes from './_baseTimes.js';
|
||||
import isArguments from './isArguments.js';
|
||||
import isArray from './isArray.js';
|
||||
import isBuffer from './isBuffer.js';
|
||||
import isIndex from './_isIndex.js';
|
||||
import isTypedArray from './isTypedArray.js';
|
||||
|
||||
/** Used for built-in method references. */
|
||||
var objectProto = Object.prototype;
|
||||
|
||||
/** Used to check objects for own properties. */
|
||||
var hasOwnProperty = objectProto.hasOwnProperty;
|
||||
|
||||
/**
|
||||
* Creates an array of the enumerable property names of the array-like `value`.
|
||||
*
|
||||
* @private
|
||||
* @param {*} value The value to query.
|
||||
* @param {boolean} inherited Specify returning inherited property names.
|
||||
* @returns {Array} Returns the array of property names.
|
||||
*/
|
||||
function arrayLikeKeys(value, inherited) {
|
||||
var isArr = isArray(value),
|
||||
isArg = !isArr && isArguments(value),
|
||||
isBuff = !isArr && !isArg && isBuffer(value),
|
||||
isType = !isArr && !isArg && !isBuff && isTypedArray(value),
|
||||
skipIndexes = isArr || isArg || isBuff || isType,
|
||||
result = skipIndexes ? baseTimes(value.length, String) : [],
|
||||
length = result.length;
|
||||
|
||||
for (var key in value) {
|
||||
if ((inherited || hasOwnProperty.call(value, key)) &&
|
||||
!(skipIndexes && (
|
||||
// Safari 9 has enumerable `arguments.length` in strict mode.
|
||||
key == 'length' ||
|
||||
// Node.js 0.10 has enumerable non-index properties on buffers.
|
||||
(isBuff && (key == 'offset' || key == 'parent')) ||
|
||||
// PhantomJS 2 has enumerable non-index properties on typed arrays.
|
||||
(isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) ||
|
||||
// Skip index properties.
|
||||
isIndex(key, length)
|
||||
))) {
|
||||
result.push(key);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export default arrayLikeKeys;
|
||||
21
datav-bank/src/utils/lodash/_arrayMap.js
Normal file
21
datav-bank/src/utils/lodash/_arrayMap.js
Normal file
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* A specialized version of `_.map` for arrays without support for iteratee
|
||||
* shorthands.
|
||||
*
|
||||
* @private
|
||||
* @param {Array} [array] The array to iterate over.
|
||||
* @param {Function} iteratee The function invoked per iteration.
|
||||
* @returns {Array} Returns the new mapped array.
|
||||
*/
|
||||
function arrayMap(array, iteratee) {
|
||||
var index = -1,
|
||||
length = array == null ? 0 : array.length,
|
||||
result = Array(length);
|
||||
|
||||
while (++index < length) {
|
||||
result[index] = iteratee(array[index], index, array);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export default arrayMap;
|
||||
20
datav-bank/src/utils/lodash/_arrayPush.js
Normal file
20
datav-bank/src/utils/lodash/_arrayPush.js
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Appends the elements of `values` to `array`.
|
||||
*
|
||||
* @private
|
||||
* @param {Array} array The array to modify.
|
||||
* @param {Array} values The values to append.
|
||||
* @returns {Array} Returns `array`.
|
||||
*/
|
||||
function arrayPush(array, values) {
|
||||
var index = -1,
|
||||
length = values.length,
|
||||
offset = array.length;
|
||||
|
||||
while (++index < length) {
|
||||
array[offset + index] = values[index];
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
export default arrayPush;
|
||||
26
datav-bank/src/utils/lodash/_arrayReduce.js
Normal file
26
datav-bank/src/utils/lodash/_arrayReduce.js
Normal file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* A specialized version of `_.reduce` for arrays without support for
|
||||
* iteratee shorthands.
|
||||
*
|
||||
* @private
|
||||
* @param {Array} [array] The array to iterate over.
|
||||
* @param {Function} iteratee The function invoked per iteration.
|
||||
* @param {*} [accumulator] The initial value.
|
||||
* @param {boolean} [initAccum] Specify using the first element of `array` as
|
||||
* the initial value.
|
||||
* @returns {*} Returns the accumulated value.
|
||||
*/
|
||||
function arrayReduce(array, iteratee, accumulator, initAccum) {
|
||||
var index = -1,
|
||||
length = array == null ? 0 : array.length;
|
||||
|
||||
if (initAccum && length) {
|
||||
accumulator = array[++index];
|
||||
}
|
||||
while (++index < length) {
|
||||
accumulator = iteratee(accumulator, array[index], index, array);
|
||||
}
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
export default arrayReduce;
|
||||
24
datav-bank/src/utils/lodash/_arrayReduceRight.js
Normal file
24
datav-bank/src/utils/lodash/_arrayReduceRight.js
Normal file
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* A specialized version of `_.reduceRight` for arrays without support for
|
||||
* iteratee shorthands.
|
||||
*
|
||||
* @private
|
||||
* @param {Array} [array] The array to iterate over.
|
||||
* @param {Function} iteratee The function invoked per iteration.
|
||||
* @param {*} [accumulator] The initial value.
|
||||
* @param {boolean} [initAccum] Specify using the last element of `array` as
|
||||
* the initial value.
|
||||
* @returns {*} Returns the accumulated value.
|
||||
*/
|
||||
function arrayReduceRight(array, iteratee, accumulator, initAccum) {
|
||||
var length = array == null ? 0 : array.length;
|
||||
if (initAccum && length) {
|
||||
accumulator = array[--length];
|
||||
}
|
||||
while (length--) {
|
||||
accumulator = iteratee(accumulator, array[length], length, array);
|
||||
}
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
export default arrayReduceRight;
|
||||
15
datav-bank/src/utils/lodash/_arraySample.js
Normal file
15
datav-bank/src/utils/lodash/_arraySample.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import baseRandom from './_baseRandom.js';
|
||||
|
||||
/**
|
||||
* A specialized version of `_.sample` for arrays.
|
||||
*
|
||||
* @private
|
||||
* @param {Array} array The array to sample.
|
||||
* @returns {*} Returns the random element.
|
||||
*/
|
||||
function arraySample(array) {
|
||||
var length = array.length;
|
||||
return length ? array[baseRandom(0, length - 1)] : undefined;
|
||||
}
|
||||
|
||||
export default arraySample;
|
||||
17
datav-bank/src/utils/lodash/_arraySampleSize.js
Normal file
17
datav-bank/src/utils/lodash/_arraySampleSize.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import baseClamp from './_baseClamp.js';
|
||||
import copyArray from './_copyArray.js';
|
||||
import shuffleSelf from './_shuffleSelf.js';
|
||||
|
||||
/**
|
||||
* A specialized version of `_.sampleSize` for arrays.
|
||||
*
|
||||
* @private
|
||||
* @param {Array} array The array to sample.
|
||||
* @param {number} n The number of elements to sample.
|
||||
* @returns {Array} Returns the random elements.
|
||||
*/
|
||||
function arraySampleSize(array, n) {
|
||||
return shuffleSelf(copyArray(array), baseClamp(n, 0, array.length));
|
||||
}
|
||||
|
||||
export default arraySampleSize;
|
||||
15
datav-bank/src/utils/lodash/_arrayShuffle.js
Normal file
15
datav-bank/src/utils/lodash/_arrayShuffle.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import copyArray from './_copyArray.js';
|
||||
import shuffleSelf from './_shuffleSelf.js';
|
||||
|
||||
/**
|
||||
* A specialized version of `_.shuffle` for arrays.
|
||||
*
|
||||
* @private
|
||||
* @param {Array} array The array to shuffle.
|
||||
* @returns {Array} Returns the new shuffled array.
|
||||
*/
|
||||
function arrayShuffle(array) {
|
||||
return shuffleSelf(copyArray(array));
|
||||
}
|
||||
|
||||
export default arrayShuffle;
|
||||
23
datav-bank/src/utils/lodash/_arraySome.js
Normal file
23
datav-bank/src/utils/lodash/_arraySome.js
Normal file
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* A specialized version of `_.some` for arrays without support for iteratee
|
||||
* shorthands.
|
||||
*
|
||||
* @private
|
||||
* @param {Array} [array] The array to iterate over.
|
||||
* @param {Function} predicate The function invoked per iteration.
|
||||
* @returns {boolean} Returns `true` if any element passes the predicate check,
|
||||
* else `false`.
|
||||
*/
|
||||
function arraySome(array, predicate) {
|
||||
var index = -1,
|
||||
length = array == null ? 0 : array.length;
|
||||
|
||||
while (++index < length) {
|
||||
if (predicate(array[index], index, array)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export default arraySome;
|
||||
12
datav-bank/src/utils/lodash/_asciiSize.js
Normal file
12
datav-bank/src/utils/lodash/_asciiSize.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import baseProperty from './_baseProperty.js';
|
||||
|
||||
/**
|
||||
* Gets the size of an ASCII `string`.
|
||||
*
|
||||
* @private
|
||||
* @param {string} string The string inspect.
|
||||
* @returns {number} Returns the string size.
|
||||
*/
|
||||
var asciiSize = baseProperty('length');
|
||||
|
||||
export default asciiSize;
|
||||
12
datav-bank/src/utils/lodash/_asciiToArray.js
Normal file
12
datav-bank/src/utils/lodash/_asciiToArray.js
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Converts an ASCII `string` to an array.
|
||||
*
|
||||
* @private
|
||||
* @param {string} string The string to convert.
|
||||
* @returns {Array} Returns the converted array.
|
||||
*/
|
||||
function asciiToArray(string) {
|
||||
return string.split('');
|
||||
}
|
||||
|
||||
export default asciiToArray;
|
||||
15
datav-bank/src/utils/lodash/_asciiWords.js
Normal file
15
datav-bank/src/utils/lodash/_asciiWords.js
Normal file
@@ -0,0 +1,15 @@
|
||||
/** Used to match words composed of alphanumeric characters. */
|
||||
var reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;
|
||||
|
||||
/**
|
||||
* Splits an ASCII `string` into an array of its words.
|
||||
*
|
||||
* @private
|
||||
* @param {string} The string to inspect.
|
||||
* @returns {Array} Returns the words of `string`.
|
||||
*/
|
||||
function asciiWords(string) {
|
||||
return string.match(reAsciiWord) || [];
|
||||
}
|
||||
|
||||
export default asciiWords;
|
||||
20
datav-bank/src/utils/lodash/_assignMergeValue.js
Normal file
20
datav-bank/src/utils/lodash/_assignMergeValue.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import baseAssignValue from './_baseAssignValue.js';
|
||||
import eq from './eq.js';
|
||||
|
||||
/**
|
||||
* This function is like `assignValue` except that it doesn't assign
|
||||
* `undefined` values.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} object The object to modify.
|
||||
* @param {string} key The key of the property to assign.
|
||||
* @param {*} value The value to assign.
|
||||
*/
|
||||
function assignMergeValue(object, key, value) {
|
||||
if ((value !== undefined && !eq(object[key], value)) ||
|
||||
(value === undefined && !(key in object))) {
|
||||
baseAssignValue(object, key, value);
|
||||
}
|
||||
}
|
||||
|
||||
export default assignMergeValue;
|
||||
28
datav-bank/src/utils/lodash/_assignValue.js
Normal file
28
datav-bank/src/utils/lodash/_assignValue.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import baseAssignValue from './_baseAssignValue.js';
|
||||
import eq from './eq.js';
|
||||
|
||||
/** Used for built-in method references. */
|
||||
var objectProto = Object.prototype;
|
||||
|
||||
/** Used to check objects for own properties. */
|
||||
var hasOwnProperty = objectProto.hasOwnProperty;
|
||||
|
||||
/**
|
||||
* Assigns `value` to `key` of `object` if the existing value is not equivalent
|
||||
* using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
|
||||
* for equality comparisons.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} object The object to modify.
|
||||
* @param {string} key The key of the property to assign.
|
||||
* @param {*} value The value to assign.
|
||||
*/
|
||||
function assignValue(object, key, value) {
|
||||
var objValue = object[key];
|
||||
if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) ||
|
||||
(value === undefined && !(key in object))) {
|
||||
baseAssignValue(object, key, value);
|
||||
}
|
||||
}
|
||||
|
||||
export default assignValue;
|
||||
21
datav-bank/src/utils/lodash/_assocIndexOf.js
Normal file
21
datav-bank/src/utils/lodash/_assocIndexOf.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import eq from './eq.js';
|
||||
|
||||
/**
|
||||
* Gets the index at which the `key` is found in `array` of key-value pairs.
|
||||
*
|
||||
* @private
|
||||
* @param {Array} array The array to inspect.
|
||||
* @param {*} key The key to search for.
|
||||
* @returns {number} Returns the index of the matched value, else `-1`.
|
||||
*/
|
||||
function assocIndexOf(array, key) {
|
||||
var length = array.length;
|
||||
while (length--) {
|
||||
if (eq(array[length][0], key)) {
|
||||
return length;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
export default assocIndexOf;
|
||||
21
datav-bank/src/utils/lodash/_baseAggregator.js
Normal file
21
datav-bank/src/utils/lodash/_baseAggregator.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import baseEach from './_baseEach.js';
|
||||
|
||||
/**
|
||||
* Aggregates elements of `collection` on `accumulator` with keys transformed
|
||||
* by `iteratee` and values set by `setter`.
|
||||
*
|
||||
* @private
|
||||
* @param {Array|Object} collection The collection to iterate over.
|
||||
* @param {Function} setter The function to set `accumulator` values.
|
||||
* @param {Function} iteratee The iteratee to transform keys.
|
||||
* @param {Object} accumulator The initial aggregated object.
|
||||
* @returns {Function} Returns `accumulator`.
|
||||
*/
|
||||
function baseAggregator(collection, setter, iteratee, accumulator) {
|
||||
baseEach(collection, function(value, key, collection) {
|
||||
setter(accumulator, value, iteratee(value), collection);
|
||||
});
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
export default baseAggregator;
|
||||
17
datav-bank/src/utils/lodash/_baseAssign.js
Normal file
17
datav-bank/src/utils/lodash/_baseAssign.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import copyObject from './_copyObject.js';
|
||||
import keys from './keys.js';
|
||||
|
||||
/**
|
||||
* The base implementation of `_.assign` without support for multiple sources
|
||||
* or `customizer` functions.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} object The destination object.
|
||||
* @param {Object} source The source object.
|
||||
* @returns {Object} Returns `object`.
|
||||
*/
|
||||
function baseAssign(object, source) {
|
||||
return object && copyObject(source, keys(source), object);
|
||||
}
|
||||
|
||||
export default baseAssign;
|
||||
17
datav-bank/src/utils/lodash/_baseAssignIn.js
Normal file
17
datav-bank/src/utils/lodash/_baseAssignIn.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import copyObject from './_copyObject.js';
|
||||
import keysIn from './keysIn.js';
|
||||
|
||||
/**
|
||||
* The base implementation of `_.assignIn` without support for multiple sources
|
||||
* or `customizer` functions.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} object The destination object.
|
||||
* @param {Object} source The source object.
|
||||
* @returns {Object} Returns `object`.
|
||||
*/
|
||||
function baseAssignIn(object, source) {
|
||||
return object && copyObject(source, keysIn(source), object);
|
||||
}
|
||||
|
||||
export default baseAssignIn;
|
||||
25
datav-bank/src/utils/lodash/_baseAssignValue.js
Normal file
25
datav-bank/src/utils/lodash/_baseAssignValue.js
Normal file
@@ -0,0 +1,25 @@
|
||||
import defineProperty from './_defineProperty.js';
|
||||
|
||||
/**
|
||||
* The base implementation of `assignValue` and `assignMergeValue` without
|
||||
* value checks.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} object The object to modify.
|
||||
* @param {string} key The key of the property to assign.
|
||||
* @param {*} value The value to assign.
|
||||
*/
|
||||
function baseAssignValue(object, key, value) {
|
||||
if (key == '__proto__' && defineProperty) {
|
||||
defineProperty(object, key, {
|
||||
'configurable': true,
|
||||
'enumerable': true,
|
||||
'value': value,
|
||||
'writable': true
|
||||
});
|
||||
} else {
|
||||
object[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
export default baseAssignValue;
|
||||
23
datav-bank/src/utils/lodash/_baseAt.js
Normal file
23
datav-bank/src/utils/lodash/_baseAt.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import get from './get.js';
|
||||
|
||||
/**
|
||||
* The base implementation of `_.at` without support for individual paths.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} object The object to iterate over.
|
||||
* @param {string[]} paths The property paths to pick.
|
||||
* @returns {Array} Returns the picked elements.
|
||||
*/
|
||||
function baseAt(object, paths) {
|
||||
var index = -1,
|
||||
length = paths.length,
|
||||
result = Array(length),
|
||||
skip = object == null;
|
||||
|
||||
while (++index < length) {
|
||||
result[index] = skip ? undefined : get(object, paths[index]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export default baseAt;
|
||||
22
datav-bank/src/utils/lodash/_baseClamp.js
Normal file
22
datav-bank/src/utils/lodash/_baseClamp.js
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* The base implementation of `_.clamp` which doesn't coerce arguments.
|
||||
*
|
||||
* @private
|
||||
* @param {number} number The number to clamp.
|
||||
* @param {number} [lower] The lower bound.
|
||||
* @param {number} upper The upper bound.
|
||||
* @returns {number} Returns the clamped number.
|
||||
*/
|
||||
function baseClamp(number, lower, upper) {
|
||||
if (number === number) {
|
||||
if (upper !== undefined) {
|
||||
number = number <= upper ? number : upper;
|
||||
}
|
||||
if (lower !== undefined) {
|
||||
number = number >= lower ? number : lower;
|
||||
}
|
||||
}
|
||||
return number;
|
||||
}
|
||||
|
||||
export default baseClamp;
|
||||
171
datav-bank/src/utils/lodash/_baseClone.js
Normal file
171
datav-bank/src/utils/lodash/_baseClone.js
Normal file
@@ -0,0 +1,171 @@
|
||||
import Stack from './_Stack.js';
|
||||
import arrayEach from './_arrayEach.js';
|
||||
import assignValue from './_assignValue.js';
|
||||
import baseAssign from './_baseAssign.js';
|
||||
import baseAssignIn from './_baseAssignIn.js';
|
||||
import cloneBuffer from './_cloneBuffer.js';
|
||||
import copyArray from './_copyArray.js';
|
||||
import copySymbols from './_copySymbols.js';
|
||||
import copySymbolsIn from './_copySymbolsIn.js';
|
||||
import getAllKeys from './_getAllKeys.js';
|
||||
import getAllKeysIn from './_getAllKeysIn.js';
|
||||
import getTag from './_getTag.js';
|
||||
import initCloneArray from './_initCloneArray.js';
|
||||
import initCloneByTag from './_initCloneByTag.js';
|
||||
import initCloneObject from './_initCloneObject.js';
|
||||
import isArray from './isArray.js';
|
||||
import isBuffer from './isBuffer.js';
|
||||
import isMap from './isMap.js';
|
||||
import isObject from './isObject.js';
|
||||
import isSet from './isSet.js';
|
||||
import keys from './keys.js';
|
||||
|
||||
/** Used to compose bitmasks for cloning. */
|
||||
var CLONE_DEEP_FLAG = 1,
|
||||
CLONE_FLAT_FLAG = 2,
|
||||
CLONE_SYMBOLS_FLAG = 4;
|
||||
|
||||
/** `Object#toString` result references. */
|
||||
var argsTag = '[object Arguments]',
|
||||
arrayTag = '[object Array]',
|
||||
boolTag = '[object Boolean]',
|
||||
dateTag = '[object Date]',
|
||||
errorTag = '[object Error]',
|
||||
funcTag = '[object Function]',
|
||||
genTag = '[object GeneratorFunction]',
|
||||
mapTag = '[object Map]',
|
||||
numberTag = '[object Number]',
|
||||
objectTag = '[object Object]',
|
||||
regexpTag = '[object RegExp]',
|
||||
setTag = '[object Set]',
|
||||
stringTag = '[object String]',
|
||||
symbolTag = '[object Symbol]',
|
||||
weakMapTag = '[object WeakMap]';
|
||||
|
||||
var arrayBufferTag = '[object ArrayBuffer]',
|
||||
dataViewTag = '[object DataView]',
|
||||
float32Tag = '[object Float32Array]',
|
||||
float64Tag = '[object Float64Array]',
|
||||
int8Tag = '[object Int8Array]',
|
||||
int16Tag = '[object Int16Array]',
|
||||
int32Tag = '[object Int32Array]',
|
||||
uint8Tag = '[object Uint8Array]',
|
||||
uint8ClampedTag = '[object Uint8ClampedArray]',
|
||||
uint16Tag = '[object Uint16Array]',
|
||||
uint32Tag = '[object Uint32Array]';
|
||||
|
||||
/** Used to identify `toStringTag` values supported by `_.clone`. */
|
||||
var cloneableTags = {};
|
||||
cloneableTags[argsTag] = cloneableTags[arrayTag] =
|
||||
cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] =
|
||||
cloneableTags[boolTag] = cloneableTags[dateTag] =
|
||||
cloneableTags[float32Tag] = cloneableTags[float64Tag] =
|
||||
cloneableTags[int8Tag] = cloneableTags[int16Tag] =
|
||||
cloneableTags[int32Tag] = cloneableTags[mapTag] =
|
||||
cloneableTags[numberTag] = cloneableTags[objectTag] =
|
||||
cloneableTags[regexpTag] = cloneableTags[setTag] =
|
||||
cloneableTags[stringTag] = cloneableTags[symbolTag] =
|
||||
cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =
|
||||
cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;
|
||||
cloneableTags[errorTag] = cloneableTags[funcTag] =
|
||||
cloneableTags[weakMapTag] = false;
|
||||
|
||||
/**
|
||||
* The base implementation of `_.clone` and `_.cloneDeep` which tracks
|
||||
* traversed objects.
|
||||
*
|
||||
* @private
|
||||
* @param {*} value The value to clone.
|
||||
* @param {boolean} bitmask The bitmask flags.
|
||||
* 1 - Deep clone
|
||||
* 2 - Flatten inherited properties
|
||||
* 4 - Clone symbols
|
||||
* @param {Function} [customizer] The function to customize cloning.
|
||||
* @param {string} [key] The key of `value`.
|
||||
* @param {Object} [object] The parent object of `value`.
|
||||
* @param {Object} [stack] Tracks traversed objects and their clone counterparts.
|
||||
* @returns {*} Returns the cloned value.
|
||||
*/
|
||||
function baseClone(value, bitmask, customizer, key, object, stack) {
|
||||
var result,
|
||||
isDeep = bitmask & CLONE_DEEP_FLAG,
|
||||
isFlat = bitmask & CLONE_FLAT_FLAG,
|
||||
isFull = bitmask & CLONE_SYMBOLS_FLAG;
|
||||
|
||||
if (customizer) {
|
||||
result = object ? customizer(value, key, object, stack) : customizer(value);
|
||||
}
|
||||
if (result !== undefined) {
|
||||
return result;
|
||||
}
|
||||
if (!isObject(value)) {
|
||||
return value;
|
||||
}
|
||||
var isArr = isArray(value);
|
||||
if (isArr) {
|
||||
result = initCloneArray(value);
|
||||
if (!isDeep) {
|
||||
return copyArray(value, result);
|
||||
}
|
||||
} else {
|
||||
var tag = getTag(value),
|
||||
isFunc = tag == funcTag || tag == genTag;
|
||||
|
||||
if (isBuffer(value)) {
|
||||
return cloneBuffer(value, isDeep);
|
||||
}
|
||||
if (tag == objectTag || tag == argsTag || (isFunc && !object)) {
|
||||
result = (isFlat || isFunc) ? {} : initCloneObject(value);
|
||||
if (!isDeep) {
|
||||
return isFlat
|
||||
? copySymbolsIn(value, baseAssignIn(result, value))
|
||||
: copySymbols(value, baseAssign(result, value));
|
||||
}
|
||||
} else {
|
||||
if (!cloneableTags[tag]) {
|
||||
return object ? value : {};
|
||||
}
|
||||
result = initCloneByTag(value, tag, isDeep);
|
||||
}
|
||||
}
|
||||
// Check for circular references and return its corresponding clone.
|
||||
stack || (stack = new Stack);
|
||||
var stacked = stack.get(value);
|
||||
if (stacked) {
|
||||
return stacked;
|
||||
}
|
||||
stack.set(value, result);
|
||||
|
||||
if (isSet(value)) {
|
||||
value.forEach(function(subValue) {
|
||||
result.add(baseClone(subValue, bitmask, customizer, subValue, value, stack));
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if (isMap(value)) {
|
||||
value.forEach(function(subValue, key) {
|
||||
result.set(key, baseClone(subValue, bitmask, customizer, key, value, stack));
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var keysFunc = isFull
|
||||
? (isFlat ? getAllKeysIn : getAllKeys)
|
||||
: (isFlat ? keysIn : keys);
|
||||
|
||||
var props = isArr ? undefined : keysFunc(value);
|
||||
arrayEach(props || value, function(subValue, key) {
|
||||
if (props) {
|
||||
key = subValue;
|
||||
subValue = value[key];
|
||||
}
|
||||
// Recursively populate clone (susceptible to call stack limits).
|
||||
assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack));
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
export default baseClone;
|
||||
18
datav-bank/src/utils/lodash/_baseConforms.js
Normal file
18
datav-bank/src/utils/lodash/_baseConforms.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import baseConformsTo from './_baseConformsTo.js';
|
||||
import keys from './keys.js';
|
||||
|
||||
/**
|
||||
* The base implementation of `_.conforms` which doesn't clone `source`.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} source The object of property predicates to conform to.
|
||||
* @returns {Function} Returns the new spec function.
|
||||
*/
|
||||
function baseConforms(source) {
|
||||
var props = keys(source);
|
||||
return function(object) {
|
||||
return baseConformsTo(object, source, props);
|
||||
};
|
||||
}
|
||||
|
||||
export default baseConforms;
|
||||
27
datav-bank/src/utils/lodash/_baseConformsTo.js
Normal file
27
datav-bank/src/utils/lodash/_baseConformsTo.js
Normal file
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* The base implementation of `_.conformsTo` which accepts `props` to check.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} object The object to inspect.
|
||||
* @param {Object} source The object of property predicates to conform to.
|
||||
* @returns {boolean} Returns `true` if `object` conforms, else `false`.
|
||||
*/
|
||||
function baseConformsTo(object, source, props) {
|
||||
var length = props.length;
|
||||
if (object == null) {
|
||||
return !length;
|
||||
}
|
||||
object = Object(object);
|
||||
while (length--) {
|
||||
var key = props[length],
|
||||
predicate = source[key],
|
||||
value = object[key];
|
||||
|
||||
if ((value === undefined && !(key in object)) || !predicate(value)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export default baseConformsTo;
|
||||
30
datav-bank/src/utils/lodash/_baseCreate.js
Normal file
30
datav-bank/src/utils/lodash/_baseCreate.js
Normal file
@@ -0,0 +1,30 @@
|
||||
import isObject from './isObject.js';
|
||||
|
||||
/** Built-in value references. */
|
||||
var objectCreate = Object.create;
|
||||
|
||||
/**
|
||||
* The base implementation of `_.create` without support for assigning
|
||||
* properties to the created object.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} proto The object to inherit from.
|
||||
* @returns {Object} Returns the new object.
|
||||
*/
|
||||
var baseCreate = (function() {
|
||||
function object() {}
|
||||
return function(proto) {
|
||||
if (!isObject(proto)) {
|
||||
return {};
|
||||
}
|
||||
if (objectCreate) {
|
||||
return objectCreate(proto);
|
||||
}
|
||||
object.prototype = proto;
|
||||
var result = new object;
|
||||
object.prototype = undefined;
|
||||
return result;
|
||||
};
|
||||
}());
|
||||
|
||||
export default baseCreate;
|
||||
21
datav-bank/src/utils/lodash/_baseDelay.js
Normal file
21
datav-bank/src/utils/lodash/_baseDelay.js
Normal file
@@ -0,0 +1,21 @@
|
||||
/** Error message constants. */
|
||||
var FUNC_ERROR_TEXT = 'Expected a function';
|
||||
|
||||
/**
|
||||
* The base implementation of `_.delay` and `_.defer` which accepts `args`
|
||||
* to provide to `func`.
|
||||
*
|
||||
* @private
|
||||
* @param {Function} func The function to delay.
|
||||
* @param {number} wait The number of milliseconds to delay invocation.
|
||||
* @param {Array} args The arguments to provide to `func`.
|
||||
* @returns {number|Object} Returns the timer id or timeout object.
|
||||
*/
|
||||
function baseDelay(func, wait, args) {
|
||||
if (typeof func != 'function') {
|
||||
throw new TypeError(FUNC_ERROR_TEXT);
|
||||
}
|
||||
return setTimeout(function() { func.apply(undefined, args); }, wait);
|
||||
}
|
||||
|
||||
export default baseDelay;
|
||||
67
datav-bank/src/utils/lodash/_baseDifference.js
Normal file
67
datav-bank/src/utils/lodash/_baseDifference.js
Normal file
@@ -0,0 +1,67 @@
|
||||
import SetCache from './_SetCache.js';
|
||||
import arrayIncludes from './_arrayIncludes.js';
|
||||
import arrayIncludesWith from './_arrayIncludesWith.js';
|
||||
import arrayMap from './_arrayMap.js';
|
||||
import baseUnary from './_baseUnary.js';
|
||||
import cacheHas from './_cacheHas.js';
|
||||
|
||||
/** Used as the size to enable large array optimizations. */
|
||||
var LARGE_ARRAY_SIZE = 200;
|
||||
|
||||
/**
|
||||
* The base implementation of methods like `_.difference` without support
|
||||
* for excluding multiple arrays or iteratee shorthands.
|
||||
*
|
||||
* @private
|
||||
* @param {Array} array The array to inspect.
|
||||
* @param {Array} values The values to exclude.
|
||||
* @param {Function} [iteratee] The iteratee invoked per element.
|
||||
* @param {Function} [comparator] The comparator invoked per element.
|
||||
* @returns {Array} Returns the new array of filtered values.
|
||||
*/
|
||||
function baseDifference(array, values, iteratee, comparator) {
|
||||
var index = -1,
|
||||
includes = arrayIncludes,
|
||||
isCommon = true,
|
||||
length = array.length,
|
||||
result = [],
|
||||
valuesLength = values.length;
|
||||
|
||||
if (!length) {
|
||||
return result;
|
||||
}
|
||||
if (iteratee) {
|
||||
values = arrayMap(values, baseUnary(iteratee));
|
||||
}
|
||||
if (comparator) {
|
||||
includes = arrayIncludesWith;
|
||||
isCommon = false;
|
||||
}
|
||||
else if (values.length >= LARGE_ARRAY_SIZE) {
|
||||
includes = cacheHas;
|
||||
isCommon = false;
|
||||
values = new SetCache(values);
|
||||
}
|
||||
outer:
|
||||
while (++index < length) {
|
||||
var value = array[index],
|
||||
computed = iteratee == null ? value : iteratee(value);
|
||||
|
||||
value = (comparator || value !== 0) ? value : 0;
|
||||
if (isCommon && computed === computed) {
|
||||
var valuesIndex = valuesLength;
|
||||
while (valuesIndex--) {
|
||||
if (values[valuesIndex] === computed) {
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
result.push(value);
|
||||
}
|
||||
else if (!includes(values, computed, comparator)) {
|
||||
result.push(value);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export default baseDifference;
|
||||
14
datav-bank/src/utils/lodash/_baseEach.js
Normal file
14
datav-bank/src/utils/lodash/_baseEach.js
Normal file
@@ -0,0 +1,14 @@
|
||||
import baseForOwn from './_baseForOwn.js';
|
||||
import createBaseEach from './_createBaseEach.js';
|
||||
|
||||
/**
|
||||
* The base implementation of `_.forEach` without support for iteratee shorthands.
|
||||
*
|
||||
* @private
|
||||
* @param {Array|Object} collection The collection to iterate over.
|
||||
* @param {Function} iteratee The function invoked per iteration.
|
||||
* @returns {Array|Object} Returns `collection`.
|
||||
*/
|
||||
var baseEach = createBaseEach(baseForOwn);
|
||||
|
||||
export default baseEach;
|
||||
14
datav-bank/src/utils/lodash/_baseEachRight.js
Normal file
14
datav-bank/src/utils/lodash/_baseEachRight.js
Normal file
@@ -0,0 +1,14 @@
|
||||
import baseForOwnRight from './_baseForOwnRight.js';
|
||||
import createBaseEach from './_createBaseEach.js';
|
||||
|
||||
/**
|
||||
* The base implementation of `_.forEachRight` without support for iteratee shorthands.
|
||||
*
|
||||
* @private
|
||||
* @param {Array|Object} collection The collection to iterate over.
|
||||
* @param {Function} iteratee The function invoked per iteration.
|
||||
* @returns {Array|Object} Returns `collection`.
|
||||
*/
|
||||
var baseEachRight = createBaseEach(baseForOwnRight, true);
|
||||
|
||||
export default baseEachRight;
|
||||
21
datav-bank/src/utils/lodash/_baseEvery.js
Normal file
21
datav-bank/src/utils/lodash/_baseEvery.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import baseEach from './_baseEach.js';
|
||||
|
||||
/**
|
||||
* The base implementation of `_.every` without support for iteratee shorthands.
|
||||
*
|
||||
* @private
|
||||
* @param {Array|Object} collection The collection to iterate over.
|
||||
* @param {Function} predicate The function invoked per iteration.
|
||||
* @returns {boolean} Returns `true` if all elements pass the predicate check,
|
||||
* else `false`
|
||||
*/
|
||||
function baseEvery(collection, predicate) {
|
||||
var result = true;
|
||||
baseEach(collection, function(value, index, collection) {
|
||||
result = !!predicate(value, index, collection);
|
||||
return result;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
export default baseEvery;
|
||||
32
datav-bank/src/utils/lodash/_baseExtremum.js
Normal file
32
datav-bank/src/utils/lodash/_baseExtremum.js
Normal file
@@ -0,0 +1,32 @@
|
||||
import isSymbol from './isSymbol.js';
|
||||
|
||||
/**
|
||||
* The base implementation of methods like `_.max` and `_.min` which accepts a
|
||||
* `comparator` to determine the extremum value.
|
||||
*
|
||||
* @private
|
||||
* @param {Array} array The array to iterate over.
|
||||
* @param {Function} iteratee The iteratee invoked per iteration.
|
||||
* @param {Function} comparator The comparator used to compare values.
|
||||
* @returns {*} Returns the extremum value.
|
||||
*/
|
||||
function baseExtremum(array, iteratee, comparator) {
|
||||
var index = -1,
|
||||
length = array.length;
|
||||
|
||||
while (++index < length) {
|
||||
var value = array[index],
|
||||
current = iteratee(value);
|
||||
|
||||
if (current != null && (computed === undefined
|
||||
? (current === current && !isSymbol(current))
|
||||
: comparator(current, computed)
|
||||
)) {
|
||||
var computed = current,
|
||||
result = value;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export default baseExtremum;
|
||||
32
datav-bank/src/utils/lodash/_baseFill.js
Normal file
32
datav-bank/src/utils/lodash/_baseFill.js
Normal file
@@ -0,0 +1,32 @@
|
||||
import toInteger from './toInteger.js';
|
||||
import toLength from './toLength.js';
|
||||
|
||||
/**
|
||||
* The base implementation of `_.fill` without an iteratee call guard.
|
||||
*
|
||||
* @private
|
||||
* @param {Array} array The array to fill.
|
||||
* @param {*} value The value to fill `array` with.
|
||||
* @param {number} [start=0] The start position.
|
||||
* @param {number} [end=array.length] The end position.
|
||||
* @returns {Array} Returns `array`.
|
||||
*/
|
||||
function baseFill(array, value, start, end) {
|
||||
var length = array.length;
|
||||
|
||||
start = toInteger(start);
|
||||
if (start < 0) {
|
||||
start = -start > length ? 0 : (length + start);
|
||||
}
|
||||
end = (end === undefined || end > length) ? length : toInteger(end);
|
||||
if (end < 0) {
|
||||
end += length;
|
||||
}
|
||||
end = start > end ? 0 : toLength(end);
|
||||
while (start < end) {
|
||||
array[start++] = value;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
export default baseFill;
|
||||
21
datav-bank/src/utils/lodash/_baseFilter.js
Normal file
21
datav-bank/src/utils/lodash/_baseFilter.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import baseEach from './_baseEach.js';
|
||||
|
||||
/**
|
||||
* The base implementation of `_.filter` without support for iteratee shorthands.
|
||||
*
|
||||
* @private
|
||||
* @param {Array|Object} collection The collection to iterate over.
|
||||
* @param {Function} predicate The function invoked per iteration.
|
||||
* @returns {Array} Returns the new filtered array.
|
||||
*/
|
||||
function baseFilter(collection, predicate) {
|
||||
var result = [];
|
||||
baseEach(collection, function(value, index, collection) {
|
||||
if (predicate(value, index, collection)) {
|
||||
result.push(value);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
export default baseFilter;
|
||||
24
datav-bank/src/utils/lodash/_baseFindIndex.js
Normal file
24
datav-bank/src/utils/lodash/_baseFindIndex.js
Normal file
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* The base implementation of `_.findIndex` and `_.findLastIndex` without
|
||||
* support for iteratee shorthands.
|
||||
*
|
||||
* @private
|
||||
* @param {Array} array The array to inspect.
|
||||
* @param {Function} predicate The function invoked per iteration.
|
||||
* @param {number} fromIndex The index to search from.
|
||||
* @param {boolean} [fromRight] Specify iterating from right to left.
|
||||
* @returns {number} Returns the index of the matched value, else `-1`.
|
||||
*/
|
||||
function baseFindIndex(array, predicate, fromIndex, fromRight) {
|
||||
var length = array.length,
|
||||
index = fromIndex + (fromRight ? 1 : -1);
|
||||
|
||||
while ((fromRight ? index-- : ++index < length)) {
|
||||
if (predicate(array[index], index, array)) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
export default baseFindIndex;
|
||||
23
datav-bank/src/utils/lodash/_baseFindKey.js
Normal file
23
datav-bank/src/utils/lodash/_baseFindKey.js
Normal file
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* The base implementation of methods like `_.findKey` and `_.findLastKey`,
|
||||
* without support for iteratee shorthands, which iterates over `collection`
|
||||
* using `eachFunc`.
|
||||
*
|
||||
* @private
|
||||
* @param {Array|Object} collection The collection to inspect.
|
||||
* @param {Function} predicate The function invoked per iteration.
|
||||
* @param {Function} eachFunc The function to iterate over `collection`.
|
||||
* @returns {*} Returns the found element or its key, else `undefined`.
|
||||
*/
|
||||
function baseFindKey(collection, predicate, eachFunc) {
|
||||
var result;
|
||||
eachFunc(collection, function(value, key, collection) {
|
||||
if (predicate(value, key, collection)) {
|
||||
result = key;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
export default baseFindKey;
|
||||
38
datav-bank/src/utils/lodash/_baseFlatten.js
Normal file
38
datav-bank/src/utils/lodash/_baseFlatten.js
Normal file
@@ -0,0 +1,38 @@
|
||||
import arrayPush from './_arrayPush.js';
|
||||
import isFlattenable from './_isFlattenable.js';
|
||||
|
||||
/**
|
||||
* The base implementation of `_.flatten` with support for restricting flattening.
|
||||
*
|
||||
* @private
|
||||
* @param {Array} array The array to flatten.
|
||||
* @param {number} depth The maximum recursion depth.
|
||||
* @param {boolean} [predicate=isFlattenable] The function invoked per iteration.
|
||||
* @param {boolean} [isStrict] Restrict to values that pass `predicate` checks.
|
||||
* @param {Array} [result=[]] The initial result value.
|
||||
* @returns {Array} Returns the new flattened array.
|
||||
*/
|
||||
function baseFlatten(array, depth, predicate, isStrict, result) {
|
||||
var index = -1,
|
||||
length = array.length;
|
||||
|
||||
predicate || (predicate = isFlattenable);
|
||||
result || (result = []);
|
||||
|
||||
while (++index < length) {
|
||||
var value = array[index];
|
||||
if (depth > 0 && predicate(value)) {
|
||||
if (depth > 1) {
|
||||
// Recursively flatten arrays (susceptible to call stack limits).
|
||||
baseFlatten(value, depth - 1, predicate, isStrict, result);
|
||||
} else {
|
||||
arrayPush(result, value);
|
||||
}
|
||||
} else if (!isStrict) {
|
||||
result[result.length] = value;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export default baseFlatten;
|
||||
16
datav-bank/src/utils/lodash/_baseFor.js
Normal file
16
datav-bank/src/utils/lodash/_baseFor.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import createBaseFor from './_createBaseFor.js';
|
||||
|
||||
/**
|
||||
* The base implementation of `baseForOwn` which iterates over `object`
|
||||
* properties returned by `keysFunc` and invokes `iteratee` for each property.
|
||||
* Iteratee functions may exit iteration early by explicitly returning `false`.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} object The object to iterate over.
|
||||
* @param {Function} iteratee The function invoked per iteration.
|
||||
* @param {Function} keysFunc The function to get the keys of `object`.
|
||||
* @returns {Object} Returns `object`.
|
||||
*/
|
||||
var baseFor = createBaseFor();
|
||||
|
||||
export default baseFor;
|
||||
16
datav-bank/src/utils/lodash/_baseForOwn.js
Normal file
16
datav-bank/src/utils/lodash/_baseForOwn.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import baseFor from './_baseFor.js';
|
||||
import keys from './keys.js';
|
||||
|
||||
/**
|
||||
* The base implementation of `_.forOwn` without support for iteratee shorthands.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} object The object to iterate over.
|
||||
* @param {Function} iteratee The function invoked per iteration.
|
||||
* @returns {Object} Returns `object`.
|
||||
*/
|
||||
function baseForOwn(object, iteratee) {
|
||||
return object && baseFor(object, iteratee, keys);
|
||||
}
|
||||
|
||||
export default baseForOwn;
|
||||
16
datav-bank/src/utils/lodash/_baseForOwnRight.js
Normal file
16
datav-bank/src/utils/lodash/_baseForOwnRight.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import baseForRight from './_baseForRight.js';
|
||||
import keys from './keys.js';
|
||||
|
||||
/**
|
||||
* The base implementation of `_.forOwnRight` without support for iteratee shorthands.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} object The object to iterate over.
|
||||
* @param {Function} iteratee The function invoked per iteration.
|
||||
* @returns {Object} Returns `object`.
|
||||
*/
|
||||
function baseForOwnRight(object, iteratee) {
|
||||
return object && baseForRight(object, iteratee, keys);
|
||||
}
|
||||
|
||||
export default baseForOwnRight;
|
||||
15
datav-bank/src/utils/lodash/_baseForRight.js
Normal file
15
datav-bank/src/utils/lodash/_baseForRight.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import createBaseFor from './_createBaseFor.js';
|
||||
|
||||
/**
|
||||
* This function is like `baseFor` except that it iterates over properties
|
||||
* in the opposite order.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} object The object to iterate over.
|
||||
* @param {Function} iteratee The function invoked per iteration.
|
||||
* @param {Function} keysFunc The function to get the keys of `object`.
|
||||
* @returns {Object} Returns `object`.
|
||||
*/
|
||||
var baseForRight = createBaseFor(true);
|
||||
|
||||
export default baseForRight;
|
||||
19
datav-bank/src/utils/lodash/_baseFunctions.js
Normal file
19
datav-bank/src/utils/lodash/_baseFunctions.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import arrayFilter from './_arrayFilter.js';
|
||||
import isFunction from './isFunction.js';
|
||||
|
||||
/**
|
||||
* The base implementation of `_.functions` which creates an array of
|
||||
* `object` function property names filtered from `props`.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} object The object to inspect.
|
||||
* @param {Array} props The property names to filter.
|
||||
* @returns {Array} Returns the function names.
|
||||
*/
|
||||
function baseFunctions(object, props) {
|
||||
return arrayFilter(props, function(key) {
|
||||
return isFunction(object[key]);
|
||||
});
|
||||
}
|
||||
|
||||
export default baseFunctions;
|
||||
24
datav-bank/src/utils/lodash/_baseGet.js
Normal file
24
datav-bank/src/utils/lodash/_baseGet.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import castPath from './_castPath.js';
|
||||
import toKey from './_toKey.js';
|
||||
|
||||
/**
|
||||
* The base implementation of `_.get` without support for default values.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} object The object to query.
|
||||
* @param {Array|string} path The path of the property to get.
|
||||
* @returns {*} Returns the resolved value.
|
||||
*/
|
||||
function baseGet(object, path) {
|
||||
path = castPath(path, object);
|
||||
|
||||
var index = 0,
|
||||
length = path.length;
|
||||
|
||||
while (object != null && index < length) {
|
||||
object = object[toKey(path[index++])];
|
||||
}
|
||||
return (index && index == length) ? object : undefined;
|
||||
}
|
||||
|
||||
export default baseGet;
|
||||
20
datav-bank/src/utils/lodash/_baseGetAllKeys.js
Normal file
20
datav-bank/src/utils/lodash/_baseGetAllKeys.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import arrayPush from './_arrayPush.js';
|
||||
import isArray from './isArray.js';
|
||||
|
||||
/**
|
||||
* The base implementation of `getAllKeys` and `getAllKeysIn` which uses
|
||||
* `keysFunc` and `symbolsFunc` to get the enumerable property names and
|
||||
* symbols of `object`.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} object The object to query.
|
||||
* @param {Function} keysFunc The function to get the keys of `object`.
|
||||
* @param {Function} symbolsFunc The function to get the symbols of `object`.
|
||||
* @returns {Array} Returns the array of property names and symbols.
|
||||
*/
|
||||
function baseGetAllKeys(object, keysFunc, symbolsFunc) {
|
||||
var result = keysFunc(object);
|
||||
return isArray(object) ? result : arrayPush(result, symbolsFunc(object));
|
||||
}
|
||||
|
||||
export default baseGetAllKeys;
|
||||
28
datav-bank/src/utils/lodash/_baseGetTag.js
Normal file
28
datav-bank/src/utils/lodash/_baseGetTag.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import Symbol from './_Symbol.js';
|
||||
import getRawTag from './_getRawTag.js';
|
||||
import objectToString from './_objectToString.js';
|
||||
|
||||
/** `Object#toString` result references. */
|
||||
var nullTag = '[object Null]',
|
||||
undefinedTag = '[object Undefined]';
|
||||
|
||||
/** Built-in value references. */
|
||||
var symToStringTag = Symbol ? Symbol.toStringTag : undefined;
|
||||
|
||||
/**
|
||||
* The base implementation of `getTag` without fallbacks for buggy environments.
|
||||
*
|
||||
* @private
|
||||
* @param {*} value The value to query.
|
||||
* @returns {string} Returns the `toStringTag`.
|
||||
*/
|
||||
function baseGetTag(value) {
|
||||
if (value == null) {
|
||||
return value === undefined ? undefinedTag : nullTag;
|
||||
}
|
||||
return (symToStringTag && symToStringTag in Object(value))
|
||||
? getRawTag(value)
|
||||
: objectToString(value);
|
||||
}
|
||||
|
||||
export default baseGetTag;
|
||||
14
datav-bank/src/utils/lodash/_baseGt.js
Normal file
14
datav-bank/src/utils/lodash/_baseGt.js
Normal file
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* The base implementation of `_.gt` which doesn't coerce arguments.
|
||||
*
|
||||
* @private
|
||||
* @param {*} value The value to compare.
|
||||
* @param {*} other The other value to compare.
|
||||
* @returns {boolean} Returns `true` if `value` is greater than `other`,
|
||||
* else `false`.
|
||||
*/
|
||||
function baseGt(value, other) {
|
||||
return value > other;
|
||||
}
|
||||
|
||||
export default baseGt;
|
||||
19
datav-bank/src/utils/lodash/_baseHas.js
Normal file
19
datav-bank/src/utils/lodash/_baseHas.js
Normal file
@@ -0,0 +1,19 @@
|
||||
/** Used for built-in method references. */
|
||||
var objectProto = Object.prototype;
|
||||
|
||||
/** Used to check objects for own properties. */
|
||||
var hasOwnProperty = objectProto.hasOwnProperty;
|
||||
|
||||
/**
|
||||
* The base implementation of `_.has` without support for deep paths.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} [object] The object to query.
|
||||
* @param {Array|string} key The key to check.
|
||||
* @returns {boolean} Returns `true` if `key` exists, else `false`.
|
||||
*/
|
||||
function baseHas(object, key) {
|
||||
return object != null && hasOwnProperty.call(object, key);
|
||||
}
|
||||
|
||||
export default baseHas;
|
||||
13
datav-bank/src/utils/lodash/_baseHasIn.js
Normal file
13
datav-bank/src/utils/lodash/_baseHasIn.js
Normal file
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* The base implementation of `_.hasIn` without support for deep paths.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} [object] The object to query.
|
||||
* @param {Array|string} key The key to check.
|
||||
* @returns {boolean} Returns `true` if `key` exists, else `false`.
|
||||
*/
|
||||
function baseHasIn(object, key) {
|
||||
return object != null && key in Object(object);
|
||||
}
|
||||
|
||||
export default baseHasIn;
|
||||
18
datav-bank/src/utils/lodash/_baseInRange.js
Normal file
18
datav-bank/src/utils/lodash/_baseInRange.js
Normal file
@@ -0,0 +1,18 @@
|
||||
/* Built-in method references for those with the same name as other `lodash` methods. */
|
||||
var nativeMax = Math.max,
|
||||
nativeMin = Math.min;
|
||||
|
||||
/**
|
||||
* The base implementation of `_.inRange` which doesn't coerce arguments.
|
||||
*
|
||||
* @private
|
||||
* @param {number} number The number to check.
|
||||
* @param {number} start The start of the range.
|
||||
* @param {number} end The end of the range.
|
||||
* @returns {boolean} Returns `true` if `number` is in the range, else `false`.
|
||||
*/
|
||||
function baseInRange(number, start, end) {
|
||||
return number >= nativeMin(start, end) && number < nativeMax(start, end);
|
||||
}
|
||||
|
||||
export default baseInRange;
|
||||
20
datav-bank/src/utils/lodash/_baseIndexOf.js
Normal file
20
datav-bank/src/utils/lodash/_baseIndexOf.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import baseFindIndex from './_baseFindIndex.js';
|
||||
import baseIsNaN from './_baseIsNaN.js';
|
||||
import strictIndexOf from './_strictIndexOf.js';
|
||||
|
||||
/**
|
||||
* The base implementation of `_.indexOf` without `fromIndex` bounds checks.
|
||||
*
|
||||
* @private
|
||||
* @param {Array} array The array to inspect.
|
||||
* @param {*} value The value to search for.
|
||||
* @param {number} fromIndex The index to search from.
|
||||
* @returns {number} Returns the index of the matched value, else `-1`.
|
||||
*/
|
||||
function baseIndexOf(array, value, fromIndex) {
|
||||
return value === value
|
||||
? strictIndexOf(array, value, fromIndex)
|
||||
: baseFindIndex(array, baseIsNaN, fromIndex);
|
||||
}
|
||||
|
||||
export default baseIndexOf;
|
||||
23
datav-bank/src/utils/lodash/_baseIndexOfWith.js
Normal file
23
datav-bank/src/utils/lodash/_baseIndexOfWith.js
Normal file
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* This function is like `baseIndexOf` except that it accepts a comparator.
|
||||
*
|
||||
* @private
|
||||
* @param {Array} array The array to inspect.
|
||||
* @param {*} value The value to search for.
|
||||
* @param {number} fromIndex The index to search from.
|
||||
* @param {Function} comparator The comparator invoked per element.
|
||||
* @returns {number} Returns the index of the matched value, else `-1`.
|
||||
*/
|
||||
function baseIndexOfWith(array, value, fromIndex, comparator) {
|
||||
var index = fromIndex - 1,
|
||||
length = array.length;
|
||||
|
||||
while (++index < length) {
|
||||
if (comparator(array[index], value)) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
export default baseIndexOfWith;
|
||||
74
datav-bank/src/utils/lodash/_baseIntersection.js
Normal file
74
datav-bank/src/utils/lodash/_baseIntersection.js
Normal file
@@ -0,0 +1,74 @@
|
||||
import SetCache from './_SetCache.js';
|
||||
import arrayIncludes from './_arrayIncludes.js';
|
||||
import arrayIncludesWith from './_arrayIncludesWith.js';
|
||||
import arrayMap from './_arrayMap.js';
|
||||
import baseUnary from './_baseUnary.js';
|
||||
import cacheHas from './_cacheHas.js';
|
||||
|
||||
/* Built-in method references for those with the same name as other `lodash` methods. */
|
||||
var nativeMin = Math.min;
|
||||
|
||||
/**
|
||||
* The base implementation of methods like `_.intersection`, without support
|
||||
* for iteratee shorthands, that accepts an array of arrays to inspect.
|
||||
*
|
||||
* @private
|
||||
* @param {Array} arrays The arrays to inspect.
|
||||
* @param {Function} [iteratee] The iteratee invoked per element.
|
||||
* @param {Function} [comparator] The comparator invoked per element.
|
||||
* @returns {Array} Returns the new array of shared values.
|
||||
*/
|
||||
function baseIntersection(arrays, iteratee, comparator) {
|
||||
var includes = comparator ? arrayIncludesWith : arrayIncludes,
|
||||
length = arrays[0].length,
|
||||
othLength = arrays.length,
|
||||
othIndex = othLength,
|
||||
caches = Array(othLength),
|
||||
maxLength = Infinity,
|
||||
result = [];
|
||||
|
||||
while (othIndex--) {
|
||||
var array = arrays[othIndex];
|
||||
if (othIndex && iteratee) {
|
||||
array = arrayMap(array, baseUnary(iteratee));
|
||||
}
|
||||
maxLength = nativeMin(array.length, maxLength);
|
||||
caches[othIndex] = !comparator && (iteratee || (length >= 120 && array.length >= 120))
|
||||
? new SetCache(othIndex && array)
|
||||
: undefined;
|
||||
}
|
||||
array = arrays[0];
|
||||
|
||||
var index = -1,
|
||||
seen = caches[0];
|
||||
|
||||
outer:
|
||||
while (++index < length && result.length < maxLength) {
|
||||
var value = array[index],
|
||||
computed = iteratee ? iteratee(value) : value;
|
||||
|
||||
value = (comparator || value !== 0) ? value : 0;
|
||||
if (!(seen
|
||||
? cacheHas(seen, computed)
|
||||
: includes(result, computed, comparator)
|
||||
)) {
|
||||
othIndex = othLength;
|
||||
while (--othIndex) {
|
||||
var cache = caches[othIndex];
|
||||
if (!(cache
|
||||
? cacheHas(cache, computed)
|
||||
: includes(arrays[othIndex], computed, comparator))
|
||||
) {
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
if (seen) {
|
||||
seen.push(computed);
|
||||
}
|
||||
result.push(value);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export default baseIntersection;
|
||||
21
datav-bank/src/utils/lodash/_baseInverter.js
Normal file
21
datav-bank/src/utils/lodash/_baseInverter.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import baseForOwn from './_baseForOwn.js';
|
||||
|
||||
/**
|
||||
* The base implementation of `_.invert` and `_.invertBy` which inverts
|
||||
* `object` with values transformed by `iteratee` and set by `setter`.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} object The object to iterate over.
|
||||
* @param {Function} setter The function to set `accumulator` values.
|
||||
* @param {Function} iteratee The iteratee to transform values.
|
||||
* @param {Object} accumulator The initial inverted object.
|
||||
* @returns {Function} Returns `accumulator`.
|
||||
*/
|
||||
function baseInverter(object, setter, iteratee, accumulator) {
|
||||
baseForOwn(object, function(value, key, object) {
|
||||
setter(accumulator, iteratee(value), key, object);
|
||||
});
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
export default baseInverter;
|
||||
24
datav-bank/src/utils/lodash/_baseInvoke.js
Normal file
24
datav-bank/src/utils/lodash/_baseInvoke.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import apply from './_apply.js';
|
||||
import castPath from './_castPath.js';
|
||||
import last from './last.js';
|
||||
import parent from './_parent.js';
|
||||
import toKey from './_toKey.js';
|
||||
|
||||
/**
|
||||
* The base implementation of `_.invoke` without support for individual
|
||||
* method arguments.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} object The object to query.
|
||||
* @param {Array|string} path The path of the method to invoke.
|
||||
* @param {Array} args The arguments to invoke the method with.
|
||||
* @returns {*} Returns the result of the invoked method.
|
||||
*/
|
||||
function baseInvoke(object, path, args) {
|
||||
path = castPath(path, object);
|
||||
object = parent(object, path);
|
||||
var func = object == null ? object : object[toKey(last(path))];
|
||||
return func == null ? undefined : apply(func, object, args);
|
||||
}
|
||||
|
||||
export default baseInvoke;
|
||||
18
datav-bank/src/utils/lodash/_baseIsArguments.js
Normal file
18
datav-bank/src/utils/lodash/_baseIsArguments.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import baseGetTag from './_baseGetTag.js';
|
||||
import isObjectLike from './isObjectLike.js';
|
||||
|
||||
/** `Object#toString` result references. */
|
||||
var argsTag = '[object Arguments]';
|
||||
|
||||
/**
|
||||
* The base implementation of `_.isArguments`.
|
||||
*
|
||||
* @private
|
||||
* @param {*} value The value to check.
|
||||
* @returns {boolean} Returns `true` if `value` is an `arguments` object,
|
||||
*/
|
||||
function baseIsArguments(value) {
|
||||
return isObjectLike(value) && baseGetTag(value) == argsTag;
|
||||
}
|
||||
|
||||
export default baseIsArguments;
|
||||
17
datav-bank/src/utils/lodash/_baseIsArrayBuffer.js
Normal file
17
datav-bank/src/utils/lodash/_baseIsArrayBuffer.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import baseGetTag from './_baseGetTag.js';
|
||||
import isObjectLike from './isObjectLike.js';
|
||||
|
||||
var arrayBufferTag = '[object ArrayBuffer]';
|
||||
|
||||
/**
|
||||
* The base implementation of `_.isArrayBuffer` without Node.js optimizations.
|
||||
*
|
||||
* @private
|
||||
* @param {*} value The value to check.
|
||||
* @returns {boolean} Returns `true` if `value` is an array buffer, else `false`.
|
||||
*/
|
||||
function baseIsArrayBuffer(value) {
|
||||
return isObjectLike(value) && baseGetTag(value) == arrayBufferTag;
|
||||
}
|
||||
|
||||
export default baseIsArrayBuffer;
|
||||
18
datav-bank/src/utils/lodash/_baseIsDate.js
Normal file
18
datav-bank/src/utils/lodash/_baseIsDate.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import baseGetTag from './_baseGetTag.js';
|
||||
import isObjectLike from './isObjectLike.js';
|
||||
|
||||
/** `Object#toString` result references. */
|
||||
var dateTag = '[object Date]';
|
||||
|
||||
/**
|
||||
* The base implementation of `_.isDate` without Node.js optimizations.
|
||||
*
|
||||
* @private
|
||||
* @param {*} value The value to check.
|
||||
* @returns {boolean} Returns `true` if `value` is a date object, else `false`.
|
||||
*/
|
||||
function baseIsDate(value) {
|
||||
return isObjectLike(value) && baseGetTag(value) == dateTag;
|
||||
}
|
||||
|
||||
export default baseIsDate;
|
||||
28
datav-bank/src/utils/lodash/_baseIsEqual.js
Normal file
28
datav-bank/src/utils/lodash/_baseIsEqual.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import baseIsEqualDeep from './_baseIsEqualDeep.js';
|
||||
import isObjectLike from './isObjectLike.js';
|
||||
|
||||
/**
|
||||
* The base implementation of `_.isEqual` which supports partial comparisons
|
||||
* and tracks traversed objects.
|
||||
*
|
||||
* @private
|
||||
* @param {*} value The value to compare.
|
||||
* @param {*} other The other value to compare.
|
||||
* @param {boolean} bitmask The bitmask flags.
|
||||
* 1 - Unordered comparison
|
||||
* 2 - Partial comparison
|
||||
* @param {Function} [customizer] The function to customize comparisons.
|
||||
* @param {Object} [stack] Tracks traversed `value` and `other` objects.
|
||||
* @returns {boolean} Returns `true` if the values are equivalent, else `false`.
|
||||
*/
|
||||
function baseIsEqual(value, other, bitmask, customizer, stack) {
|
||||
if (value === other) {
|
||||
return true;
|
||||
}
|
||||
if (value == null || other == null || (!isObjectLike(value) && !isObjectLike(other))) {
|
||||
return value !== value && other !== other;
|
||||
}
|
||||
return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual, stack);
|
||||
}
|
||||
|
||||
export default baseIsEqual;
|
||||
83
datav-bank/src/utils/lodash/_baseIsEqualDeep.js
Normal file
83
datav-bank/src/utils/lodash/_baseIsEqualDeep.js
Normal file
@@ -0,0 +1,83 @@
|
||||
import Stack from './_Stack.js';
|
||||
import equalArrays from './_equalArrays.js';
|
||||
import equalByTag from './_equalByTag.js';
|
||||
import equalObjects from './_equalObjects.js';
|
||||
import getTag from './_getTag.js';
|
||||
import isArray from './isArray.js';
|
||||
import isBuffer from './isBuffer.js';
|
||||
import isTypedArray from './isTypedArray.js';
|
||||
|
||||
/** Used to compose bitmasks for value comparisons. */
|
||||
var COMPARE_PARTIAL_FLAG = 1;
|
||||
|
||||
/** `Object#toString` result references. */
|
||||
var argsTag = '[object Arguments]',
|
||||
arrayTag = '[object Array]',
|
||||
objectTag = '[object Object]';
|
||||
|
||||
/** Used for built-in method references. */
|
||||
var objectProto = Object.prototype;
|
||||
|
||||
/** Used to check objects for own properties. */
|
||||
var hasOwnProperty = objectProto.hasOwnProperty;
|
||||
|
||||
/**
|
||||
* A specialized version of `baseIsEqual` for arrays and objects which performs
|
||||
* deep comparisons and tracks traversed objects enabling objects with circular
|
||||
* references to be compared.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} object The object to compare.
|
||||
* @param {Object} other The other object to compare.
|
||||
* @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
|
||||
* @param {Function} customizer The function to customize comparisons.
|
||||
* @param {Function} equalFunc The function to determine equivalents of values.
|
||||
* @param {Object} [stack] Tracks traversed `object` and `other` objects.
|
||||
* @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
|
||||
*/
|
||||
function baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) {
|
||||
var objIsArr = isArray(object),
|
||||
othIsArr = isArray(other),
|
||||
objTag = objIsArr ? arrayTag : getTag(object),
|
||||
othTag = othIsArr ? arrayTag : getTag(other);
|
||||
|
||||
objTag = objTag == argsTag ? objectTag : objTag;
|
||||
othTag = othTag == argsTag ? objectTag : othTag;
|
||||
|
||||
var objIsObj = objTag == objectTag,
|
||||
othIsObj = othTag == objectTag,
|
||||
isSameTag = objTag == othTag;
|
||||
|
||||
if (isSameTag && isBuffer(object)) {
|
||||
if (!isBuffer(other)) {
|
||||
return false;
|
||||
}
|
||||
objIsArr = true;
|
||||
objIsObj = false;
|
||||
}
|
||||
if (isSameTag && !objIsObj) {
|
||||
stack || (stack = new Stack);
|
||||
return (objIsArr || isTypedArray(object))
|
||||
? equalArrays(object, other, bitmask, customizer, equalFunc, stack)
|
||||
: equalByTag(object, other, objTag, bitmask, customizer, equalFunc, stack);
|
||||
}
|
||||
if (!(bitmask & COMPARE_PARTIAL_FLAG)) {
|
||||
var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),
|
||||
othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');
|
||||
|
||||
if (objIsWrapped || othIsWrapped) {
|
||||
var objUnwrapped = objIsWrapped ? object.value() : object,
|
||||
othUnwrapped = othIsWrapped ? other.value() : other;
|
||||
|
||||
stack || (stack = new Stack);
|
||||
return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack);
|
||||
}
|
||||
}
|
||||
if (!isSameTag) {
|
||||
return false;
|
||||
}
|
||||
stack || (stack = new Stack);
|
||||
return equalObjects(object, other, bitmask, customizer, equalFunc, stack);
|
||||
}
|
||||
|
||||
export default baseIsEqualDeep;
|
||||
18
datav-bank/src/utils/lodash/_baseIsMap.js
Normal file
18
datav-bank/src/utils/lodash/_baseIsMap.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import getTag from './_getTag.js';
|
||||
import isObjectLike from './isObjectLike.js';
|
||||
|
||||
/** `Object#toString` result references. */
|
||||
var mapTag = '[object Map]';
|
||||
|
||||
/**
|
||||
* The base implementation of `_.isMap` without Node.js optimizations.
|
||||
*
|
||||
* @private
|
||||
* @param {*} value The value to check.
|
||||
* @returns {boolean} Returns `true` if `value` is a map, else `false`.
|
||||
*/
|
||||
function baseIsMap(value) {
|
||||
return isObjectLike(value) && getTag(value) == mapTag;
|
||||
}
|
||||
|
||||
export default baseIsMap;
|
||||
62
datav-bank/src/utils/lodash/_baseIsMatch.js
Normal file
62
datav-bank/src/utils/lodash/_baseIsMatch.js
Normal file
@@ -0,0 +1,62 @@
|
||||
import Stack from './_Stack.js';
|
||||
import baseIsEqual from './_baseIsEqual.js';
|
||||
|
||||
/** Used to compose bitmasks for value comparisons. */
|
||||
var COMPARE_PARTIAL_FLAG = 1,
|
||||
COMPARE_UNORDERED_FLAG = 2;
|
||||
|
||||
/**
|
||||
* The base implementation of `_.isMatch` without support for iteratee shorthands.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} object The object to inspect.
|
||||
* @param {Object} source The object of property values to match.
|
||||
* @param {Array} matchData The property names, values, and compare flags to match.
|
||||
* @param {Function} [customizer] The function to customize comparisons.
|
||||
* @returns {boolean} Returns `true` if `object` is a match, else `false`.
|
||||
*/
|
||||
function baseIsMatch(object, source, matchData, customizer) {
|
||||
var index = matchData.length,
|
||||
length = index,
|
||||
noCustomizer = !customizer;
|
||||
|
||||
if (object == null) {
|
||||
return !length;
|
||||
}
|
||||
object = Object(object);
|
||||
while (index--) {
|
||||
var data = matchData[index];
|
||||
if ((noCustomizer && data[2])
|
||||
? data[1] !== object[data[0]]
|
||||
: !(data[0] in object)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
while (++index < length) {
|
||||
data = matchData[index];
|
||||
var key = data[0],
|
||||
objValue = object[key],
|
||||
srcValue = data[1];
|
||||
|
||||
if (noCustomizer && data[2]) {
|
||||
if (objValue === undefined && !(key in object)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
var stack = new Stack;
|
||||
if (customizer) {
|
||||
var result = customizer(objValue, srcValue, key, object, source, stack);
|
||||
}
|
||||
if (!(result === undefined
|
||||
? baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG, customizer, stack)
|
||||
: result
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export default baseIsMatch;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user