一、前言:从数据展示到交互洞察的跃迁
在前两个实验中,我们分别完成了浏览器市场分析大屏的静态布局与数据接入,以及用户画像大屏的多维度数据绑定和筛选器联动。然而,一个真正具备商业价值的可视化大屏,不仅需要"能看",更需要"能交互"——让用户通过简单的点击、切换,就能深入挖掘数据背后的洞察。
本实验将带领大家进入Max蓝图编辑器的高级交互领域,实现三大核心功能:
Tab导航切换:通过图层可见性控制,在同一文件中实现"市场分析"与"用户画像"两个大屏的无缝切换
地图省份点击下钻:点击地图省份,右侧核心指标卡动态更新为该省份数据
热力图动态渲染:根据用户数自动渲染地图颜色深浅,实现地理分布的可视化
无需编写后端API,无需复杂的前端事件监听,只需在蓝图编辑器中拖拽节点、配置逻辑,即可完成企业级交互大屏。
二、实验目标与核心技能图谱
2.1 实验目的
| 图层管理 | 使用图层可见性控制实现大屏内容切换 |
| 导航交互 | 使用Tab列表组件配置页面内容显示/隐藏 |
| 地理下钻 | 使用地图组件交互事件实现省份点击联动 |
| 数据联动 | 配置指标卡组件根据地图点击动态更新数据 |
| 热力渲染 | 基于adcode映射实现地图热力层动态着色 |
2.2 实验环境
-
实验平台:助睿在线实验平台
-
可视化工具:助睿Max(一站式数据可视化平台)
-
数据来源:团队私有数据库(MySQL)
-
前置实验:实验6-1(静态布局)、实验6-2(数据接入)
2.3 最终效果预览
完成本实验后,您的大屏将具备以下交互能力:
-
✅ 顶部Tab导航一键切换"市场分析"与"用户画像"
-
✅ 地图根据当前浏览器用户数自动渲染颜色深浅(热力图)
-
✅ 点击任意省份,右侧四个核心指标卡实时刷新为该省份数据
-
✅ 切换浏览器筛选器,地图热力图同步更新
三、整体交互架构设计
3.1 系统交互全景图

