javascript or jquery function for deleting graph using onclick event - javascript

I have used rickshaw library for plotting graphs. In that the legend part is there. I have also used button on the legend to delete graph. That means when I click on close button the respected graph should get deleted. But I am unable to do this. Is there any JavaScript or jQuery function to do this? Please help me finding the solution for this. Onclick event.. JavaScript function for deletion of graph
This is my code for plotting graph using rickshaw library...
<html>
<head>
<title>Sample-Rickshaw example</title>
<link type="text/css" rel="stylesheet" href="rickshaw.min.css">
<script src="vendor/d3.min.js"></script>
<script src="vendor/d3.layout.min.js"></script>
<script src="rickshaw.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js">
</script>
// CSS part
<style>
#chart_container {
position: relative;
display: inline-block;
font-family: Arial, Helvetica, sans-serif;
}
#chart {
display: inline-block;
margin-left: 40px;
}
#y_axis {
position: absolute;
top: 0;
bottom: 0;
width: 40px;
}
#legend {
display: oneline-block;
vertical-align: top;
margin: 0 0 0 10px;
}
#close_box {
btn_size:large;
font-family: Verdana, Geneva, sans-serif;
font-size:small ; font-weight: bold;
float: right; color: #666;
display: block; text-decoration: none;
border: 2px solid #666;
padding: 0px 3px 0px 3px;
}
</style>
// actual code
<body>
<div id="chart_container">
<div id="y_axis"></div>
<div id="chart"></div>
</div>
</head>
<div id="chart">
</div>
<div id="legend">
<FORM>
<INPUT type="button" value="x" onclick="remove graph">Remove Graph
</FORM>
</div>
// script for plotting data//
<script>
var palette = new Rickshaw.Color.Palette();
var graph = new Rickshaw.Graph( {
element: document.querySelector("#chart"),
width: 550,
height: 250,
series: [
{
name: "Northeast",
data: [ { x: -1893456000, y: 25868573 }, { x: -1577923200, y: 29662053 }, { x: -1262304000, y: 34427091 }, { x: -946771200, y: 35976777 }, { x: -631152000, y: 39477986 }, { x: -315619200, y: 44677819 }, { x: 0, y: 49040703 }, { x: 315532800, y: 49135283 }, { x: 631152000, y: 50809229 }, { x: 946684800, y: 53594378 }, { x: 1262304000, y: 55317240 } ],
color: palette.color(),
}
]
} );
var x_axis = new Rickshaw.Graph.Axis.Time( { graph: graph } );
var y_axis = new Rickshaw.Graph.Axis.Y( {
graph: graph,
orientation: 'left',
tickFormat: Rickshaw.Fixtures.Number.formatKMBT,
element: document.getElementById('y_axis'),
} );
var legend = new Rickshaw.Graph.Legend( {
element: document.querySelector('#legend'),
graph: graph
} );
graph.render();
// jquery function
$('#legend').on('click','.button',function(e){
$(this).remove(graph);
e.preventdefault
});
/*
$('#legend').on('click', function(e){
$('#legend').remove(); // or do something else
e.preventDefault();
}
*/
</script>
//Html tags
</body>
</html>
This is my whole code for plotting graph and respected legend.. commented part in the code is for deletion part.Is there any JavaScript or jQuery function to do this? Please help me finding the solution for this. Onclick event.. JavaScript function for deletion of graph`

The JavaScript error console complains about multiple things in your code. Perhaps take some time to find your errors yourself before you implement my changes. Always have the error console open when you are coding something in JavaScript!
To get your code working:
In the onclick-attribute something in JavaScript is expected. Instead of:
<!-- this is invalid, not a method call, not an initialization, in onclick ... -->
<INPUT type="button" value="x" onclick="remove graph">Remove Graph
put
<input type="button" value="x" onclick="removegraph()" />Remove Graph
Notice that I also ended the tag with />. Pay attention that all the tags are closed correctly!
When I analyzed the elements on the website, I noticed that the graph isn't printed in the graph div, but uses the chart_container. To change this behavior I edited the parameters of the graph:
var graph = new Rickshaw.Graph( {
element: $("#chart")[0], // I changed this line because this was obviously not working
width: 550,
height: 250,
series: [{
name: "Northeast",
data: [ { x: -1893456000, y: 25868573 }, { x: -1577923200, y: 29662053 }, { x: -1262304000, y: 34427091 }, { x: -946771200, y: 35976777 }, { x: -631152000, y: 39477986 }, { x: -315619200, y: 44677819 }, { x: 0, y: 49040703 }, { x: 315532800, y: 49135283 }, { x: 631152000, y: 50809229 }, { x: 946684800, y: 53594378 }, { x: 1262304000, y: 55317240 } ],
color: palette.color()
}]
});
Replace your method
// jquery function
$('#legend').on('click','.button',function(e){
$(this).remove(graph);
e.preventdefault // this line throws an error, because there is no ; and it is not a method-call nor an initialization or anything
});
with
// we've defined before, that this method is called when you click on the button X
function removegraph()
{
$("#chart").remove() ;
// uncomment the following lines, if you want to remove also the chart_container and the legend
// $("#chart_container").remove() ;
// $("#legend").remove() ;
}
Also pay attention that you open and close the tags in the correct order, for example:
<html>
<head>
</head>
<body>
</body>
</html>
This isn't correct in your code.

Related

Jointjs trigger action when hovering a markup selector of cell

I know that it's pretty easy to trigger an action in JointJS if you click a markup selector. We can simply add a custom event attr of that markup element, but as far as I know only pointer events are allowed. Is there any way to archive the same for hovering?
For example I have a custom cell with 4 buttons, that are just a bunch of svg tag added via the markup. I want to change the opacity of all other elements on the canvas, depending on the button that was hovered. I have an idea on how to filter everything and change the opacity, but I have no idea on how to trigger that event and know what selector I'm hovering.
You could take advantage of the 'element:mouseenter' event on the paper, then event.target can give you access to sub-elements on the shape.
In the following example, when you hover a color on the button shape, the standard.Rectangle type shapes all change to that color.
This solution takes advantage of adding classes via markup, and checking if the target has the particular class.
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jointjs/3.6.5/joint.css" />
<style>
.joint-paper {
display: inline-block;
border: 1px solid gray;
}
</style>
</head>
<body>
<!-- content -->
<div id="myholder"></div>
<!-- dependencies -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.4.1/backbone.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jointjs/3.6.5/joint.js"></script>
<!-- code -->
<script type="text/javascript">
var namespace = joint.shapes;
var graph = new joint.dia.Graph({}, { cellNamespace: namespace });
var paper = new joint.dia.Paper({
el: document.getElementById('myholder'),
model: graph,
width: 600,
height: 300,
gridSize: 1,
cellViewNamespace: namespace
});
class ButtonShape extends joint.dia.Element {
defaults() {
return {
...super.defaults,
type: 'MyShape',
size: {
width: 120,
height: 155
},
attrs: {
body: {
width: 'calc(w)',
height: 'calc(h)',
fill: '#ffffff',
stroke: '#333333',
strokeWidth: 2,
rx: 5,
ry: 5,
pointerEvents: 'none'
},
rectUpper: {
width: 'calc(0.8*w)',
height: 'calc(h/2.5)',
fill: 'cornflowerblue',
stroke: '#333333',
strokeWidth: 2,
x: 'calc(0.1*w)',
y: 10
},
rectLower: {
width: 'calc(0.8*w)',
height: 'calc(h/2.5)',
fill: 'tomato',
stroke: '#333333',
strokeWidth: 2,
x: 'calc(0.1*w)',
y: 'calc(h - calc(h/2.5 + 10))'
},
}
};
}
preinitialize() {
this.markup = [{
tagName: 'rect',
selector: 'body'
}, {
tagName: 'rect',
selector: 'rectUpper',
className: 'upper'
}, {
tagName: 'rect',
selector: 'rectLower',
className: 'lower'
}];
}
}
const buttonShape = new ButtonShape();
buttonShape.position(10, 10);
buttonShape.addTo(graph);
for(let i = 0; i < 5; i++) {
const rect = new joint.shapes.standard.Rectangle();
rect.position(i * 60 + 10, 200);
rect.resize(50, 50);
rect.addTo(graph);
}
paper.on('element:mouseenter', function (cellView, evt) {
const rectangles = graph.getElements().filter((el) => el.get('type') === 'standard.Rectangle');
if (evt.target.classList.contains('upper')) {
rectangles.forEach((rect) => {
rect.attr('body/fill', 'cornflowerblue')
});
}
if (evt.target.classList.contains('lower')) {
rectangles.forEach((rect) => {
rect.attr('body/fill', 'tomato')
});
}
});
</script>
</body>
</html>

Connect the dot vertically instead of horizontally on Line Chart

I have a line chart which shows multiple lines. X-axis represents date and Y-axis represents numeric reading. The lines represent the category PZ-1, PZ-2 & PZ-3. I have managed to remove the horizontal line that connect between the dots but now I want to connect the dots vertically that aligns based on the date on X-axis. I do not want to rotate the line or swap X-axis position with Y-axis and vice versa. Does anyone know how I can achieve the vertical line? Thank you
Below is my current code:
const data = {
datasets: [
{label: 'PZ-1',data:[{x:'2022-02-25', y:40.551},{x:'2022-03-01', y:35.889},{x:'2022-03-02', y:34.68},{x:'2022-03-03', y:33.182},{x:'2022-03-04', y:30.82},{x:'2022-03-05', y:29.864},{x:'2022-03-08', y:28.413},{x:'2022-03-10', y:28.413},{x:'2022-03-12', y:28.424},{x:'2022-03-15', y:25.578},{x:'2022-03-17', y:27.07},{x:'2022-03-19', y:27.42},{x:'2022-03-22', y:27.478},{x:'2022-03-24', y:22.817},{x:'2022-03-26', y:22.576},{x:'2022-03-29', y:22.326},{x:'2022-03-31', y:22.011},{x:'2022-04-02', y:21.672},{x:'2022-04-05', y:21.561},{x:'2022-04-07', y:21.307},{x:'2022-04-09', y:34.988},{x:'2022-04-12', y:28.89},{x:'2022-04-14', y:28.618},{x:'2022-04-17', y:28.862},{x:'2022-04-19', y:27.727},{x:'2022-04-21', y:27.493},{x:'2022-04-23', y:27.149},{x:'2022-04-26', y:25.862},{x:'2022-04-28', y:25.59},{x:'2022-04-30', y:25.37},{x:'2022-05-04', y:24.79},{x:'2022-05-06', y:24.927}],backgroundColor: '#778899',borderColor: '#778899',borderWidth: 1,showLine: false},{label: 'PZ-2',data:[{x:'2022-02-22', y:40.994},{x:'2022-03-01', y:55.537},{x:'2022-03-02', y:62.907},{x:'2022-03-03', y:59.462},{x:'2022-03-04', y:55.175},{x:'2022-03-05', y:53.294},{x:'2022-03-08', y:50.284},{x:'2022-03-10', y:49.89},{x:'2022-03-12', y:50.334},{x:'2022-03-15', y:47.137},{x:'2022-03-17', y:48.726},{x:'2022-03-19', y:48.294},{x:'2022-03-22', y:48.002},{x:'2022-03-24', y:40.156},{x:'2022-03-26', y:39.857},{x:'2022-03-29', y:39.678},{x:'2022-03-31', y:39.331},{x:'2022-04-02', y:36.719},{x:'2022-04-05', y:36.438},{x:'2022-04-07', y:36.258},{x:'2022-04-09', y:72.891},{x:'2022-04-12', y:59.97},{x:'2022-04-14', y:59.578},{x:'2022-04-17', y:59.781},{x:'2022-04-19', y:60.408},{x:'2022-04-21', y:60.309},{x:'2022-04-23', y:59.82},{x:'2022-04-26', y:61.679},{x:'2022-04-28', y:61.539},{x:'2022-04-30', y:61.187},{x:'2022-05-04', y:59.871},{x:'2022-05-06', y:59.63}],backgroundColor: '#DB7093',borderColor: '#DB7093',borderWidth: 1,showLine: false},{label: 'PZ-3',data:[{x:'2022-02-22', y:51.455},{x:'2022-03-01', y:44.882},{x:'2022-03-02', y:58.791},{x:'2022-03-03', y:55.118},{x:'2022-03-04', y:48.364},{x:'2022-03-05', y:47.498},{x:'2022-03-08', y:45.477},{x:'2022-03-10', y:44.859},{x:'2022-03-12', y:45.468},{x:'2022-03-15', y:39.599},{x:'2022-03-17', y:40.561},{x:'2022-03-19', y:39.993},{x:'2022-03-22', y:40.232},{x:'2022-03-24', y:33.061},{x:'2022-03-26', y:33.169},{x:'2022-03-29', y:32.99},{x:'2022-03-31', y:32.849},{x:'2022-04-02', y:31.811},{x:'2022-04-05', y:31.412},{x:'2022-04-07', y:31.223},{x:'2022-04-09', y:84.506},{x:'2022-04-12', y:74.415},{x:'2022-04-14', y:74.079},{x:'2022-04-17', y:73.876},{x:'2022-04-19', y:87.873},{x:'2022-04-21', y:87.748},{x:'2022-04-23', y:87.45},{x:'2022-04-26', y:76.555},{x:'2022-04-28', y:76.401},{x:'2022-04-30', y:76.649},{x:'2022-05-04', y:75.585},{x:'2022-05-06', y:75.748}],backgroundColor: '#8B008B',borderColor: '#8B008B',borderWidth: 1,showLine: false}
]
};
// config
const config = {
type: 'line',
data,
options: {
layout: {
padding: {
left: 5
}
},
indexAxis: 'x',
scales: {
y: {
beginAtZero: true
},
x:{
reverse: false,
type: 'time',
time: {
tooltipFormat: 'dd-MMM-yy',
displayFormats: {
day: 'dd-MMM-yy'
}
},
ticks: {
source: 'date',
autoSkip: false
}
}
}
}
};
// render init block
const myChart = new Chart(
document.getElementById('myChart'),
config
);
* {
margin: 0;
padding: 0;
font-family: sans-serif;
}
.chartCard {
overflow:auto;
background: rgba(255, 26, 104, 0.2);
display: flex;
align-items: center;
justify-content: center;
}
.chartBox {
padding: 20px;
border-radius: 20px;
border: solid 3px rgba(255, 26, 104, 1);
background: white;
}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Line Chart</title>
</head>
<body>
<div class="chartCard">
<div class="chartBox">
<canvas id="myChart" style="position: relative;height:1200px;width:1400px"></canvas>
</div>
</div>
<script src="https://rawgit.com/moment/moment/2.2.1/min/moment.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js"></script>
</body>
</html>
You can use the Plugin Core API and define a beforeDraw hook that draws the lines directly on the canvas through the CanvasRenderingContext2D.
Please take a look at your amended code and see how it works.
const data = {
datasets: [
{label: 'PZ-1',data:[{x:'2022-02-25', y:40.551},{x:'2022-03-01', y:35.889},{x:'2022-03-02', y:34.68},{x:'2022-03-03', y:33.182},{x:'2022-03-04', y:30.82},{x:'2022-03-05', y:29.864},{x:'2022-03-08', y:28.413},{x:'2022-03-10', y:28.413},{x:'2022-03-12', y:28.424},{x:'2022-03-15', y:25.578},{x:'2022-03-17', y:27.07},{x:'2022-03-19', y:27.42},{x:'2022-03-22', y:27.478},{x:'2022-03-24', y:22.817},{x:'2022-03-26', y:22.576},{x:'2022-03-29', y:22.326},{x:'2022-03-31', y:22.011},{x:'2022-04-02', y:21.672},{x:'2022-04-05', y:21.561},{x:'2022-04-07', y:21.307},{x:'2022-04-09', y:34.988},{x:'2022-04-12', y:28.89},{x:'2022-04-14', y:28.618},{x:'2022-04-17', y:28.862},{x:'2022-04-19', y:27.727},{x:'2022-04-21', y:27.493},{x:'2022-04-23', y:27.149},{x:'2022-04-26', y:25.862},{x:'2022-04-28', y:25.59},{x:'2022-04-30', y:25.37},{x:'2022-05-04', y:24.79},{x:'2022-05-06', y:24.927}],backgroundColor: '#778899',borderColor: '#778899',borderWidth: 1,showLine: false},{label: 'PZ-2',data:[{x:'2022-02-22', y:40.994},{x:'2022-03-01', y:55.537},{x:'2022-03-02', y:62.907},{x:'2022-03-03', y:59.462},{x:'2022-03-04', y:55.175},{x:'2022-03-05', y:53.294},{x:'2022-03-08', y:50.284},{x:'2022-03-10', y:49.89},{x:'2022-03-12', y:50.334},{x:'2022-03-15', y:47.137},{x:'2022-03-17', y:48.726},{x:'2022-03-19', y:48.294},{x:'2022-03-22', y:48.002},{x:'2022-03-24', y:40.156},{x:'2022-03-26', y:39.857},{x:'2022-03-29', y:39.678},{x:'2022-03-31', y:39.331},{x:'2022-04-02', y:36.719},{x:'2022-04-05', y:36.438},{x:'2022-04-07', y:36.258},{x:'2022-04-09', y:72.891},{x:'2022-04-12', y:59.97},{x:'2022-04-14', y:59.578},{x:'2022-04-17', y:59.781},{x:'2022-04-19', y:60.408},{x:'2022-04-21', y:60.309},{x:'2022-04-23', y:59.82},{x:'2022-04-26', y:61.679},{x:'2022-04-28', y:61.539},{x:'2022-04-30', y:61.187},{x:'2022-05-04', y:59.871},{x:'2022-05-06', y:59.63}],backgroundColor: '#DB7093',borderColor: '#DB7093',borderWidth: 1,showLine: false},{label: 'PZ-3',data:[{x:'2022-02-22', y:51.455},{x:'2022-03-01', y:44.882},{x:'2022-03-02', y:58.791},{x:'2022-03-03', y:55.118},{x:'2022-03-04', y:48.364},{x:'2022-03-05', y:47.498},{x:'2022-03-08', y:45.477},{x:'2022-03-10', y:44.859},{x:'2022-03-12', y:45.468},{x:'2022-03-15', y:39.599},{x:'2022-03-17', y:40.561},{x:'2022-03-19', y:39.993},{x:'2022-03-22', y:40.232},{x:'2022-03-24', y:33.061},{x:'2022-03-26', y:33.169},{x:'2022-03-29', y:32.99},{x:'2022-03-31', y:32.849},{x:'2022-04-02', y:31.811},{x:'2022-04-05', y:31.412},{x:'2022-04-07', y:31.223},{x:'2022-04-09', y:84.506},{x:'2022-04-12', y:74.415},{x:'2022-04-14', y:74.079},{x:'2022-04-17', y:73.876},{x:'2022-04-19', y:87.873},{x:'2022-04-21', y:87.748},{x:'2022-04-23', y:87.45},{x:'2022-04-26', y:76.555},{x:'2022-04-28', y:76.401},{x:'2022-04-30', y:76.649},{x:'2022-05-04', y:75.585},{x:'2022-05-06', y:75.748}],backgroundColor: '#8B008B',borderColor: '#8B008B',borderWidth: 1,showLine: false}]};
const config = {
type: 'line',
plugins: [{
beforeDraw: chart => {
var ctx = chart.ctx;
ctx.save();
ctx.strokeStyle = '#aaaaaa';
var xAxis = chart.scales.x;
var yAxis = chart.scales.y;
xAxis.ticks.forEach((t, i) => {
const dateString = moment(t.value).format('YYYY-MM-DD');
const values = chart.data.datasets
.filter((ds, i) => !chart.getDatasetMeta(i).hidden)
.map(ds => ds.data.find(v => v.x == dateString))
.filter(v => v != undefined)
.map(o => o.y);
if (values.length > 1) {
var x = xAxis.getPixelForTick(i);
var yTop = yAxis.getPixelForValue(Math.max(...values));
var yBottom = yAxis.getPixelForValue(Math.min(...values));
ctx.beginPath();
ctx.moveTo(x, yBottom);
ctx.lineTo(x, yTop);
ctx.stroke();
}
});
ctx.restore();
}
}],
data,
options: {
layout: {
padding: {
left: 5
}
},
scales: {
y: {
beginAtZero: true
},
x: {
offset: true,
type: 'time',
time: {
tooltipFormat: 'dd-MMM-yy',
displayFormats: {
day: 'dd-MMM-yy'
}
},
grid: {
display: false
},
ticks: {
source: 'date',
autoSkip: false
}
}
}
}
};
new Chart('myChart', config );
<script src="https://rawgit.com/moment/moment/2.2.1/min/moment.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js"></script>
<canvas id="myChart" height="140"></canvas>

The graph fly out of screen when the child number per node is greater than 5

I learned cytoscape.js and related extension some days and tried its many amazing features.
I find that when the number of children is greater than 5 and expand a node, the whole graph fly out of screen.
I constructed more complex data which own 3 parent nodes and 5 child nodes per parent node. There is a connection between any two child nodes.
So there are 3 parent nodes, 15 children nodes and 14+13+12..1 links.
To sum up, when there are more links, the layout behavior looks abnormal.
See my demo below.
You can modify parameters of my function getInitData() to see the effect.
document.addEventListener('DOMContentLoaded', function(){
var cy = window.cy = cytoscape({
container: document.getElementById('cy'),
ready: function(){
var api = this.expandCollapse({
layoutBy: {
name: "cose-bilkent",
animate: 'end',
randomize: false,
fit: false,
idealEdgeLength : 150
},
fisheye: false,
animate: true,
undoable: false
});
api.collapseAll();
},
style: [
{
selector: 'node',
style: {
'background-color': '#ad1a66'
}
},
{
selector: ':parent',
style: {
'background-opacity': 0.333
}
},
{
selector: "node.cy-expand-collapse-collapsed-node",
style: {
"background-color": "darkblue",
"shape": "rectangle"
}
},
{
selector: 'edge',
style: {
'width': 3,
'line-color': '#ad1a66'
}
},
{
selector: 'edge.meta',
style: {
'width': 2,
'line-color': 'red'
}
},
{
selector: ':selected',
style: {
"border-width": 3,
"border-color": '#DAA520'
}
}
],
elements : getInitData(3, 5)
});
var api = cy.expandCollapse('get');
var elements = null;
});
function getInitData(parentNum, childrenNum){
var data = [], children = [], i, j, n;
for(i = 0; i < parentNum; i++){
n = "parent"+i;
data.push({"group":'nodes',data:{"id":n}});
for(j = 0; j < childrenNum; j++){
children.push({"group":'nodes',data:{"id":n+"_child_"+j, parent:n}});
}
}
var s,t;
for(i = 0; i < children.length - 1; i++){
s = children[i].data.id;
for(j = i+1; j < children.length; j++){
t = children[j].data.id;
data.push({"group":'edges',data:{"id":s+"_"+t, source:s, target:t}});
}
}
return data.concat(children);
}
body {
font-family: helvetica neue, helvetica, liberation sans, arial, sans-serif;
font-size: 14px;
}
#cy {
z-index: 999;
width: 100%;
height: 100%;
}
h1 {
opacity: 0.5;
font-size: 1em;
font-weight: bold;
}
<script src="https://code.jquery.com/jquery-2.0.3.min.js"></script>
<script src="https://unpkg.com/cytoscape#3.1.0/dist/cytoscape.min.js"></script>
<!-- for testing with local version of cytoscape.js -->
<!--<script src="../cytoscape.js/build/cytoscape.js"></script>-->
<script src="https://unpkg.com/cytoscape-cose-bilkent#4.0.0/cytoscape-cose-bilkent.js"></script>
<script src="https://unpkg.com/cytoscape-expand-collapse#3.1.1/cytoscape-expand-collapse.js"></script>
<div id="cy"></div>
Solution one:
Your graph doesn't have any fitting logic. You can implement that yourself with the two methods cy.center(), which centers the graph to the current viewport and cy.fit(), which zooms the graph to the right position. You would have to call these mehtods everytime you change your graph, e.g. when you add a node, remove a node or, like in your case, expand and collapse. You can do that by binding these events and calling the said methods there.
Binding, as you know from the last question works like this:
cy.unbind('event');
cy.bind('event', 'target', function (event) {...});
Solution two:
You can alternatively, if possible (not all layouts can do this), set the method to fit: true,, which fits the graph with cy.fit(); and cy.center(); internally.
Additional problem and solution for that:
You said, that your graph looks bad when you only have one node in it, so to circumvent that, you can set the padding property of 'cose-bilkent' to a higher number. You can do that at the initialization in the options.
document.addEventListener('DOMContentLoaded', function() {
var padding = 10;
var cy = window.cy = cytoscape({
container: document.getElementById('cy'),
layout: {
name: 'cose-bilkent',
animate: false,
randomize: true
},
style: [{
selector: 'node',
style: {
'background-color': '#ad1a66'
}
},
{
selector: 'edge',
style: {
'width': 3,
'line-color': '#ad1a66'
}
}
],
elements: [{
"data": {
"id": "glyph9"
}
}]
});
document.getElementById("add").addEventListener("click", function() {
padding += 10;
var layout = cy.layout({
name: 'cose-bilkent',
animate: false,
padding: padding
});
layout.run();
});
});
body {
font: 14px helvetica neue, helvetica, arial, sans-serif;
}
#cy {
height: 90%;
width: 100%;
position: absolute;
float: left;
}
button {
margin-right: 10px;
}
<!DOCTYPE>
<html>
<head>
<title>cytoscape-cose-bilkent.js demo</title>
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1">
<script src="https://code.jquery.com/jquery-2.0.3.min.js"></script>
<script src="https://unpkg.com/cytoscape#3.1.0/dist/cytoscape.min.js"></script>
<!-- for testing with local version of cytoscape.js -->
<!--<script src="../cytoscape.js/build/cytoscape.js"></script>-->
<script src="https://unpkg.com/cytoscape-cose-bilkent#4.0.0/cytoscape-cose-bilkent.js"></script>
<script src="https://unpkg.com/cytoscape-expand-collapse#3.1.1/cytoscape-expand-collapse.js"></script>
</head>
<body>
<button id="add" type="button">Add padding</button>
<div id="cy"></div>
</body>
</html>

Time slider to move automatically using setInterval()

I am trying to make a Mapbox map that would show data chronologically for a given year, and I am trying to make the year be specified automatically in sequence.
However, I am having a problem using setInterval to move the time slider in the following script automatically, and it gives me a [object HTMLLabelElement] without the slider moving.
Am I setting the setInterval to the wrong function?
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<title></title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.29.0/mapbox-gl.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.29.0/mapbox-gl.css' rel='stylesheet' />
<style>
body { margin:0; padding:0; }
#map { position:absolute; top:0; bottom:0; width:100%; }
</style>
</head>
<body>
<style>
.map-overlay {
font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;
position: absolute;
width: 25%;
top: 0;
left: 0;
padding: 10px;
}
.map-overlay .map-overlay-inner {
background-color: #fff;
box-shadow:0 1px 2px rgba(0, 0, 0, 0.20);
border-radius: 3px;
padding: 10px;
margin-bottom: 10px;
}
.map-overlay h2 {
line-height: 24px;
display: block;
margin: 0 0 10px;
}
.map-overlay input {
background-color: transparent;
display: inline-block;
width: 100%;
position: relative;
margin: 0;
cursor: ew-resize;
}
</style>
<div id='map'></div>
<div class='map-overlay top'>
<div class='map-overlay-inner'>
<h2>Tel-Aviv Cinemas 1914-2016</h2>
<label id='Year'></label>
<input id='slider' type='range' min='0' max='102' step='1' value='0' />
</div>
<div class='map-overlay-inner'></div>
</div>
<script src="https://d3js.org/d3.v4.js"></script>
<script>
mapboxgl.accessToken = 'pk.eyJ1Ijoia3Z5YiIsImEiOiJjaXUwMHEwcmgwMDAxMnlvM3NzMm0xbGozIn0.JL_eeNZL_lDoJxijNqFPoA';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/dark-v9',
center: [34.775981, 32.081287],
zoom: 11
});
var Years = ['1914', '1915', '1916', '1917', '1918', '1919', '1920', '1921', '1922', '1923', '1924', '1925', '1926', '1927', '1928', '1929', '1930', '1931', '1932', '1933', '1934', '1935', '1936', '1937', '1938', '1939', '1940', '1941', '1942', '1943', '1944', '1945', '1946', '1947', '1948', '1949', '1950', '1951', '1952', '1953', '1954', '1955', '1956', '1957', '1958', '1959', '1960', '1961', '1962', '1963', '1964', '1965', '1966', '1967', '1968', '1969', '1970', '1971', '1972', '1973', '1974', '1975', '1976', '1977', '1978', '1979', '1980', '1981', '1982', '1983', '1984', '1985', '1986', '1987', '1988', '1989', '1990', '1991', '1992', '1993', '1994', '1995', '1996', '1997', '1998', '1999', '2000', '2001', '2002', '2003', '2004', '2005', '2006', '2007', '2008', '2009', '2010', '2011', '2012', '2013', '2014', '2015', '2016'];
function filterBy(Year) {
var filters = ['==', 'Year', Year];
map.setFilter('cinema-circles', filters);
map.setFilter('cinema-labels', filters);
// Set the label to the Year
document.getElementById('Year').textContent = Year;
}
map.on('load', function() {
// Data courtesy of https://earthquake.usgs.gov/
// Query for significant earthquakes in 2015 URL request looked like this:
// https://earthquake.usgs.gov/fdsnws/event/1/query
// ?format=geojson
// &starttime=2015-01-01
// &endtime=2015-12-31
// &minmagnitude=6'
//
// Here we're using d3 to help us make the ajax request but you can use
// Any request method (library or otherwise) you wish.
d3.json('https://cldex.net/visual/cinema_telaviv.geojson', function(err, data) {
if (err) throw err;
// Create a Year property value based on time
// used to filter against.
data.features = data.features.map(function(d) {
return d;
});
map.addSource('cinemas', {
'type': 'geojson',
'data': data
});
map.addLayer({
'id': 'cinema-circles',
'type': 'circle',
'source': 'cinemas',
'paint': {
'circle-color': {
property: 'sqrt',
stops: [
[0, '#f1f075'],
[1500, '#e55e5e']
]
},
'circle-opacity': 0.75,
'circle-radius': 20
}
});
map.addLayer({
'id': 'cinema-labels',
'type': 'symbol',
'source': 'cinemas',
'layout': {
'text-field': '{Cinema}',
'text-font': ['Open Sans Bold', 'Arial Unicode MS Bold'],
'text-size': 12
},
'paint': {
'text-color': 'rgba(0,0,0,0.5)'
}
});
// Set filter to first Year of the Year
// 0 = 1914
filterBy(1914);
document.getElementById('slider').addEventListener('input', function(e) {
var Year = window.setInterval(function() { parseInt(Years[e.target.value]) }, 1000);
filterBy(Year);
});
// Create a popup, but don't add it to the map yet.
var popup = new mapboxgl.Popup({
closeButton: false,
closeOnClick: false
});
map.on('mousemove', function(e) {
var features = map.queryRenderedFeatures(e.point, { layers: ['cinema-circles'] });
// Change the cursor style as a UI indicator.
map.getCanvas().style.cursor = (features.length) ? 'pointer' : '';
if (!features.length) {
popup.remove();
return;
}
var feature = features[0];
// Populate the popup and set its coordinates
// based on the feature found.
popup.setLngLat(feature.geometry.coordinates)
.setHTML(feature.properties.Cinema+'<b> Cinema Information</b>'+'<br><b>Number: </b>'+feature.properties.Number+'<br><b>Number of Screens: </b>'+feature.properties.Screens+'<br><b>Number of Seats: </b>'+feature.properties.Seatss)
.addTo(map);
});
});
});
</script>
</body>
</html>
My Data can be found in a geojson: https://cldex.net/visual/cinema_telaviv.geojson
Your usage of setInterval is incorrect currently, and you have a few syntax errors.
Where you currently have this:
var Year = set.Interval(function() { parseInt(Years[e.target.value] }, 1000);
Try this instead:
var Year = window.setInterval(function() { parseInt(Years[e.target.value]) }, 1000);
You may still have some issues elsewhere, but I was having difficulty getting your data endpoint parsing correctly in d3. It may help to post up a codepen or something of this to get more help if you need it.
Edit:
I've created a codepen from your current setup, which may help you to tinker around a little easier: http://codepen.io/anon/pen/EZjKqM
As you can see I've made a few more changes, such as adding something to increment through the array of years which uses your filterBy function. It doesn't work perfectly, but you can see how it's parsing the data correctly and changing the year by the second.
This is achieved by using the following JS:
// Automatically cycle through years.
var yearSlider = document.getElementById('slider');
var curYearIndex = -1;
function advanceYear() {
++curYearIndex;
if (curYearIndex >= years.length) {
curYearIndex = 0;
}
return years[curYearIndex];
}
var cycleYears = window.setInterval(function() {
var currentYear = advanceYear();
filterBy(parseInt(currentYear));
}, 1000);
Unfortunately this is probably as far as I'll get with this, as I've other things to work on, but it perhaps gives you a bit of a starting point.
#Wakeuphate, this is an awesome solution (up-voted accordingly). I was able to implement quickly for my project.
It seems the missing item was moving the slider as well. I was able to achieve this by simply adding the following line:
document.getElementById('slider').value = currentYear;
So that the full function looks like:
var cycleYears = window.setInterval(function() {
var currentYear = advanceYear();
filterBy(parseInt(currentYear));
document.getElementById('slider').value = currentYear;
}, 1000);

How Align the Legend Items in Chart.js 2?

I just need to align the Chart Legend so it don't look too messy as the default shows, here is an example what I'm trying to achieve:
Please give some code suggestions: https://jsfiddle.net/holp/68wf75r8/
new Chart(document.getElementById("field-0"), {
type: 'pie',
data: {
labels: ["Chat", "Prospeção", "Whatsapp", "Trial", "Site", "Telefone", "E-mail", "Evento"],
datasets: [{
data: [700, 400, 200, 150, 80, 50, 20, 10],
borderWidth: 2,
hoverBorderWidth: 10,
backgroundColor: pieColors,
hoverBackgroundColor: pieColors,
hoverBorderColor: pieColors,
borderColor: pieColors
}]
},
options: {
legend: {
labels: {
padding: 20
}
}
}
});
There is legend.labels.generateLabels hook you generally can use to customise your legend labels.
I found out, that you can put something like below to adjust Chart.js calculations.
generateLabels: function (chart) {
chart.legend.afterFit = function () {
var width = this.width; // guess you can play with this value to achieve needed layout
this.lineWidths = this.lineWidths.map(function(){return width;});
};
// here goes original or customized code of your generateLabels callback
}
Weird thing that there is no actual configuration option to achieve this.
Chartjs v2 creates an overhead to handle the legends. Basically what you are looking for is to leverage the usage of generateLabels.
The key point to bare in mind is that you need to return an valid array of legend objects.
This plunker describes the solution.
Main focus on this part:
generateLabels: (chart) => {
chart.legend.afterFit = function () {
var width = this.width;
console.log(this);
this.lineWidths = this.lineWidths.map( () => this.width-12 );
this.options.labels.padding = 30;
this.options.labels.boxWidth = 15;
};
var data = chart.data;
//https://github.com/chartjs/Chart.js/blob/1ef9fbf7a65763c13fa4bdf42bf4c68da852b1db/src/controllers/controller.doughnut.js
if (data.labels.length && data.datasets.length) {
return data.labels.map((label, i) => {
var meta = chart.getDatasetMeta(0);
var ds = data.datasets[0];
var arc = meta.data[i];
var custom = arc && arc.custom || {};
var getValueAtIndexOrDefault = this.getValueAtIndexOrDefault;
var arcOpts = chart.options.elements.arc;
var fill = custom.backgroundColor ? custom.backgroundColor : getValueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor);
var stroke = custom.borderColor ? custom.borderColor : getValueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor);
var bw = custom.borderWidth ? custom.borderWidth : getValueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth);
return {
text: label,
fillStyle: fill,
strokeStyle: stroke,
lineWidth: bw,
hidden: isNaN(ds.data[i]) || meta.data[i].hidden,
// Extra data used for toggling the correct item
index: i
};
});
}
return [];
}
I tried to do as advised by the comments above. But to see that it is really difficult. It’s better and easier for me to set:
legend: {display: FALSE, ..} `, and then render the legend using html (angular, react, view .. another render template):
// part of angualr model class
public dataSets = [{
label: "New Deals",
backgroundColor: "#88B2FF",
data: [26, 15, 5],
},
{
label: "Active Deals",
backgroundColor: "#397FFF",
data: [7, 13, 22],
},
....
this.chart = new Chart(ctx, {
type: "roundedBar",
data: {
labels: this.xLabels,
datasets: this.dataSets,
},
<div style="width: 380px;height: 200px; display: inline-block;">
<canvas id="chart" aria-label="Hello ARIA World" role="img"></canvas>
</div>
<!-- This is angular template -->
<ul class="legend">
<li *ngFor="let set of dataSets">
<i [style.backgroundColor]="set.backgroundColor" class="icon"></i>
<label>
{{ set.label }}
</label>
</li>
</ul>
<style>
.legend {
display: flex;
text-align: center;
justify-content: space-between;
font-size: 10px;
line-height: 12px;
}
.icon {
width: 10px;
height: 10px;
border-radius: 50%;
display: inline-block;
}
</style>

Categories

Resources