热力图 数据生成与展示

1 篇文章 0 订阅

后台数据生成

local setting = require("bundle://setting");
local fs = require("fs");
local math = require("math");
local json = require("json");

local heatmap_config = setting.heatmap_config;
local root = heatmap_config.root;

local radius_level_value = heatmap_config.radius_level_value;
local raduis_level_max = heatmap_config.raduis_level_max;


local r,err = fs.existsSync(root);
if not r then
    fs.mkdirSync(root);
end

-- 半径等级划分原则
local function getLevelByMax(val, max)
	local level = math.floor(val*10/max);
	if level == 0 then level = 1; end
	return level;
end

-- 半径扩大原则
local function getRadiusByLevel(level, base)
	return base*level;
end

-- 碰撞检测
local function checkImpact(old, new, hmap)
	-- 根据点被点击的次数和点击最大值,计算出这个点的级别,级别越高,点的半径越大
	local level = getLevelByMax(old.value, hmap.max);
	-- 根据级别和半径单位,获取真实半径
	local radius = getRadiusByLevel(level, radius_level_value);

	-- 如果新的点,在老的点的范围内,那么就算碰撞了
	if radius >= math.floor(math.sqrt(math.pow(old.y - new.y, 2) + math.pow(old.x - new.x, 2))) then
		return old;
	end
end

local function merge_points(old, new, hmap)
	-- 圆心均衡
	old.x = math.floor((old.value*old.x + new.x)/(old.value+1));
	old.y = math.floor((old.value*old.y + new.y)/(old.value+1));
	old.value = 1 + old.value;
end


-- 将数据进行简化
local function analysis(req, parseconfig)
	if not req.ps.head or not req.ps.record then return {ret = -1, err="热力图解析失败: req.ps.head或req.ps.record不存在"}; end

	local gameid = req.ps.head.gameid or req.ps.gameid;
	local source = req.ps.head.source or req.ps.source;
	local timestamp = tonumber(req.ps.head.timestamp or req.ps.timestamp);

	if not source then return {ret = -1, err = "热力图解析失败: 没有source字段, 请检查数据格式"} end
	if not gameid then return {ret = -1, err = "热力图解析失败: 没有gameid字段, 请检查数据格式"} end
	if not timestamp then return {ret = -1, err = "热力图解析失败: 没有gameid字段, 请检查数据格式"} end

	local openfds = {};

	local now = timestamp;
	-- 时间目录
	local datepath = string.format("%s/%s", root, os.date("%Y%m%d", now));
	-- gameid_source目录
	local gid_source_path = string.format("%s/%s_%s", datepath, gameid, source);
	if not fs.existsSync(datepath) then fs.mkdirSync(datepath) end
	if not fs.existsSync(gid_source_path) then fs.mkdirSync(gid_source_path) end

	local abs_dir = gid_source_path;

	local record = req.ps.record;
	for i,v in ipairs(record) do
		-- 坐标取整数
		local point = {x = math.floor(v.px/100), y = math.floor(v.py/100)};

		-- 取不为0的坐标,掐坐标没有意义
		if point.x ~= 0 and point.y ~= 0 then
			local page = v.page;
			local layer = v.layer;
			local file;

			-- 优先保存到layer
			if layer and layer ~= '' then
				file = layer;
			elseif page and page ~= '' then
				file = page;
			end

			-- 如果有page或者layer存在的情况,点击坐标才有效
			if file then
				
				local filepath = string.format("%s/%s.log", abs_dir, file);

				-- 缓存的热力图数据
				local hmap = openfds[filepath];

				-- 没有缓存的热力图数据就去文件读,并保存到缓存中
				if not hmap then
					local cont = fs.readFileSync(filepath);
					hmap = json.decode(cont or '') or {};
					openfds[filepath] = hmap;
				end

				-- heatmap.js需要的数据要有 max字段和data字段
				-- max为点击数最大值
				-- data为点击坐标及点击数
				hmap.max = hmap.max or 1;
				hmap.data = hmap.data or {};

				local old;

				for ii,vv in ipairs(hmap.data) do
					-- 碰撞检测,查找point有落入hmap中的任意一个点的范围,就返回这个点
					old = checkImpact(vv, point, hmap);
					if old then break; end
				end

				if old then
					-- 将point合并到old中,old.value + 1
					merge_points(old, point, hmap);
					-- 判断最大值,进行对比,hmap.max保持最大值
					if hmap.max < old.value then hmap.max = old.value; end
				else
					-- 如果是新的点,计数一次
					point.value = 1;
					table.insert(hmap.data, point);
				end
            end
        end
    end
	-- 保存数据
	for filepath,hmap in pairs(openfds) do
		fs.writeFileSync(filepath, json.encode(hmap));
	end
	return {ret = 0};