3.2 两大核心交互链路
链路一:大屏切换交互(图层可见性控制)
Tab列表组件
│
├── 点击"市场分析" (id=1) ──→ 分支判断(id==1)为真
│ ├── 设置图层:市场分析组 → 显示
│ └── 设置图层:用户画像组 → 隐藏
│
└── 点击"用户画像" (id=2) ──→ 分支判断(id==1)为假
├── 设置图层:市场分析组 → 隐藏
└── 设置图层:用户画像组 → 显示
链路二:地图省份点击联动(地理下钻)
基础平面地图(区域热力层)
│
├── 点击区域时事件 ──→ 提取地区名称(并行数据处理)
│ │
│ ├── 省份全称 → 简称映射
│ └── 存入全局变量 window.globalProvinceName
│ │
│ └──→ 省份核心指标查询(SQL请求)
│ │
│ ├── 读取 window.globalProvinceName
│ ├── 读取 window.GLOBAL_SELECTED_BROWSER
│ └── 执行动态SQL
│ │
│ └──→ 省份核心指标分发(并行数据处理)
│ │
│ ├── 分支1:总用户数 → 指标卡1
│ ├── 分支2:平均年龄 → 指标卡2
│ ├── 分支3:本科占比 → 指标卡3
│ └── 分支4:中高收入占比 → 指标卡4
│
└── 热力渲染链路(独立)
│
├── 地理边界geojson加载完成 ──→ 提取adcode映射表
│ │
│ └── 存入 window.globalProvinceAdcode
│ │
└── 浏览器切换/页面加载 ──→ 各省份用户数查询(SQL)
│
└──→ 地图数据与用户数映射
│
└──→ 导入热力值数据接口
四、核心技术深度解析
4.1 图层可见性控制:单文件多屏方案
设计背景:在实际业务场景中,一个数据分析项目往往包含多个视角(如市场分析、用户画像、运营监控)。如果每个视角都创建独立的大屏文件,会导致:
-
维护成本高(样式、数据源需重复配置)
-
切换体验差(页面跳转有白屏)
-
状态丢失(筛选器状态无法跨页面传递)
Max解决方案:通过图层组 + 可见性控制,在同一文件中管理多个大屏内容。
技术原理:
-
将"市场分析"所有组件放入一个图层组(如"市场分析组")
-
将"用户画像"所有组件放入另一个图层组(如"用户画像组")
-
通过Tab列表组件的点击事件,控制两个组的显示/隐藏状态
优势对比:
| 独立文件 | 2+ | 差(页面跳转) | 不支持 | 高 |
| 图层切换(本方案) | 1 | 优(无刷新) | 支持 | 低 |
4.2 地图交互事件体系
Max地图组件(基础平面地图)提供了丰富的交互事件:
| 当数据接口地理边界geojson数据加载完成时 | 地图GeoJSON加载完成 | GeoJSON对象(含features数组) |
| 点击区域时 | 用户点击某个省份区域 | { name, adcode, … } |
| 鼠标移入区域触发 | 鼠标悬停省份 | { name, adcode, … } |
| 鼠标移出区域触发 | 鼠标离开省份 | { name, adcode, … } |
本实验使用的事件:
-
点击区域时:触发省份下钻,更新指标卡
-
当数据接口地理边界geojson数据加载完成时:提取adcode映射表,为热力渲染做准备
4.3 省份名称标准化:全称与简称的映射
问题背景:地图组件返回的省份名称是全称(如"江苏省"、"广西壮族自治区"),但数据库中存储的是简称(如"江苏"、"广西")。直接用于SQL查询会导致匹配失败。
解决方案:建立双向映射表,在数据流中进行名称转换。
// 特殊映射表(直辖市、自治区、特别行政区)
const specialMap = {
'北京市': '北京', '天津市': '天津', '上海市': '上海', '重庆市': '重庆',
'广西壮族自治区': '广西', '内蒙古自治区': '内蒙古',
'西藏自治区': '西藏', '宁夏回族自治区': '宁夏',
'新疆维吾尔自治区': '新疆',
'香港特别行政区': '香港', '澳门特别行政区': '澳门'
};
通用处理规则:
优先匹配特殊映射表(处理直辖市、自治区等特殊情况)
通用处理:去除末尾的"省"、"自治区"、"市"后缀
最终得到数据库可识别的简称
4.4 行政区划代码(adcode)映射
什么是adcode? adcode是国家统计局发布的行政区划代码,是地图渲染的"身份证"。Max地图组件通过adcode识别每个省份的边界和位置。
为什么需要adcode映射?
地图热力层的数据格式要求:
{
"name": "江苏",
"value": 1500,
"area_id": 320000
}
其中 area_id 就是adcode。因此,我们需要建立"省份名称 → adcode"的映射关系。
数据来源:地图组件内置的GeoJSON数据中已经包含了每个省份的adcode,只需在加载完成后提取即可。
五、实验步骤详解
5.1 Step 1:配置大屏Tab导航切换
5.1.1 设计思路
Tab列表组件是一个可自定义选项的交互组件。本实验的核心技巧是"透明化"——将Tab列表的背景色、选中背景色、悬浮背景色的透明度都设为0,使其与顶部的导航按钮完全重合,给用户"点击按钮切换页面"的错觉,实际上是通过图层可见性控制实现内容切换。
5.1.2 组件配置
(1)添加Tab列表组件
-
从组件库拖拽"Tab列表"组件到画布顶部导航区域

-
调整大小和位置,使其与两个导航按钮("市场分析"、"用户画像")完全重合

(2)样式配置(透明化处理)
在Tab列表组件的基本设置中:
-
行数:1
-
列数:2

-
在标签默认配置中,将以下三项的透明度设置为 0:
-
背景颜色
-
选中背景色
-
悬浮背景色

