利用echarts的关系图编写html,在用安卓的webview加载这个html实现最终的效果。
一、demo展示
二、html编写
自行参考echarts官网配置项,更改图表样式,由于图片跨域问题,单独用浏览器打开会报错,可自已更换symbol属性中的图片地址。
relationNet.html
<!DOCTYPE html>
<html style="height: 100%">
<head>
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport"/>
<meta http-equiv="Access-Control-Allow-Origin" content="*"/>
<meta charset="utf-8">
</head>
<body style="height: 100%; margin: 0 0 0 0">
<div id="container" style="width:100%; height:100%; overflow:visible;"></div>
<script src="http://cdn.bootcss.com/echarts/3.7.1/echarts.min.js"></script>
<script type="text/javascript">
var dom = document.getElementById("container");
var myChart = echarts.init(dom);
var app = {};
var echartJson = {
"series": [{
"edgeLabel": {"normal": {"formatter": "{c}", "show": true}},
"edgeSymbol": "circle",
"force": {"repulsion": 2000},
"layout": "force",
"links": [{"value": "同学", "source": "650103198702015111", "target": "350555099779584311"}, {
"value": "同事",
"source": "650103198702015111",
"target": "342870099576708940"
}, {"value": "亲戚", "source": "650103198702015111", "target": "827850577979002868"}],
"roam": false,
"itemStyle": {"normal": {"color": "#6495ED"}},
"label": {
"normal": {
"show": true,
"position": "bottom",
"color": "#fff",
"backgroundColor": "#808080",
"padding": [1, 4],
"borderRadius": 5
}
},
"symbol": "circle",
"symbolSize": 50,
"type": "graph"
}], "tooltip": {"show": false}
};
loadEcharts(echartJson);
function loadEcharts(echartJson) {
if (echartJson && typeof echartJson === "object") {
myChart.setOption(echartJson, true);
}
}
// echarts图表点击跳转
myChart.on('click', function (params) {
if (params.data.id) {
var idCard = params.data.id; // 获取被点击节点的身份证号
alert(idCard);
} else {
alert('您点击节点信息!');
}
});
var map = [{
"name": "张1",
"symbolSize": 80,
"symbol": "http://tupian.qqw21.com/article/UploadPic/2020-1/202011921482931830.jpg",
"id": "650103198702015111",
"itemStyle": {"normal": {"color": "red"}}
}, {
"name": "张3",
"symbol": "http://image.biaobaiju.com/uploads/20180803/23/1533308847-sJINRfclxg.jpeg",
"symbolSize": 60,
"id": "350555099779584311"
}, {
"name": "张4",
"symbol": "http://image.biaobaiju.com/uploads/20180803/23/1533308847-sJINRfclxg.jpeg",
"symbolSize": 60,
"id": "342870099576708940"
}, {
"name": "张6",
"symbol": "http://image.biaobaiju.com/uploads/20180803/23/1533308847-sJINRfclxg.jpeg",
"symbolSize": 60,
"id": "827850577979002868"
}];
pubdata(map);
function getImgData(imgSrc, object, callback) {
const canvas = document.createElement('canvas');
const contex = canvas.getContext('2d');
const img = new Image();
img.setAttribute('crossOrigin', 'anonymous');
img.crossOrigin = '';
img.src = imgSrc;
img.onload = function () {
center = {
x: img.width / 2,
y: img.height / 2.5
};
var newImgWidth = img.width;
var newImgHeight = img.height;
var minLine = 0;
var maxLine = 0;
if (newImgWidth >= newImgHeight) {
maxLine = newImgWidth;
minLine = newImgHeight;
} else {
maxLine = newImgHeight;
minLine = newImgWidth;
}
canvas.width = maxLine;
canvas.height = maxLine;
contex.beginPath();
contex.arc(maxLine / 2, maxLine / 2, maxLine / 2, 0, 2 * Math.PI); //画出圆
contex.lineWidth = 2;
contex.strokeStyle = 'orange';
contex.stroke();
contex.clip(); //裁剪上面的圆形
if (newImgWidth >= newImgHeight) {
contex.drawImage(img, (newImgWidth / 2) - (newImgHeight / 2), 0, minLine, minLine, 0, 0, maxLine, maxLine);
} else {
contex.drawImage(img, 0, (newImgHeight / 2) - (newImgWidth / 2), minLine, minLine, 0, 0, maxLine, maxLine);
}
contex.restore(); // 还原状态
callback(canvas.toDataURL('image/png', 1), object);
}
}
var androidMap;
function pubdata(json) {
androidMap = json;
var len = androidMap.length;
for (var i = 0; i < len; i++) {
var object = androidMap[i];
if (androidMap[i].symbol != null && androidMap[i].symbol != "") {
var http = androidMap[i].symbol;
getImgData(http, androidMap[i], function (data0, object) {
http = data0;
var img = "image://" + http;
object.symbol = img;
myChart.setOption({
series: [{
data: androidMap
}]
})
});
}
}
}
</script>
</body>
</html>
三、安卓编写
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<WebView
android:id="@+id/relation_net_webView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
MainActivity.java
package cn.xkw.myapplication;
import android.net.http.SslError;
import android.os.Build;
import android.os.Bundle;
import android.webkit.SslErrorHandler;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import androidx.appcompat.app.AppCompatActivity;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class MainActivity extends AppCompatActivity {
WebView webView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initWebView();
}
public void initWebView(){
webView = (WebView) findViewById(R.id.relation_net_webView);
try {
if (Build.VERSION.SDK_INT >= 16) {
Class<?> clazz = webView.getSettings().getClass();
Method method = clazz.getMethod(
"setAllowUniversalAccessFromFileURLs", boolean.class);//利用反射机制去修改设置对象
if (method != null) {
method.invoke(webView.getSettings(), true);//修改设置
}
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
webView.setWebChromeClient(new WebChromeClient());
// 覆盖WebView默认使用第三方或系统默认浏览器打开网页的行为,使网页用WebView打开
webView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
handler.proceed(); //表示等待证书响应
}
@Override
public void onPageFinished(final WebView view, String url) {
super.onPageFinished(view, url);
}
});
WebSettings webSettings = webView.getSettings();
// 设置http与https共存
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
}
webSettings.setAllowFileAccessFromFileURLs(true); // 设置跨域
webSettings.setJavaScriptCanOpenWindowsAutomatically(true); // js可以直接打开窗口
webSettings.setJavaScriptEnabled(true); // 是否允许执行js
webSettings.setAllowFileAccessFromFileURLs(true); // 设置跨域
webSettings.setBlockNetworkImage(false); // 图片显示
webSettings.setDomStorageEnabled(true); // DOM Storage
webSettings.setAllowFileAccess(true); // 设置可以访问文件
webSettings.setLoadsImagesAutomatically(true); // 支持自动加载图片
webSettings.setDefaultTextEncodingName("utf-8"); // 设置编码格式
webView.loadUrl("file:///android_asset/relationNet.html");
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cn.xkw.myapplication">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <!-- 允许程序访问网络 -->
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:usesCleartextTraffic="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
目录结构
四、参考文章
echarts关系图,节点以圆形图片显示:
https://blog.csdn.net/qq_36072384/article/details/85319126
webView显示h5的坑:
https://www.jianshu.com/p/1c2b02b14432
canvas裁剪图片: