var blockinfo = new Vue({ parent: navbar, el: '#blockinfo', delimiters: ["${", "}"], data: { blocktimechart: null, blocktxchart: null, mapdata: {}, netcode: "N3main" }, watch: { netcode: function (newVal, oldVal) { this.loadBlockInfo(true); this.loadNodeMap(true); } }, methods: { loadBlockInfo(net_changed) { fetch("/api/" + this.netcode + "/latest") .then(resp => { resp.json() .then(json => { this.renderBlockTimeChart(json); this.renderBlockTransactionChart(json); }) .catch(e => { console.log(e) if (net_changed) { this.renderBlockTimeChart([]); this.renderBlockTransactionChart([]); } }); }) .catch(e => { console.log(e) if (net_changed) { this.renderBlockTimeChart([]); this.renderBlockTransactionChart([]); } }); }, renderBlockTransactionChart(json) { let labels = json.map(d => d.height) let data = json.map(d => d.tx) if (this.blocktxchart != null) { this.blocktxchart.data.labels = labels; this.blocktxchart.data.datasets[0].data = data; this.blocktxchart.update(); return; } let ctx = document.getElementById('blocktxchart').getContext('2d'); this.blocktxchart = new Chart(ctx, { type: 'bar', data: { labels: labels, datasets: [{ label: 'tx', data: data, backgroundColor: 'rgba(0, 255, 0, 1)', }] }, options: { responsive: true, plugins:{ legend: { display: false, } }, scales: { yAxes: [{ ticks: { beginAtZero: true, precision: 0, } }] } } }); }, renderBlockTimeChart(json) { let labels = json.map(d => d.height) let data = json.map(d => d.interval) if (this.blocktimechart != null) { this.blocktimechart.data.labels = labels; this.blocktimechart.data.datasets[0].data = data; this.blocktimechart.update(); return; } let ctx = document.getElementById('blocktimechart').getContext('2d'); this.blocktimechart = new Chart(ctx, { type: 'bar', data: { labels: labels, datasets: [{ label: 'blocktime', data: data, backgroundColor: function (ctx) { var index = ctx.dataIndex; var value = ctx.dataset.data[index]; return 30 < value ? 'red' : 'rgba(0, 255, 0, 1)'; }, }] }, options: { responsive: true, plugins:{ legend: { display: false, } }, scales: { yAxes: [{ ticks: { beginAtZero: true } }] } } }); }, loadNodeMap() { fetch("/api/" + this.netcode + "/nodemap") .then(resp => { resp.json() .then(json => { this.mapdata = json; if (this.mapdata.nodes.length > 0) this.drawMap(); }) .catch(e => console.log(e)); }) .catch(e => console.log(e)); }, drawMap() { let selected = new Object(); let width = this.$refs.map.clientWidth; let height = this.$refs.map.clientHeight; if (height == 0) height = 600; let getSelected = () => { return selected; } let setSelected = (e, d) => { selected.ele = e; selected.data = d; } let drag = simulation => { function dragstarted(d) { if (!d3.event.active) simulation.alphaTarget(0.3).restart(); d.fx = d.x; d.fy = d.y; } function dragged(d) { d.fx = d3.event.x; d.fy = d3.event.y; } function dragended(d) { if (!d3.event.active) simulation.alphaTarget(0); d.fx = null; d.fy = null; } return d3.drag() .on("start", dragstarted) .on("drag", dragged) .on("end", dragended); } let color = (d) => { let scale = d3.scaleOrdinal([1, 2, 3, 4, 5, 6, 7, 8, 9], d3.schemeCategory10); let color = scale(d.group); return color; } let links = this.mapdata.links.map(d => Object.create(d)); let nodes = this.mapdata.nodes.map(d => Object.create(d)); let simulation = d3.forceSimulation(nodes) .force("link", d3.forceLink(links).id(d => d.id).strength(0.1).distance(40)) .force("charge", d3.forceManyBody().strength(-100)) .force("center", d3.forceCenter(width / 2, height / 2)); let svg = d3.select(".map").append("svg").attr("width", width).attr("height", height); this.svg = svg; let link = svg.append("g") .attr("stroke", "#999") .attr("stroke-opacity", 0.6) .selectAll("line") .data(links) .join("line") .attr("stroke-width", d => 1); // Define the div for the tooltip var div = d3.select("body").append("div") .attr("class", "tooltip") .style("opacity", 0); let node = svg.append("g") .attr("stroke", "#fff") .attr("stroke-width", 1.5) .selectAll("circle") .data(nodes) .join("circle") .attr("r", 6) .attr("fill", color) .call(drag(simulation)) .on("mouseover", function (d) { let html = d.host != "" ? `Addr: ${d.host}:${d.port}` : `Addr: ${d.ip}:${d.port}`; div.transition() .duration(200) .style("opacity", 1); div.html( html ) .style("left", (d3.event.pageX) + "px") .style("top", (d3.event.pageY - 28) + "px"); }) .on("mouseout", function (d) { div.transition() .duration(500) .style("opacity", 0); }); node.append("title") .text(d => d.name); simulation.on("tick", () => { link .attr("x1", d => d.source.x) .attr("y1", d => d.source.y) .attr("x2", d => d.target.x) .attr("y2", d => d.target.y); node .attr("cx", d => d.x) .attr("cy", d => d.y); }); } }, mounted: function () { this.loadBlockInfo(false); this.loadNodeMap(false); setInterval(() => this.loadBlockInfo(false), 15000); setInterval(() => this.loadNodeMap(false), 1000 * 3600 * 2); }, });