-
效果:Tab列表组件完全透明,用户只能看到底层的导航按钮文字,但点击区域实际由Tab列表捕获。
(3)数据配置
在数据面板中,保留2列数据:
[
{ "id": 1, "content": "" },
{ "id": 2, "content": "" }
]
-
id:用于分支判断,区分"市场分析"和"用户画像"
-
content:设为空字符串(因为按钮文字由底层样式提供)
配置完成后,点击刷新数据按钮。
5.1.3 蓝图编辑器配置
(1)导出组件
将以下组件导出到蓝图编辑器:
-
"市场分析"组(图层组)
-
"用户画像"组(图层组)
-
Tab列表组件

(2)添加分支判断节点
添加"分支判断"节点,配置处理方法:
return data.id == 1;
逻辑说明:
-
当用户点击"市场分析"时,Tab列表输出 { id: 1 },表达式为 true
-
当用户点击"用户画像"时,Tab列表输出 { id: 2 },表达式为 false
(3)配置"满足"分支(id=1,显示市场分析)
在"分支判断"的满足分支上,添加两个"设置图层可见性"动作:
| 市场分析组 | 显示 |
| 用户画像组 | 隐藏 |
(4)配置"不满足"分支(id=2,显示用户画像)
在"分支判断"的不满足分支上,添加两个"设置图层可见性"动作:
| 市场分析组 | 隐藏 |
| 用户画像组 | 显示 |
(5)节点连线
5.1.4 验证要点
-
[ ] 点击"市场分析"按钮,市场分析大屏显示,用户画像大屏隐藏
-
[ ] 点击"用户画像"按钮,用户画像大屏显示,市场分析大屏隐藏
-
[ ] 切换过程无页面刷新,体验流畅
5.2 Step 2:配置地图省份点击联动
5.2.1 设计思路
用户点击地图省份 → 提取省份名称 → 查询该省份核心指标 → 分发到四个指标卡。这是典型的地理下钻分析(Geo-drilldown)。
5.2.2 核心组件配置
(1)提取地区名称(并行数据处理节点)
作用:接收地图点击事件输出的数据对象,提取省份名称,通过映射表转换为简称,存入全局变量。
节点配置:
添加"并行数据处理"节点,重命名为"提取地区名称"。
处理方法代码:
// 省份特殊映射(直辖市、自治区、特别行政区)
const specialMap = {
'北京市': '北京',
'天津市': '天津',
'上海市': '上海',
'重庆市': '重庆',
'广西壮族自治区': '广西',
'内蒙古自治区': '内蒙古',
'西藏自治区': '西藏',
'宁夏回族自治区': '宁夏',
'新疆维吾尔自治区': '新疆',
'香港特别行政区': '香港',
'澳门特别行政区': '澳门'
};
let provinceName = data.name;
// 优先使用特殊映射
if (specialMap[provinceName]) {
provinceName = specialMap[provinceName];
} else {
// 通用处理:去除末尾的"省"、"自治区"、"市"
provinceName = provinceName.replace(/(省|自治区|市)$/, '');
}
// 存入全局变量,供后续SQL节点读取
window.globalProvinceName = provinceName;
return provinceName;
代码解析:
| 特殊映射 | 直接查表 | "北京市" → "北京" |
| 通用处理 | 正则去除后缀 | "江苏省" → "江苏" |
| 全局存储 | window.globalProvinceName | 跨节点共享 |
(2)省份核心指标查询(SQL请求节点)
作用:根据当前选中的浏览器和点击的省份,查询四个核心指标。
节点配置:
添加"SQL请求"节点,重命名为"省份核心指标查询"。
处理方法代码:
const selectedProvince = window.globalProvinceName;
console.log("点击的省份名称(处理后):", selectedProvince);
const selectedBrowser = window.GLOBAL_SELECTED_BROWSER;
const sql = `
— 指标1:总用户数
select 'total_users' as name, sum(user_count) as value
from labs.user_profile_stats
where browser_name = '${selectedBrowser}'
and province = '${selectedProvince}'
union all
— 指标2:平均年龄(加权平均)
select 'avg_age' as name,
round(sum(age * user_count) / sum(user_count), 0) as value
from labs.user_profile_stats
where browser_name = '${selectedBrowser}'
and province = '${selectedProvince}'
union all
— 指标3:本科及以上占比
select 'high_edu_ratio' as name,
round(
sum(case when edu in ('本科', '硕士及以上') then user_count else 0 end) * 100.0 / sum(user_count),
2
) as value
from labs.user_profile_stats
where browser_name = '${selectedBrowser}'
and province = '${selectedProvince}'
union all
— 指标4:中高收入占比
select 'high_income_ratio' as name,
round(
sum(case when income in ('5001~8000元', '8001~12000元', '12000元以上')
then user_count else 0 end) * 100.0 / sum(user_count),
2
) as value
from labs.user_profile_stats
where browser_name = '${selectedBrowser}'
and province = '${selectedProvince}'
`;
console.log("生成的省份核心指标SQL:", sql);
return sql;
SQL设计要点:
| 总用户数 | SUM(user_count) | 整数 |
| 平均年龄 | SUM(age * user_count) / SUM(user_count) | 0位小数 |
| 本科及以上占比 | CASE WHEN 条件计数 / 总数 × 100% | 2位小数 |
| 中高收入占比 | 多值匹配 + 条件计数 / 总数 × 100% | 2位小数 |
为什么用 UNION ALL? 四个指标结构相同(name, value),合并为一次查询减少数据库往返。每个指标通过 name 字段标识,便于后续分发。
(3)省份核心指标分发(并行数据处理节点)
作用:将SQL返回的四行数据拆分为四个独立数值,分别发送给对应的指标卡。
节点配置:
添加"并行数据处理"节点,重命名为"省份核心指标分发"。
分支1:总用户数 → 总用户数指标卡
var item = data.find(item => item.name === 'total_users');
return [{ value: item ? item.value : 0 }];
分支2:平均年龄 → 平均年龄指标卡
var item = data.find(item => item.name === 'avg_age');
return [{ value: item ? item.value : 0 }];
分支3:本科及以上占比 → 本科及以上占比指标卡
var item = data.find(item => item.name === 'high_edu_ratio');
return [{ value: item ? item.value : 0 }];
分支4:中高收入占比 → 中高收入占比指标卡
var item = data.find(item => item.name === 'high_income_ratio');
return [{ value: item ? item.value : 0 }];
5.2.3 蓝图连线

