数据源采集手机的mach
接口获取的CPU和内存数据,每秒调用取一次,收集起来转成echarts的数据格式即可
采用的是echarts的line-gradient
图表样式
https://echarts.apache.org/examples/zh/editor.html?c=line-gradient
OC代码
获取CPU和内存
// 需要 #include <mach/mach.h> 头文件
//获取CPU用量
+ (float)getCpuUsage
{
kern_return_t kr;
thread_array_t thread_list;
mach_msg_type_number_t thread_count;
thread_info_data_t thinfo;
mach_msg_type_number_t thread_info_count;
thread_basic_info_t basic_info_th;
kr = task_threads(mach_task_self(), &thread_list, &thread_count);
if (kr != KERN_SUCCESS) {
return -1;
}
float cpu_usage = 0;
for (int i = 0; i < thread_count; i++)
{
thread_info_count = THREAD_INFO_MAX;
kr = thread_info(thread_list[i], THREAD_BASIC_INFO,(thread_info_t)thinfo, &thread_info_count);
if (kr != KERN_SUCCESS) {
return -1;
}
basic_info_th = (thread_basic_info_t)thinfo;
if (!(basic_info_th->flags & TH_FLAGS_IDLE))
{
cpu_usage += basic_info_th->cpu_usage;
}
}
NSUInteger CPUNum = [NSProcessInfo processInfo].activeProcessorCount;
cpu_usage = cpu_usage / (float)TH_USAGE_SCALE * 100.0 / CPUNum;
vm_deallocate(mach_task_self(), (vm_offset_t)thread_list, thread_count * sizeof(thread_t));
return cpu_usage;
}
//获取内存
+ (float)getAppMemory{
NSUInteger memoryUsageInByte = 0;
task_vm_info_data_t vmInfo;
mach_msg_type_number_t count = TASK_VM_INFO_COUNT;
kern_return_t kernelReturn = task_info(mach_task_self(), TASK_VM_INFO, (task_info_t) &vmInfo, &count);
if(kernelReturn == KERN_SUCCESS) {
memoryUsageInByte = (NSUInteger) vmInfo.phys_footprint;
} else {
return -1;
}
return memoryUsageInByte/1024.0/1024.0;
}
Vue代码
package.json
{
"name": "show_data_echarts",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve --open",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"core-js": "^3.6.5",
"echarts": "^5.2.1",
"vue": "^2.6.11"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^4.5.0",
"@vue/cli-plugin-eslint": "^4.5.0",
"@vue/cli-service": "^4.5.0",
"babel-eslint": "^10.1.0",
"eslint": "^6.7.2",
"eslint-plugin-vue": "^6.2.2",
"less": "^3.0.4",
"less-loader": "^5.0.0",
"vue-template-compiler": "^2.6.11"
}
}
main.js
import Vue from 'vue'
import App from './App.vue'
import * as echarts from 'echarts';
Vue.prototype.$echarts = echarts
Vue.config.productionTip = false
new Vue({
echarts,
render: h => h(App)
}).$mount('#app')
App.vue
<template>
<div class="container">
<div id="input">
<textarea
v-model="cpu"
name="cpu"
id="cpu-input"
cols="30"
rows="30"
placeholder="请在这里填写CPU数据"
></textarea>
<span style="margin-left: 15px"> </span>
<textarea
v-model="memery"
name="memery"
id="memery-input"
cols="30"
rows="30"
placeholder="请在这里填写内存数据"
></textarea>
</div>
<div class="file-select-bg">
<div>
<label for="file">选择CPU数据: </label>
<input type="file" accept=".txt" name="选择CPU数据" id="selectCPU" @change="selectCpuData">
</div>
<div>
<label for="file">选择内存数据: </label>
<input type="file" accept=".txt" name="选择内存数据" id="selectMem" @change="selectMemData">
</div>
</div>
<div class="button" @click="clickAction">生成图表</div>
<div id="cpu"></div>
<div class="tips" v-show="showCpuTips">最大值: <strong>{{cpuDict.max}}</strong>% 最小值: <strong>{{cpuDict.min}}</strong>% 平均值: <strong>{{cpuDict.avg.toFixed(2)}}</strong>%</div>
<div id="memery"></div>
<div class="tips" v-show="showMemeryTips">最大值: <strong>{{memeryDict.max}}</strong>MB 最小值: <strong>{{memeryDict.min}}</strong>MB 平均值: <strong>{{memeryDict.avg.toFixed(2)}}</strong>MB</div>
</div>
</template>
<script>
export default {
data() {
return {
showCpuTips:false,
showMemeryTips:false,
cpu: "",
memery: "",
cpuData: [],
memeryData: [],
cpuDict:{
min:0.0,
max:1.0,
avg:0.0
},
memeryDict:{
min:0.0,
max:0.0,
avg:0.0
}
};
},
mounted() {},
methods: {
selectCpuData(){
var self = this;
var file = document.getElementById("selectCPU").files[0];
var reader = new FileReader();
reader.readAsText(file,'utf-8');
reader.onload = function () {
self.cpu = this.result
this.cpuData = JSON.parse(this.cpu);
this.drawTab(true);
}
},
selectMemData(){
var self = this;
var file = document.getElementById("selectMem").files[0];
var reader = new FileReader();
reader.readAsText(file,'utf-8');
reader.onload = function () {
self.memery = this.result
this.memeryData = JSON.parse(this.memery);
this.drawTab(false);
}
},
clickAction() {
if (this.cpu.length) {
this.cpuData = JSON.parse(this.cpu);
this.drawTab(true);
}
if (this.memery.length) {
this.memeryData = JSON.parse(this.memery);
this.drawTab(false);
}
},
getMaxValue(arr){
var max = arr[0];
for(var i=1;i<arr.length;i++){
if(max<arr[i]) max=arr[i];
}
return max;
},
getMinValue(arr){
var min = arr[0];
for(var i=1;i<arr.length;i++){
if(min>arr[i]) min=arr[i];
}
return min;
},
getAvgValue(arr){
var sum = 0;
for(var i=1;i<arr.length;i++){
sum+=arr[i];
}
return sum/arr.length;
},
parserCpuData(){
if(!this.cpuData.length){
return
}
var cpuArr = []
const localData = this.cpuData;
for (let index = 0; index < localData.length; index++) {
const element = localData[index];
const cpu = element[1];
cpuArr.push(cpu);
}
const max = this.getMaxValue(cpuArr);
const min = this.getMinValue(cpuArr);
const avg = this.getAvgValue(cpuArr);
this.cpuDict = {
max,
min,
avg
};
this.showCpuTips = true;
},
parserMemeryData(){
if(!this.memeryData.length){
return
}
var memArr = []
const localData = this.memeryData;
for (let index = 0; index < localData.length; index++) {
const element = localData[index];
const mem = element[1];
memArr.push(mem);
}
const max = this.getMaxValue(memArr);
const min = this.getMinValue(memArr);
const avg = this.getAvgValue(memArr);
this.memeryDict = {
max,
min,
avg
};
this.showMemeryTips = true;
},
//https://echarts.apache.org/examples/zh/editor.html?c=line-gradient
drawTab(isDrawCPU) {
let title = isDrawCPU ? "CPU性能变化趋势图" : "内存性能变化趋势图";
this.$echarts.init(document.getElementById(isDrawCPU
? 'cpu':'memery')).dispose();
let myChart = isDrawCPU
? this.$echarts.init(document.getElementById("cpu"))
: this.$echarts.init(document.getElementById("memery"));
let tabData = isDrawCPU ? this.cpuData : this.memeryData;
const dateList = tabData.map(function (item) {
return item[0];
});
const valueList = tabData.map(function (item) {
return item[1];
});
this.parserCpuData();
this.parserMemeryData();
const formatter = isDrawCPU? "CPU占用 <span style='color:red'> {c}% </span> " : "内存占用 <span style='color:red'> {c}MB </span> "
let option = {
visualMap: [
{
show: false,
type: "continuous",
seriesIndex: 0,
dimension: 0,
min: 0,
max: dateList.length - 1,
},
],
title: [
{
top: "5%",
left: "center",
text: title,
},
],
tooltip: {
trigger: "axis",
formatter: formatter,
axisPointer: {
type: "cross",
crossStyle: {
color: "#0cf",
type: "solid"
},
},
show:true
},
xAxis: [
{
data: dateList,
name:"时间"
},
],
yAxis: [
{
gridIndex: 0,
name:isDrawCPU? "CPU(%)":"内存(MB)"
},
],
grid: [
{
top: "20%",
},
],
series: [
{
type: "line",
showSymbol: true,
data: valueList,
xAxisIndex: 0,
yAxisIndex: 0,
},
],
};
myChart.setOption(option,true);
},
},
};
</script>
<style lang="less">
.button {
margin: 30px;
margin-left: 150px;
font-size: 25px;
color: white;
text-align: center;
180px;
height: 50px;
line-height: 50px;
cursor: pointer;
border-radius: 5px;
background-color: #7799ff;
}
.container {
100%;
height: 100%;
}
#cpu {
400px;
height: 400px;
}
#memery {
margin-top: 50px;
400px;
height: 400px;
}
.tips{
margin-top: -10px;
margin-bottom: 100px;
margin-left: 10px;
font-size: 20px;
color: orangered;
}
.file-select-bg{
500px;
height: 60px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-around;
flex: 1;
}
</style>
原生代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>性能图表展示</title>
<script src="https://cdn.bootcss.com/echarts/5.2.1/echarts.min.js"></script>
<style>
.button {
margin: 30px;
margin-left: 150px;
font-size: 25px;
color: white;
text-align: center;
180px;
height: 50px;
line-height: 50px;
cursor: pointer;
border-radius: 5px;
background-color: #7799ff;
}
.container {
100%;
height: 100%;
}
#cpu {
400px;
height: 400px;
}
#memery {
margin-top: 50px;
400px;
height: 400px;
}
.tips {
margin-top: -10px;
margin-left: 10px;
font-size: 20px;
color: orangered;
}
.file-select-bg {
600px;
height: 60px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-around;
flex: 1;
}
</style>
</head>
<body>
<div class="container">
<div id="input">
<textarea
name="cpu"
id="cpu-input"
cols="30"
rows="30"
placeholder="请在这里填写CPU数据"
></textarea>
<span style="margin-left: 15px"> </span>
<textarea
name="memery"
id="memery-input"
cols="30"
rows="30"
placeholder="请在这里填写内存数据"
></textarea>
</div>
<div class="file-select-bg">
<div>
<label for="file">选择CPU数据: </label>
<input
type="file"
accept=".txt"
name="选择CPU数据"
id="selectCPU"
onchange="selectCpuData()"
/>
</div>
<div>
<label for="file">选择内存数据: </label>
<input
type="file"
accept=".txt"
name="选择内存数据"
id="selectMem"
onchange="selectMemData()"
/>
</div>
</div>
<div class="button" onclick="clickAction()">生成图表</div>
<div id="cpu"></div>
<div class="tips" id="cpu-tips"></div>
<div id="memery"></div>
<div class="tips" id="memery-tips"></div>
</div>
<script type="text/javascript">
var cpuData = [];
var memeryData = [];
function selectCpuData() {
var file = document.getElementById("selectCPU").files[0];
var reader = new FileReader();
reader.readAsText(file, "utf-8");
reader.onload = function () {
document.getElementById("cpu-input").innerText = this.result;
};
}
function selectMemData() {
var file = document.getElementById("selectMem").files[0];
var reader = new FileReader();
reader.readAsText(file, "utf-8");
reader.onload = function () {
document.getElementById("memery-input").innerText = this.result;
};
}
function clickAction() {
const cpuText = document.getElementById("cpu-input").value;
if (cpuText.length) {
cpuData = JSON.parse(cpuText);
}
if (cpuData.length) {
parserCpuData();
drawTab(true);
}
const memText = document.getElementById("memery-input").value;
if (memText.length) {
memeryData = JSON.parse(memText);
}
if (memeryData.length) {
parserMemeryData();
drawTab(false);
}
}
function drawTab(isDrawCPU) {
let title = isDrawCPU ? "CPU性能变化趋势图" : "内存性能变化趋势图";
echarts
.init(document.getElementById(isDrawCPU ? "cpu" : "memery"))
.dispose();
var myChart = isDrawCPU
? echarts.init(document.getElementById("cpu"))
: echarts.init(document.getElementById("memery"));
let tabData = isDrawCPU ? cpuData : memeryData;
const dateList = tabData.map(function (item) {
return item[0];
});
const valueList = tabData.map(function (item) {
return item[1];
});
const formatter = isDrawCPU
? "CPU占用 <span style='color:red'> {c}% </span> "
: "内存占用 <span style='color:red'> {c}MB </span> ";
let option = {
visualMap: [
{
show: false,
type: "continuous",
seriesIndex: 0,
dimension: 0,
min: 0,
max: dateList.length - 1,
},
],
title: [
{
top: "5%",
left: "center",
text: title,
},
],
tooltip: {
trigger: "axis",
formatter: formatter,
axisPointer: {
type: "cross",
crossStyle: {
color: "#0cf",
type: "solid",
},
},
show: true,
},
xAxis: [
{
data: dateList,
name: "时间",
},
],
yAxis: [
{
gridIndex: 0,
name: "CPU(%)",
},
],
grid: [
{
top: "20%",
},
],
series: [
{
type: "line",
showSymbol: true,
data: valueList,
xAxisIndex: 0,
yAxisIndex: 0,
},
],
};
myChart.setOption(option, true);
}
function parserCpuData() {
if (!cpuData.length) {
return;
}
var cpuArr = [];
for (let index = 0; index < cpuData.length; index++) {
const element = cpuData[index];
const cpu = element[1];
cpuArr.push(cpu);
}
const max = this.getMaxValue(cpuArr);
const min = this.getMinValue(cpuArr);
const avg = this.getAvgValue(cpuArr);
document.getElementById(
"cpu-tips"
).innerHTML = `最大值: <strong>${max}</strong>% 最小值: <strong>${min}</strong>% 平均值: <strong>${avg.toFixed(
2
)}</strong>% `;
}
function parserMemeryData() {
if (!memeryData.length) {
return;
}
var memArr = [];
for (let index = 0; index < memeryData.length; index++) {
const element = memeryData[index];
const mem = element[1];
memArr.push(mem);
}
const max = this.getMaxValue(memArr);
const min = this.getMinValue(memArr);
const avg = this.getAvgValue(memArr);
document.getElementById(
"memery-tips"
).innerHTML = `最大值: <strong>${max}</strong>MB 最小值: <strong>${min}</strong>MB 平均值: <strong>${avg.toFixed(
2
)}</strong>MB `;
}
function getMaxValue(arr) {
var max = arr[0];
for (var i = 1; i < arr.length; i++) {
if (max < arr[i]) max = arr[i];
}
return max;
}
function getMinValue(arr) {
var min = arr[0];
for (var i = 1; i < arr.length; i++) {
if (min > arr[i]) min = arr[i];
}
return min;
}
function getAvgValue(arr) {
var sum = 0;
for (var i = 1; i < arr.length; i++) {
sum += arr[i];
}
return sum / arr.length;
}
</script>
</body>
</html>
样例数据源
CPU数据
[["19:28:11", 0.30],["19:28:12", 6.35],["19:28:13", 7.35],["19:28:14", 7.22],["19:28:15", 7.42],["19:28:16", 6.57],["19:28:17", 5.75],["19:28:18", 6.47],["19:28:19", 6.22],["19:28:20", 6.10],["19:28:21", 6.07],["19:28:22", 5.90],["19:28:23", 5.68],["19:28:24", 5.77],["19:28:25", 6.38],["19:28:26", 5.28],["19:28:27", 6.67],["19:28:28", 5.90],["19:28:29", 6.17],["19:28:30", 5.20],["19:28:31", 5.90],["19:28:32", 7.47],["19:28:33", 6.93],["19:28:34", 6.88],["19:28:35", 8.10],["19:28:36", 7.48],["19:28:37", 7.27],["19:28:38", 5.60],["19:28:39", 5.70],["19:28:40", 5.57],["19:28:41", 5.60],["19:28:42", 5.83],["19:28:43", 5.93],["19:28:44", 6.53],["19:28:45", 6.45],["19:28:46", 6.67],["19:28:47", 6.02],["19:28:48", 6.73],["19:28:49", 6.47],["19:28:50", 6.03],["19:28:51", 5.35],["19:28:52", 5.58],["19:28:53", 5.45],["19:28:54", 5.70],["19:28:55", 6.42],["19:28:56", 7.45],["19:28:57", 8.12],["19:28:58", 8.03],["19:28:59", 6.25],["19:29:00", 6.47],["19:29:01", 6.38],["19:29:02", 7.08],["19:29:03", 6.78],["19:29:04", 6.25],["19:29:05", 5.88],["19:29:06", 6.33],["19:29:07", 6.75]]
内存数据
[["19:28:11", 13.17],["19:28:12", 15.61],["19:28:13", 18.72],["19:28:14", 18.94],["19:28:15", 19.17],["19:28:16", 19.42],["19:28:17", 19.94],["19:28:18", 16.69],["19:28:19", 16.11],["19:28:20", 16.05],["19:28:21", 16.05],["19:28:22", 15.84],["19:28:23", 17.16],["19:28:24", 16.94],["19:28:25", 17.38],["19:28:26", 16.92],["19:28:27", 17.97],["19:28:28", 18.02],["19:28:29", 27.70],["19:28:30", 18.80],["19:28:31", 18.61],["19:28:32", 17.77],["19:28:33", 16.58],["19:28:34", 16.56],["19:28:35", 15.97],["19:28:36", 16.24],["19:28:37", 16.03],["19:28:38", 14.88],["19:28:39", 14.83],["19:28:40", 14.83],["19:28:41", 14.86],["19:28:42", 16.00],["19:28:43", 14.84],["19:28:44", 16.03],["19:28:45", 14.89],["19:28:46", 16.05],["19:28:47", 16.27],["19:28:48", 16.03],["19:28:49", 16.03],["19:28:50", 16.03],["19:28:51", 16.03],["19:28:52", 16.03],["19:28:53", 16.06],["19:28:54", 16.05],["19:28:55", 16.25],["19:28:56", 16.03],["19:28:57", 16.03],["19:28:58", 16.30],["19:28:59", 14.94],["19:29:00", 14.91],["19:29:01", 14.88],["19:29:02", 16.56],["19:29:03", 15.49],["19:29:04", 16.61],["19:29:05", 16.61],["19:29:06", 16.61],["19:29:07", 16.42]]