android Echart力圖webview,包含雙向交互內容
H5界面代碼
<!DOCTYPE html>
<html>
<head>
<title>關係圖</title>
<script src="./jquery-3.4.1.min.js"></script>
<script src="./echarts.min.js"></script>
</head>
<body>
<div id="main" style="width:1000px;height:800px"></div>
<script type="text/javascript" charset="UTF-8">
var myChart = echarts.init(document.getElementById('main'));
var categories = [];
categories[0] = {
name: '中心節點'
};
categories[1] = {
name: '上游節點'
};
categories[2] = {
name: '下游節點'
};
var items = [];
option = {
// 圖的標題
title: {
text: '關係圖'
},
// 提示框的配置
tooltip: {
formatter: function(x) {
return x.data.name;
}
},
// 工具箱
toolbox: {
// 顯示工具箱
show: true,
feature: {
mark: {
show: true
},
// 還原
restore: {
show: true
},
// 保存爲圖片
saveAsImage: {
show: true
}
}
},
legend: [{
// selectedMode: 'single',
data: categories.map(function(a) {
return a.name;
})
}],
animation: true,
animationDurationUpdate: 1500,
animationEasingUpdate: 'quinticInOut',
series: [{
type: 'graph',
<!-- type:"effectScatter", -->
// 類型:關係圖
layout: 'force',
//圖的佈局,類型爲力導圖
symbolSize: 80,
// 調整節點的大小
roam: true,
legendHoverLink : true,
focusNodeAdjacency:true,
nodeScaleRatio : 0,
edgeSymbol: ['circle', 'arrow'],
edgeLabel: {
normal: {
textStyle: {
fontSize: 20
}
}
},
force: {
repulsion: 3500,
edgeLength :80,
layoutAnimation : false
},
draggable: false,
lineStyle : {
normal : {
color : 'rgba(205,51,51,0.4)',
width : '3',
type : 'dotted', //線的類型 'solid'(實線)'dashed'(虛線)'dotted'(點線)
curveness : 0.2, //線條的曲線程度,從0到1
opacity : 1 // 圖形透明度。支持從 0 到 1 的數字,爲 0 時不繪製該圖形。默認0.5
},
emphasis : {//高亮狀態
}
},
edgeLabel: {
normal: {
show: true,
formatter: function(x) {
var reg = /[,,]/g;
return x.data.name.replace(reg,"$&\n");
}
}
},
label: {
normal: {
show: true,
textStyle: {},
formatter: function(x) {
return x.data.name.replace(/[^\x00-\xff]/g, "$&\x01").replace(/.{16}\x01?/g, "$&\n").replace(/\x01/g, "");
}
}
},
// 假數據,用不到,對比看得
data: [{
name: 'node01',
des: 'nodedes01',
symbolSize: 70,
symbol:"roundRect",
category: 0,
},
{
name: 'node02',
des: 'nodedes02',
symbolSize: 50,
category: 1,
},
{
name: 'node03',
des: 'nodedes3',
symbolSize: 50,
category: 1,
},
{
name: 'node04',
des: 'nodedes04',
symbolSize: 50,
category: 1,
},
{
name: 'node05',
des: 'nodedes05',
symbolSize: 50,
category: 1,
}],
links: [{
source: 'node01',
target: 'node02',
name: 'link01',
des: 'link01des'
},
{
source: 'node01',
target: 'node03',
name: 'link02',
des: 'link02des'
},
{
source: 'node01',
target: 'node04',
name: 'link03',
des: 'link03des'
},
{
source: 'node01',
target: 'node05',
name: 'link04',
des: 'link05des'
}],
categories: categories,
}]
};
myChart.on('click',function(params)
{
if (params.data.source != null)
{
callback.jumpTopicEcho(params.data.name);
}
});
function javaCallJs(event)
{
}
/**加載node節點**/
function loadEcharts(nodeJson)
{
option["series"][0]["data"] = nodeJson;
}
/**加載link數據**/
function loadLinkEcharts(linkJson)
{
option["series"][0]["links"] = linkJson;
myChart.setOption(option);
}
</script>
</body>
</html>
承載的自定義webview
public class EchartView extends WebView {
private static final String TAG = "EchartView";
public EchartView(Context context) {
this(context, null);
}
public EchartView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public EchartView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@SuppressLint("JavascriptInterface")
private void init() {
WebSettings webSettings = getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
webSettings.setSupportZoom(false);
webSettings.setDisplayZoomControls(false);
addJavascriptInterface(new JSCallback(), "callback");
//直接放在android工程的assest目錄下
loadUrl("file:///android_asset/echarts/force.html");
}
/**
* 刷新echart數據
* @param node 節點json
* @param link link的json
*/
public void refreshEchartsWithOption(String node, String link) {
if (node == null || link == null) {
return;
}
String call = "javascript:loadEcharts(" + node + ")";
loadUrl(call);
String linkCall = "javascript:loadLinkEcharts(" + link + ")";
loadUrl(linkCall);
}
}
H5調用android的方法類
/**
* H5調用方法類
*/
public class JSCallback extends Object
{
@JavascriptInterface
public void jumpTopicEcho(String topic)
{
//獲取當前所在的activity
final Activity activity = MyActivityManager.getInstance().getCurrentActivity();
if (activity != null)
{
final String[] split = topic.split(",");//以逗號分割
AlertDialog alertDialog = new AlertDialog
.Builder(activity)
.setItems(split, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//根據選擇跳轉其他activity
Intent intent = new Intent(activity,TopicMsgActivity.class);
intent.putExtra("topic",split[which]);
activity.startActivity(intent);
}
}).create();
alertDialog.show();
}
}
}
具體使用方法實例
/**
* 力圖的activity
*/
public class EChartsActivity extends AppCompatActivity
{
private EchartView webView;
private List<NodeInfo> nodeInfos = new ArrayList<>();
private List<LinkInfo> linkInfos = new ArrayList<>();
//上游節點
private List<String> upStreamNodes = new ArrayList<>();
//根節點
private NodeInfo rootNode;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.echarts_activity);
getData();
webView = findViewById(R.id.chart_view);
webView.setWebViewClient(new WebViewClient()
{
@Override
public void onPageFinished(WebView view, String url)
{
super.onPageFinished(view, url);
//最好在h5頁面加載完畢後再加載數據,防止html的標籤還未加載完成,不能正常顯示
EChartsDataTask task = new EChartsDataTask("zzkk");
task.execute();
}
});
}
private void getData()
{
//todo 獲取數據
}
private class EChartsDataTask extends AsyncTask<Object, Integer, Object>
{
private String params;
public EChartsDataTask(String params)
{
this.params = params;
}
@Override
protected Object doInBackground(Object... objects)
{
//添加返回數據
nodeInfos.clear();
nodeInfos.addAll(JNIUtils.getNodesFromJNI(params));
linkInfos.clear();
linkInfos.addAll(JNIUtils.getLinkFromJNI(params));
return null;
}
@Override
protected void onPostExecute(Object o)
{
super.onPostExecute(o);
if (!nodeInfos.isEmpty() && !linkInfos.isEmpty())
{
rootNode = nodeInfos.get(0);
// 需要拼接成json數據
String link = getLinkBuffer().toString();
String node = getNodeBuffer().toString();
Log.d("zzkk", "node = " + node);
Log.d("zzkk", "link = " + link);
//h5界面刷新數據
webView.refreshEchartsWithOption(node, link);
}
}
}
private StringBuffer getLinkBuffer()
{
StringBuffer linkBuffer = new StringBuffer();
linkBuffer.append("[" + "\n");
upStreamNodes.clear();
for (int i = 0; i < linkInfos.size(); i++)
{
LinkInfo info = linkInfos.get(i);
// 如果目標節點是根節點,添加至上游列表中
if (rootNode.name.equals(info.target))
{
upStreamNodes.add(info.source);
}
if (i == linkInfos.size() - 1)
{
linkBuffer.append("{" + "\n");
linkBuffer.append("source : " + "'" + info.source + "'," + "\n");
linkBuffer.append("target : " + "'" + info.target + "'," + "\n");
linkBuffer.append("name : " + "'" + "topic1, topic2, " +
"topic3" + "'," +
"\n");
linkBuffer.append("des : " + "'" + info.desc + "'" + "\n");
linkBuffer.append("}" + "\n");
}
else
{
linkBuffer.append("{" + "\n");
linkBuffer.append("source : " + "'" + info.source + "'," + "\n");
linkBuffer.append("target : " + "'" + info.target + "'," + "\n");
linkBuffer.append("name : " + "'" + info.name + "'," + "\n");
linkBuffer.append("des : " + "'" + info.desc + "'" + "\n");
linkBuffer.append("}," + "\n");
}
}
linkBuffer.append("]" + "\n");
return linkBuffer;
}
private int isUpStreamNode(String nodeName)
{
return upStreamNodes.contains(nodeName) ? 1 : 2;
}
private String getSize(String name)
{
if (name == null)
{
return "[110, 60]";
}
else
{
String dealName = name.replaceAll("\\s+", " ");
int height = ((dealName.length() / 16) + 1) * 23;
return "[110, "+ height + "]";
}
}
private StringBuffer getNodeBuffer()
{
StringBuffer nodeBuffer = new StringBuffer();
nodeBuffer.append("[" + "\n");
for (int i = 0; i < nodeInfos.size(); i++)
{
if (i == 0)
{
nodeBuffer.append("{" + "\n");
NodeInfo info = nodeInfos.get(i);
nodeBuffer.append("name : " + "'" + info.name + "'," + "\n");
nodeBuffer.append("des : " + "'" + info.topic + "'," + "\n");
nodeBuffer.append("symbolSize : " + "[100, 60]" + ",\n");
nodeBuffer.append("symbol :\"circle\""+ ",\n");
nodeBuffer.append("category : " + 0 + "\n");
nodeBuffer.append("}," + "\n");
}
else if (i == nodeInfos.size() - 1)
{
nodeBuffer.append("{" + "\n");
NodeInfo info = nodeInfos.get(i);
nodeBuffer.append("name : " + "'" + info.name + "'," + "\n");
nodeBuffer.append("des : " + "'" + info.topic + "'," + "\n");
nodeBuffer.append("symbolSize : " + getSize(info.name) + ",\n");
nodeBuffer.append("symbol :\"circle\"" + ",\n");
nodeBuffer.append("category : " + isUpStreamNode(info.name) + "\n");
nodeBuffer.append("}" + "\n");
}
else
{
nodeBuffer.append("{" + "\n");
NodeInfo info = nodeInfos.get(i);
nodeBuffer.append("name : " + "'" + info.name + "'," + "\n");
nodeBuffer.append("des : " + "'" + info.topic + "'," + "\n");
nodeBuffer.append("symbolSize : " + getSize(info.name) + ",\n");
nodeBuffer.append("symbol :\"circle\"" + ",\n");
nodeBuffer.append("category : " + isUpStreamNode(info.name) + "\n");
nodeBuffer.append("}," + "\n");
}
}
nodeBuffer.append("]" + "\n");
return nodeBuffer;
}
}