5.2.4 验证要点
-
[ ] 点击地图上的江苏省,指标卡显示江苏省的数据
-
[ ] 点击地图上的广东省,指标卡显示广东省的数据
-
[ ] 指标数据与当前选中的浏览器一致(如当前选中Chrome,则显示Chrome在江苏的数据)
-
[ ] 切换浏览器后,再次点击同一省份,数据应相应变化
5.3 Step 3:配置地图热力层动态渲染
5.3.1 设计思路
为了直观展示全国各省份的用户分布,需要在地图上用颜色深浅表示用户数(用户数越多,颜色越深)。这需要完成三个步骤:
提取adcode映射表:从地图GeoJSON中提取"省份名称 → adcode"映射
查询各省份用户数:按浏览器统计每个省份的用户总数
数据映射与格式化:将查询结果匹配adcode,输出热力层所需格式
5.3.2 核心组件配置
(1)提取adcode映射表(并行数据处理节点)
作用:在地图GeoJSON加载完成后,提取每个省份的adcode和名称,建立映射表。
触发时机:区域热力层的当数据接口地理边界geojson数据加载完成时事件
节点配置:
添加"并行数据处理"节点,重命名为"提取adcode映射表"。
处理方法代码:
/**
* 提取地理数据中的 adcode 和 name,建立名称→adcode 映射
* @param {Object} data – 地理数据对象(包含 features 数组)
* @returns {Object} 名称到 adcode 的映射表
*/
function extractAdcodeAndName(data) {
if (!data || !Array.isArray(data.features)) {
console.error('无效的地图数据格式');
return {};
}
const nameToAdcode = {};
data.features.forEach(feature => {
const props = feature.properties;
if (props && props.adcode && props.name) {
nameToAdcode[props.name] = props.adcode;
}
});
return nameToAdcode;
}
const mapping = extractAdcodeAndName(data);
// 存入全局变量,供后续热力数据映射使用
window.globalProvinceAdcode = mapping;
console.log("省份adcode映射表已加载", Object.keys(mapping).length);
return mapping;
代码解析:
| 数据校验 | 检查 data.features 是否为数组 | 防御性编程 |
| 遍历features | forEach 遍历每个省份 | GeoJSON标准结构 |
| 提取属性 | feature.properties.adcode / .name | GeoJSON规范 |
| 全局存储 | window.globalProvinceAdcode | 跨节点共享 |
(2)各省份用户数查询(SQL请求节点)
作用:根据当前选中的浏览器,统计每个省份的用户总数。
节点配置:
添加"SQL请求"节点,重命名为"各省份用户数查询"。
处理方法代码:
const selectedBrowser = window.GLOBAL_SELECTED_BROWSER;
const sql = `
SELECT
province AS name,
SUM(user_count) AS value
FROM labs.user_profile_stats
WHERE browser_name = '${selectedBrowser}'
AND province IS NOT NULL
AND province != ''
GROUP BY province
ORDER BY value DESC
`;
console.log("生成的所有省份用户数SQL:", sql);
return sql;
SQL设计要点:
-
GROUP BY province:按省份聚合
-
ORDER BY value DESC:按用户数降序排列,便于查看TOP省份
-
AND province IS NOT NULL AND province != '':过滤空值,避免地图渲染异常
(3)地图数据与用户数映射(并行数据处理节点)
作用:将SQL查询结果中的省份名称与adcode映射表匹配,生成热力层所需的 { name, value, area_id } 格式。
节点配置:
添加"并行数据处理"节点,重命名为"地图数据与用户数映射"。
处理方法代码:
function convertToMapData(data) {
if (!Array.isArray(data) || data.length === 0) {
return [];
}
return data.map(item => {
const provinceName = item.name;
// 第一步:直接匹配
let area_id = window.globalProvinceAdcode[provinceName];
// 第二步:如果直接匹配失败,尝试简化名称
if (!area_id) {
const simplifiedName = provinceName.replace(
/省|市|自治区|特别行政区|回族|壮族|维吾尔|藏族|苗族/g,
''
);
for (const fullName in window.globalProvinceAdcode) {
if (fullName.includes(simplifiedName)) {
area_id = window.globalProvinceAdcode[fullName];
break;
}
}
}
// 第三步:兜底处理
if (!area_id) {
// console.warn(`未找到省份 "${provinceName}" 的匹配 adcode`);
area_id = "000000";
}
return {
name: provinceName,
value: parseFloat(item.value) || 0,
area_id: Number(area_id)
};
});
}
const result = convertToMapData(data);
// console.log("最终返回的地图热力数据:", result);
return result;
映射策略详解:
| 第一层:直接匹配 | globalProvinceAdcode[provinceName] | 名称完全一致 |
| 第二层:简化匹配 | 去除后缀后模糊匹配 | 数据库简称 vs GeoJSON全称 |
| 第三层:兜底处理 | 使用默认adcode "000000" | 防止渲染崩溃 |
数据格式说明:
热力层要求的数据格式:
[
{ "name": "江苏", "value": 1500, "area_id": 320000 },
{ "name": "广东", "value": 2300, "area_id": 440000 }
]
-
name:省份名称(用于tooltip显示)
-
value:用户数(用于颜色深浅计算)
-
area_id:adcode(用于定位省份边界)
5.3.3 蓝图连线(热力渲染链路)

