Related
I have this problem where every time a user hovers there mouse pointer over my map of the USA, the map renders again. (Visually, it flashes on the screen and it looks terrible).
This is because I have an 'entityRolloever' event which causes a state variable to change.
entityRollover: function(event, data){
setHoveredState(data.label)
}
How I understand it is, when a React component (i.e. my map) changes state, it re-renders.
But what I want is, when a user hovers over a U.S. State, I want the state that is being hovered over to show up in a separate text box (without the whole map re-rendering).
I have searched around, and I have found some other React hooks which could solve this. They are useRef, useMemo, and useCallback. However, I'm not sure how they would solve my problem as I have never used them before.
If you want to recreate my problem, create a basic React app
npx create-react-app
Install the following packages
npm i fusioncharts react-fusioncharts fusionmaps
Then grab the code in my jsfiddle and paste it into 'App.js'
https://jsfiddle.net/cmascardo5/s8trame5/
There are a couple of ways to resolve this issue. I chose to replace useState() hook with useRef() since it matches your case perfectly.
useState() is a hook used in functional components to re-render components on state change, but in your case this is NOT something that we want. We want to track the updates without re-rendering the components. To achieve this, we use useRef(). When we use useRef() for the updates it will not fire re-rendering unlike useState().
In your code, I commented out the {hoveredState} you had to avoid re-rendering. Then I created a p element and ref it with useRef(). Then on the entityRollove method, I update the innerText of the referenced p element. This way we are tracking the updates without re-rendering. It is simpler to see the code, I did comment on the lines I added: (paste it in your App.js)
import React from 'react';
import './App.css';
import ReactFC from 'react-fusioncharts';
import FusionCharts from 'fusioncharts';
import FusionMaps from 'fusioncharts/fusioncharts.maps';
import USA from 'fusionmaps/maps/fusioncharts.usa';
import FusionTheme from 'fusioncharts/themes/fusioncharts.theme.fusion';
import { Grid, Paper } from '#material-ui/core';
import { useState } from 'react';
import { useRef } from 'react';
ReactFC.fcRoot(FusionCharts, FusionMaps, USA, FusionTheme);
export default function App({}) {
const [hoveredState, setHoveredState] = useState('All States');
let test1 = 'test';
// const hoveredState =useRef("All states");
// Here we are using UseRef() to get a reference to an element we want to use to show each State's names
const paragraphEl = useRef(null);
const colorrange = {
minvalue: '20',
code: '#00A971',
gradient: '1',
color: [
{
minvalue: '20',
maxvalue: '40',
code: '#EFD951',
},
{
minvalue: '40',
maxvalue: '60',
code: '#FD8963',
},
{
minvalue: '60',
maxvalue: '80',
code: '#D60100',
},
],
};
const data = [
{
id: 'HI',
value: '70.0',
},
{
id: 'DC',
value: '52.3',
},
{
id: 'MD',
value: '54.2',
},
{
id: 'DE',
value: '55.3',
},
{
id: 'RI',
value: '50.1',
},
{
id: 'WA',
value: '48.3',
},
{
id: 'OR',
value: '48.4',
},
{
id: 'CA',
value: '59.4',
},
{
id: 'AK',
value: '26.6',
},
{
id: 'ID',
value: '44.4',
},
{
id: 'NV',
value: '49.9',
},
{
id: 'AZ',
value: '60.3',
},
{
id: 'MT',
value: '42.7',
},
{
id: 'WY',
value: '42.0',
},
{
id: 'UT',
value: '48.6',
},
{
id: 'CO',
value: '45.1',
},
{
id: 'NM',
value: '53.4',
},
{
id: 'ND',
value: '40.4',
},
{
id: 'SD',
value: '45.2',
},
{
id: 'NE',
value: '48.8',
},
{
id: 'KS',
value: '54.3',
},
{
id: 'OK',
value: '59.6',
},
{
id: 'TX',
value: '64.8',
},
{
id: 'MN',
value: '41.2',
},
{
id: 'IA',
value: '47.8',
},
{
id: 'MO',
value: '54.5',
},
{
id: 'AR',
value: '60.4',
},
{
id: 'LA',
value: '66.4',
},
{
id: 'WI',
value: '43.1',
},
{
id: 'IL',
value: '51.8',
},
{
id: 'KY',
value: '55.6',
},
{
id: 'TN',
value: '57.6',
},
{
id: 'MS',
value: '63.4',
},
{
id: 'AL',
value: '62.8',
},
{
id: 'GA',
value: '63.5',
},
{
id: 'MI',
value: '44.4',
},
{
id: 'IN',
value: '51.7',
},
{
id: 'OH',
value: '50.7',
},
{
id: 'PA',
value: '48.8',
},
{
id: 'NY',
value: '45.4',
},
{
id: 'VT',
value: '42.9',
},
{
id: 'NH',
value: '43.8',
},
{
id: 'ME',
value: '41.0',
},
{
id: 'MA',
value: '47.9',
},
{
id: 'CT',
value: '49.0',
},
{
id: 'NJ',
value: '52.7',
},
{
id: 'WV',
value: '51.8',
},
{
id: 'VA',
value: '55.1',
},
{
id: 'NC',
value: '59.0',
},
{
id: 'SC',
value: '62.4',
},
{
id: 'FL',
value: '70.7',
},
];
// };
FusionCharts.ready(function () {
var chart = new FusionCharts({
type: 'maps/usa',
caption: 'Average Temperature of US States',
subcaption: '1979 - 2000',
entityfillhovercolor: '#F8F8E9',
numbersuffix: '°F',
showlabels: '1',
borderthickness: '0.4',
theme: 'fusion',
entitytooltext:
'<b>$lname</b> has an average temperature of <b>$datavalue</b>',
renderAt: 'chart-container',
width: '700',
height: '500',
colorrange: colorrange,
dataFormat: 'json',
dataSource: {
chart: {
caption: 'Average Temperature of US States',
subcaption: '1979 - 2000',
entityfillhovercolor: '#F8F8E9',
numbersuffix: '°F',
showlabels: '1',
borderthickness: '0.4',
theme: 'fusion',
entitytooltext:
'<b>$lname</b> has an average temperature of <b>$datavalue</b>',
// "animation":0,
// "defaultAnimation":0
},
colorrange: colorrange,
data: data,
},
events: {
preRender: function (event, data) {
// code to be executed before the chart is re-rendered
},
postRender: function (event, data) {
// code to be executed after the chart is re-rendered
},
entityRollover: function (event, data) {
console.log('test..' + data.label);
// Here we get a reference to the paragraph element and set its innerText to be the state's name we are hovering on
paragraphEl.current.innerText = data.label;
},
},
}).render();
});
return (
<Grid container spacing={2}>
<Grid item xs={9}>
<div id="chart-container"></div>
</Grid>
<Grid item xs={3}>
// we create a p element that will hold state's name on hover
<p ref={paragraphEl}></p>
{/* {hoveredState} */}
</Grid>
</Grid>
);
}
I am using cytoscape.js for my visualization project in which I have to show a Hierarchical structure with compound nodes.
So I initially used Cose-Bilkent layout which worked like a charm but the requirement is that all the child nodes of a parent must be in a single row. So I tried to tweak around a bit but couldn't get the exact result.
Then I tried to use grid layout by giving hardcoded row and column numbers and I got the exact result but as my data is dynamic I realized its difficult to assign row numbers and column numbers on my own.
Here is the data I used,
elements: [ // list of graph elements to start with
{ // node a
data: { id: 'X1', label: 'X1'}
},
{
data: { id: 'X2', label: 'X2'}
},
{
data: { id: 'X3', label: 'X3'}
},
{
data: { id: 'X4', label: 'X4'}
},
{
data: { id: 'X5', label: 'X5'}
},
{
data: { id: 'X6', label: 'X6'}
},
{
data: { id: 'X7', label: 'X7'}
},
{
data: { id: 'X8', label: 'X8'}
},
{
data: { id: 'X9', label: 'X9'}
},
{
data: { id: 'X10', label: 'X10'}
},
{
data: { id: 'X1e1',label: 'e1', parent: 'X1', row: '1' ,col: '1'}
},
{
data: { id: 'X1e5',label: 'e5', parent: 'X1', row: '1',col: '2'}
},
{
data: { id: 'X1e6',label: 'e6', parent: 'X1', row: '1',col: '3'}
},
{
data: { id: 'X2e2',label: 'e2', parent: 'X2', row: '3',col: '1'}
},
{
data: { id: 'X2e3',label: 'e3', parent: 'X2', row: '3',col: '2'}
},
{
data: { id: 'X3e4',label: 'e4', parent: 'X3', row: '4',col: '1'}
},
{
data: { id: 'X4e5',label: 'e5', parent: 'X4', row: '2',col: '1'}
},
{
data: { id: 'X4e6',label: 'e6', parent: 'X4', row: '2',col: '2'}
},
{
data: { id: 'X5e7',label: 'e7', parent: 'X5', row: '7',col: '1'}
},
{
data: { id: 'X6e8',label: 'e8', parent: 'X6', row: '5',col: '1'}
},
{
data: { id: 'X6e9',label: 'e9', parent: 'X6', row: '5',col: '2'}
},
{
data: { id: 'X7e10',label: 'e10', parent: 'X7', row: '7',col: '2'}
},
{
data: { id: 'X7e11',label: 'e11', parent: 'X7', row: '7',col: '3'}
},
{
data: { id: 'X7e12',label: 'e12', parent: 'X7', row: '7',col: '4'}
},
{
data: { id: 'X8e13',label: 'e13', parent: 'X8', row: '6',col: '1'}
},
{
data: { id: 'X8e14',label: 'e14', parent: 'X8', row: '6',col: '2'}
},
{
data: { id: 'X8e15',label: 'e15', parent: 'X8', row: '6',col: '3'}
},
{
data: { id: 'X8e16',label: 'e16', parent: 'X8', row: '6',col: '4'}
},
{
data: { id: 'X9e17',label: 'e17', parent: 'X9', row: '8',col: '1'}
},
{
data: { id: 'X10e18',label: 'e18', parent: 'X10', row: '8',col: '2'}
},
{
data: { id: 'X1e5X4e5', source:'X1e5', target:'X4e5'}
},
{
data: { id: 'X1e6X4e6', source:'X1e6', target:'X4e6'}
},
{
data: { id: 'X1e1X2', source:'X1e1', target:'X2'}
},
{
data: { id: 'X2e3X3', source:'X2e3', target:'X3'}
},
{
data: { id: 'X4e5X5', source:'X4e5', target:'X5'}
},
{
data: { id: 'X4e6X6', source:'X4e6', target:'X6'}
},
{
data: { id: 'X6X8e16', source:'X6', target:'X8e16'}
},
{
data: { id: 'X6e9X8', source:'X6e9', target:'X8'}
},
{
data: { id: 'X6e8X7', source:'X6e8', target:'X7'}
},
{
data: { id: 'X6X7e12', source:'X6', target:'X7e12'}
}
]
and layout
layout:{
name: 'grid',
fit: true,
position: function( node ){ return {row:node.data('row'), col:node.data('col') }}
}
And here is the result I got(and also expected) by setting manual rows and columns
Any help would be appreciated. Thanks
Well there are two extensions, which would achieve just what you need:
even-parents
no-overlap
Coincidentally, both come from the same person, so this should not be a problem at all, all you have to do from there is to apply the right styles for the application to look like your example:
document.addEventListener("DOMContentLoaded", function() {
var cy = (window.cy = cytoscape({
container: document.getElementById("cy"),
layout: {
name: "evenParent"
},
style: [{
selector: "node",
style: {
"content": "data(id)",
"background-color": "#ad1a66"
}
},
{
selector: ":parent",
style: {
"background-opacity": 0.333
}
},
{
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: {
nodes: [{
data: {
id: "Jerry",
name: "Jerry"
}
},
{
data: {
id: "Elaine",
name: "Elaine"
}
},
{
data: {
id: "Kramer",
name: "Kramer"
}
},
{
data: {
id: "George",
name: "George"
}
},
{
data: {
id: "Martin",
name: "Martin"
}
},
{
data: {
id: "Philippe",
name: "Philippe"
}
},
{
data: {
id: "Louis",
name: "Louis"
}
},
{
data: {
id: "Genevieve",
name: "Genevieve"
}
},
{
data: {
id: "Leo",
name: "Leo"
}
},
{
data: {
id: "Larry",
name: "Larry"
}
},
{
data: {
id: "Logaina",
name: "Logaina"
}
}
],
edges: [{
data: {
source: "Jerry",
target: "Elaine"
}
},
{
data: {
source: "Jerry",
target: "Kramer"
}
},
{
data: {
source: "Jerry",
target: "George"
}
},
{
data: {
source: "Elaine",
target: "Martin"
}
},
{
data: {
source: "Elaine",
target: "Philippe"
}
},
{
data: {
source: "Elaine",
target: "Louis"
}
},
{
data: {
source: "Elaine",
target: "Genevieve"
}
},
{
data: {
source: "Elaine",
target: "Leo"
}
},
{
data: {
source: "Kramer",
target: "Larry"
}
},
{
data: {
source: "Kramer",
target: "Logaina"
}
}
]
}
}));
// demo your collection ext
cy.nodes().noOverlap({
padding: 5
});
});
body {
font: 14px helvetica neue, helvetica, arial, sans-serif;
}
#cy {
height: 100%;
width: 100%;
position: absolute;
left: 0;
top: 0;
}
<html>
<head>
<script src="https://unpkg.com/cytoscape/dist/cytoscape.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/cytoscape-even-parent#1.1.1/cytoscape-even-parent.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/cytoscape-no-overlap#1.0.1/cytoscape-no-overlap.min.js"></script>
</head>
<body>
<div id="cy"></div>
</body>
</html>
The following code worked for me,
Please consider #Stephen's code if this doesn't work.
var cy = cytoscape({
container: /* your div within which you want to render */ ,
elements: [ /*list of graph elements to start with */ ] ,
style: [ /* the stylesheet for the graph */ ] ,
layout:{
name: 'cola',
fit: false,
infinite: false,
avoidOverlap: true
}
});
//Used to make child nodes stay on the same row
cy.ready(function(){
setTimeout(function(){
cy.zoom(0.5);
cy.nodes(':compound').forEach(function(comp,j,comps){
var nodePosition={};
if(comp.descendants().length>1)
{
var minX;
var maxY;
comp.descendants().forEach(function(ele,i,eles){
if(i==0)
{
minX=ele.renderedPosition('x');
maxY=ele.renderedPosition('y');
}
else
{
var tempX=ele.renderedPosition('x');
var tempY=ele.renderedPosition('y');
if(tempX<minX)
{
minX=tempX;
}
if(tempY>maxY)
{
maxY=tempY;
}
}
});
comp.descendants().forEach(function(ele,i,eles){
ele.renderedPosition({x:minX,y:maxY});
minX=minX+60;
});
}
cy.resize();
cy.fit();
cy.minZoom(cy.zoom());
});
},1000);
});
P.S: Don't forget to include the cytoscape scripts;)
I am using Fusion charts but one of my charts doesn't load. My html is :
<fusioncharts [width]="width" [height]="height" [type]="type" [dataFormat]="dataFormat" [dataSource]="dataSource">
</fusioncharts>
And the data for the chart:
this.dataSource = {
'chart': {
'caption': 'Number of posts',
'startingangle': '120',
'showlabels': '0',
'showlegend': '1',
'enablemultislicing': '0',
'slicingdistance': '15',
'showpercentvalues': '1',
'showpercentintooltip': '0',
'theme': 'ocean'
},
'data': [
{ label: 'Venezuela', value: '290' },
{ label: 'Saudi', value: '260' },
{ label: 'Canada', value: '180' },
{ label: 'Iran', value: '140' },
{ label: 'Russia', value: '115' },
{ label: 'UAE', value: '100' },
{ label: 'US', value: '30' },
{ label: 'China', value: '30' }
]
};
The particular chart doesn't load. In the console I also got another error TypeError: i.title is undefined. It is in vendor.2d90d48c94b0a738e874.bundle.js. The file is minified and there is no way to unerstand from where it comes. Atleast I can't. Can I ask you for some advice?
I have a panel and inside of it I have a grid, so my question is how to have 2 buttons to collapse/expand all groups in a grid? I'm still new to ExtJs.
Here's the code that I'm using. It works just fine.
var store = Ext.create('Ext.data.Store', {
fields: ['name', 'seniority', 'department'],
groupField: 'department',
data: [
{ name: 'Michael Scott', seniority: 7, department: 'Management' },
{ name: 'Dwight Schrute', seniority: 2, department: 'Sales' },
{ name: 'Jim Halpert', seniority: 3, department: 'Sales' },
{ name: 'Kevin Malone', seniority: 4, department: 'Accounting' },
{ name: 'Angela Martin', seniority: 5, department: 'Accounting' }
]
});
Ext.create('Ext.grid.Panel', {
title: 'Employees',
store: store,
columns: [
{ text: 'Name', dataIndex: 'name', flex: 1 },
{ text: 'Seniority', dataIndex: 'seniority', flex: 1 }
],
features: [{ftype:'grouping'}],
renderTo: Ext.getBody()
});
Maybe using dockedItem in the Panel will be the way I want it.
For buttons, I guess you would use a toolbar on your grid:
tbar:[{
iconCls:'x-fa fa-plus-square',
handler:function(btn) {
btn.up('grid').getView().findFeature("grouping").expandAll();
}
},{
iconCls:'x-fa fa-minus-square',
handler:function(btn) {
btn.up('grid').getView().findFeature("grouping").collapseAll();
}
}]
shortcut
you can directly set the collapsible property attributes of a grid as per your requirement.
I have a treeview like below, i need to remove one child from the list based on the user. Can any one tell me how to remove the child from the treeview.
var treedata = [
{
label: 'Floor', type: 'Country',
children: [
{
label: 'Bangalore', type: 'Location',
children: [{ label: 'Technopolis', type: 'facility', id: 1 }, { label: 'Ecity Tower-2', type: 'facility', id: 2 }, { label: 'Bagmane', type: 'facility', id: 3 }, { label: 'Cyber Park', type: 'facility', id: 4 }]
},
{
label: 'Hyderabad', type: 'Location',
children: [{ label: 'Hitech City ', type: 'facility', id: 5 }, { label: 'Cyber City', type: 'facility', id: 6 }]
},
{
label: 'Chennai', type: 'Location',
children: [{ label: 'XXX', type: 'facility', id: 7 }]
},
{
label: 'Mumbai', type: 'facility', id: 8
}
]
},
{
label: 'Role Administration', type: 'Role',
children: [{ label: 'Assign Role', type: 'Role', id: 1 }]
},
{
label: 'Hoteling Admin', type: 'Hoteling',
children: [{ label: 'Hoteling', type: 'Hoteling', id: 1 }]
}
];
The above is my jquery tree data. I want to remove the role administration if the user is a normal user by checking the user role.
Anyone help me how to do using jquery.
Thanks
You can use $.grep() to filter the array to a new array based on whatever conditions you want.
var userRole='normal';
if( userRole === 'normal'){
treeview = $.grep(treeview, function(item){
return item.label != 'Role Administration';
});
}
grep() API docs