end

前端数据展示


<!DOCTYPE html>
<!--
 *  test_heatmap.html  2018-07-18
 *  Copyright (C) 2018  Chuanpao Su
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *
 ************************************************************************
 *      FileName: test_heatmap.html
 *
 *        Author: Chuanpao Su
 *       Version: 1.0
 *   Description: ----
 *          Mail: suchuanpao@outlook.com
 *        Create: 2018-07-18 16:30:18
 * Last Modified: 2018-07-18 16:49:38
 *  
 ***********************************************************************-->
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
    <style>
        div {
            width:1080;
			height:1080px;
			border: 1px solid;
			border-color: grey;
			background-image:url("static/img/page_game_ddz.png");
        }
    </style>
</head>
<body>
    <div id="heatmap"></div>
</body>
<script src="static/js/heatmap.js"></script>
<script type="application/javascript" src="static/js/ai_platform.js"></script>
<script type="text/javascript">
// 创建一个heatmap实例对象
// “h337” 是heatmap.js全局对象的名称.可以使用它来创建热点图实例
// 这里直接指定热点图渲染的div了.heatmap支持自定义的样式方案,网页外包接活具体可看官网api
var heatmapInstance = h337.create({
    container: document.querySelector('#heatmap'),
});
requestServer("GET", "/bdata/query_heatmap_data?layer=game_ddz&gameid=3&source=ppb2whmj_oppo&date=20180726", function (res) {
    //因为data是一组数据,web切图报价所以直接setData
    //console.log(res)
    for (var i = 0; i < res.record.data.length; i++) {
        res.record.data[i].y = 1080-res.record.data[i].y;
    }
    heatmapInstance.setData(res.record); //数据绑定还可以使用
})

</script>
</html>
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity力图生成算法是一种通过收集和分析大量数据生成可视化力图的算法。力图用不同颜色的点表示特定区域的数据密集程度,由此可以有效地展示数据的分布情况和点区域。 在Unity中,力图生成算法通常包括以下步骤: 1. 数据收集:首先需要收集与力图相关的数据。这些数据可以来自用户行为、传感器数据或其他来源。数据可以是离散的,如坐标点或事件发生次数,也可以是连续的,如数值或颜色。 2. 数据归一化:归一化是将原始数据转化为统一的数值范围,以便数据能够在力图中呈现。这样可以确保每个数据点的权重相对均衡。 3. 力图网格划分:将数据点分布的区域划分为网格,每个网格表示一个区域。网格的大小可以根据需求进行调整,较小的网格可以提供更精确的力图细节,而较大的网格可以加快计算速度。 4. 力值计算:对于每个网格,根据其包含的数据点进行力值的计算。常见的计算方法是根据数据点的距离、权重或频率来决定力值。 5. 力图渲染:将计算得到的力图数据转化为可视化的图像。通常使用渐变色来表示力值的不同程度,如使用红色表示高力值,蓝色表示低力值。 6. 显示与交互:最后,将生成力图与Unity中的场景进行融合,使用户可以通过交互方式与力图进行互动。这可以包括添加标签、放大、缩小或导航等功能,以使力图更加易于理解和使用。 通过以上步骤,Unity力图生成算法可以将大量数据转化为直观的力图,帮助用户更好地理解数据分布和趋势,从而做出有效的决策或优化操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值