5.3.4 验证要点
-
[ ] 地图加载后,各省份呈现不同颜色深浅
-
[ ] 用户数最多的省份颜色最深
-
[ ] 切换浏览器筛选器,地图颜色分布相应变化
-
[ ] 无数据的省份显示为默认颜色(或灰色)
5.4 Step 4:完整蓝图整合
完成以上三个步骤后,您的蓝图应包含以下完整的数据流:
5.4.1 大屏切换链路
5.4.2 省份点击下钻链路
5.4.3 热力渲染链路
六、关键技术深度解析
6.1 全局变量管理策略
本实验使用了多个全局变量进行跨节点数据共享:
| window.GLOBAL_SELECTED_BROWSER | 当前选中的浏览器 | 浏览器参数接收 | 各SQL请求节点 |
| window.globalProvinceName | 点击的省份简称 | 提取地区名称 | 省份核心指标查询 |
| window.globalProvinceAdcode | 省份名称→adcode映射 | 提取adcode映射表 | 地图数据与用户数映射 |
设计原则:
-
✅ 单一职责:每个变量只存储一种数据
-
✅ 命名规范:使用 GLOBAL_ 前缀标识全局变量
-
✅ 生命周期:在页面加载时初始化,在交互事件中更新
6.2 分支判断节点的条件表达式
本实验中的分支判断使用简单的等值判断:
return data.id == 1;
进阶用法:
| 多Tab切换 | return data.id; | 直接返回ID,配合多分支 |
| 范围判断 | return data.value > 100; | 数值阈值判断 |
| 复合条件 | return data.id == 1 && data.type == 'market'; | 多条件组合 |
| 字符串匹配 | return data.name.includes('北京'); | 模糊匹配 |
6.3 地图热力层的数据驱动原理
Max地图组件的热力渲染基于数据驱动模式:
原始数据(省份+用户数)
│
├──→ 数据映射(匹配adcode)
│
├──→ 颜色映射(value → 颜色深浅)
│ 平台内置算法:根据value范围自动分配颜色梯度
│
└──→ 渲染层(Canvas/SVG绘制)
颜色映射算法(平台内部实现):
-
自动计算数据的最大值和最小值
-
将数值范围映射到颜色梯度(如浅蓝 → 深蓝)
-
支持自定义颜色主题
七、常见问题与解决方案
Q1:Tab切换时,两个大屏内容重叠显示
原因:图层可见性配置错误,或两个组未正确分组。
解决方案:
确认"市场分析组"和"用户画像组"是独立的图层组
检查分支判断的两个分支是否分别配置了"显示"和"隐藏"
初始状态下,确保只有一个组是可见的
Q2:点击地图省份,指标卡数据不更新
排查步骤:
在"提取地区名称"节点添加 console.log(data),确认是否接收到点击事件
检查 window.globalProvinceName 是否正确赋值
在"省份核心指标查询"节点添加 console.log(sql),确认SQL语句正确
检查数据库中该省份+浏览器的组合是否有数据
Q3:地图热力层不显示颜色
排查步骤:
确认"提取adcode映射表"节点是否正确执行(检查控制台日志)
检查 window.globalProvinceAdcode 是否包含有效的映射关系
在"地图数据与用户数映射"节点添加调试代码,确认输出格式为 { name, value, area_id }
检查 area_id 是否为数字类型(字符串会导致匹配失败)
Q4:省份名称映射失败(如"内蒙古自治区"无法匹配)
原因:简化名称的逻辑未能覆盖所有特殊情况。
解决方案:
-
在 specialMap 中添加缺失的映射
-
或在简化名称逻辑中增加更多的正则替换规则
Q5:切换浏览器后,地图热力图未更新
原因:热力渲染链路未与浏览器筛选器联动。
解决方案:
-
确认"各省份用户数查询"节点的触发源包含"浏览器筛选器"
-
确认SQL中使用了 window.GLOBAL_SELECTED_BROWSER 变量
八、实验总结与进阶思考
8.1 核心收获
通过本实验,我们完成了从数据展示到交互洞察的完整闭环:
| Tab导航切换 | 图层可见性控制 + 分支判断 | 单文件管理多屏,降低维护成本 |
| 省份点击下钻 | 事件驱动 + 动态SQL + 数据分发 | 地理维度深入分析 |
| 热力图渲染 | GeoJSON解析 + adcode映射 + 数据驱动着色 | 直观展示地理分布差异 |
8.2 可扩展的交互场景
基于本实验的技术框架,可以进一步扩展:
| 双击下钻到城市 | 地图组件支持多级下钻,配置城市级GeoJSON |
| 时间轴播放 | 添加时间筛选器,实现数据随时间变化的热力图动画 |
| 多指标切换 | 添加指标切换按钮,热力图按不同指标(用户数/时长/收入)渲染 |
| 联动高亮 | 点击省份时,同时高亮该省份在所有图表中的数据 |
| 数据下钻弹窗 | 点击省份后弹出模态框,展示该省份的详细用户画像 |
8.3 性能优化建议
| SQL优化 | 为 browser_name + province 添加联合索引 | 查询速度提升60%+ |
| 数据缓存 | 对adcode映射表进行本地缓存 | 避免重复解析GeoJSON |
| 懒加载 | 市场分析组数据延迟加载 | 首屏加载时间减少40% |
| 防抖处理 | 地图点击添加防抖(300ms) | 避免快速点击导致多次请求 |
8.4 发布与分享
完成所有配置后,点击"发布"按钮:
打开发布分享开关
复制分享链接
在浏览器中打开链接,即可在线观看
示例分享链接格式:
http://47.109.66.142:30887/#/dataScreen/release?shareId=cb73b29223c74387a7cb02880d010c0b
九、完整代码速查表
9.1 省份名称映射代码
const specialMap = {
'北京市': '北京', '天津市': '天津', '上海市': '上海', '重庆市': '重庆',
'广西壮族自治区': '广西', '内蒙古自治区': '内蒙古', '西藏自治区': '西藏',
'宁夏回族自治区': '宁夏', '新疆维吾尔自治区': '新疆',
'香港特别行政区': '香港', '澳门特别行政区': '澳门'
};
let provinceName = data.name;
if (specialMap[provinceName]) {
provinceName = specialMap[provinceName];
} else {
provinceName = provinceName.replace(/(省|自治区|市)$/, '');
}
window.globalProvinceName = provinceName;
return provinceName;
9.2 省份核心指标SQL模板
const selectedProvince = window.globalProvinceName;
const selectedBrowser = window.GLOBAL_SELECTED_BROWSER;
const sql = `
select 'total_users' as name, sum(user_count) as value
from labs.user_profile_stats
where browser_name = '${selectedBrowser}' and province = '${selectedProvince}'
union all
select 'avg_age' as name,
round(sum(age * user_count) / sum(user_count), 0) as value
from labs.user_profile_stats
where browser_name = '${selectedBrowser}' and province = '${selectedProvince}'
union all
select 'high_edu_ratio' as name,
round(sum(case when edu in ('本科', '硕士及以上') then user_count else 0 end) * 100.0 / sum(user_count), 2) as value
from labs.user_profile_stats
where browser_name = '${selectedBrowser}' and province = '${selectedProvince}'
union all
select 'high_income_ratio' as name,
round(sum(case when income in ('5001~8000元', '8001~12000元','12000元以上') then user_count else 0 end) * 100.0 / sum(user_count), 2) as value
from labs.user_profile_stats
where browser_name = '${selectedBrowser}' and province = '${selectedProvince}'
`;
return sql;
9.3 adcode提取代码
function extractAdcodeAndName(data) {
if (!data || !Array.isArray(data.features)) {
console.error('无效的地图数据格式');
return {};
}
const nameToAdcode = {};
data.features.forEach(feature => {
const props = feature.properties;
if (props && props.adcode && props.name) {
nameToAdcode[props.name] = props.adcode;
}
});
return nameToAdcode;
}
const mapping = extractAdcodeAndName(data);
window.globalProvinceAdcode = mapping;
return mapping;
9.4 热力数据映射代码
function convertToMapData(data) {
if (!Array.isArray(data) || data.length === 0) return [];
return data.map(item => {
const provinceName = item.name;
let area_id = window.globalProvinceAdcode[provinceName];
if (!area_id) {
const simplifiedName = provinceName.replace(/省|市|自治区|特别行政区|回族|壮族|维吾尔|藏族|苗族/g, '');
for (const fullName in window.globalProvinceAdcode) {
if (fullName.includes(simplifiedName)) {
area_id = window.globalProvinceAdcode[fullName];
break;
}
}
}
if (!area_id) area_id = "000000";
return {
name: provinceName,
value: parseFloat(item.value) || 0,
area_id: Number(area_id)
};
});
}
return convertToMapData(data);
版权声明:本文为实验平台实验指导内容的技术总结,仅供学习交流使用。
发布日期:2026年6月


