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>
);
}
Help Me please !! What happened to this error? I changed the class name of the table, but I cannot change it and this error occurs?
new gridjs.Grid({
columns: [{ name: 'ID', width: '60px' },
{ name: 'Name', width: '200px' },
{ name: 'Position', width: '300px' },
{ name: 'Email', width: '200px' },
{ name: 'Tel', width: '100px' },
{ name: '', width: '40px', sort: false }],
sort: true,
search: true,
pagination: {
limit: 5,
},
className: {
table: 'table',
thead: 'thead-dark'
},
language: {
'search': {
'placeholder': ' Search...'
},
},
server: {
url: 'http://localhost:55289/ManageUser/GetUserList',
then: data => data.map(user => [user.id,
user.first_name + '\xa0\xa0\xa0' + user.last_name,
user.position, user.email,
user.tel_mobile,
gridjs.html(`<a id="button-delete" href="/ManageUser/Delete/${user.id}"><button class="btn btn-danger"><i class="fa fa-close"></i></button></a>`)])
}
}).render(document.getElementById("user-table"));
As Tammy mentioned, you need to define a custom id for your column:
const grid = new Grid({
columns: [{
id: 'name',
name: 'Name'
}, {
id: 'email',
name: 'Email'
}, {
id: 'phoneNumber',
name: 'Phone Number'
}],
data: [
{ name: 'John', email: 'john#example.com', phoneNumber: '(353) 01 222 3333' },
{ name: 'Mark', email: 'mark#gmail.com', phoneNumber: '(01) 22 888 4444' },
]
});
Demo: https://gridjs.io/docs/examples/import-json
I had the same issue:
Could not find a valid ID for one of the columns.
Make sure a valid "id" is set for all columns
And the fix was what Tammy mentions, I had an empty named column.
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 wanted to replace dojox.grid.DataGrid with new Dgrid but I have trouble with it. I'm using Dojo 1.9.1 and here is excerpts of my code:
HTML:
<script type="text/javascript"><!--
require({
baseUrl: "/res/js/",
packages: [
{ name: "dojo", location: "dojo/dojo" },
{ name: "dijit", location: "dojo/dijit" },
{ name: "dojox", location: "dojo/dojox" },
{ name: "put-selector", location: "put-selector" },
{ name: "xstyle", location: "xstyle" },
{ name: "dgrid", location: "dgrid" },
{ name: "allwins", location: "allwins" }
]
},[
"allwins/Admin",
"dojo/parser",
"dojo/domReady!"
],function(admin, Parser){
admin.initUi(/*...*/);
});
</script>
<!-- ... -->
<div data-dojo-id="invoicesTab2"
data-dojo-type="dijit.layout.BorderContainer"
data-dojo-props="region: 'center',
title: 'Faktury 2'">
<div id=invoicesGridTab2"></div>
</div>
JavaScript:
request(invoicesDataUrl, {
handleAs: "json"
}).then(function (response) {
var store = new Memory({ data: response });
var grid = new OnDemandGrid({
region: "center",
store: store,
columns: {
invoice_id: { label: "FID" },
user_id: { label: "UID" },
invoice_no: { label: "Číslo" },
user_fullname: { label: "Plátce" },
created_formatted: { label: "Vystavena" },
payment_date_formatted: { label: "Splatnost" },
payment_total: { label: "Částka" }
}
}, "invoicesGridTab2");
grid.startup();
});
I can add few more things:
List item
I have no errors at the JavaScript console
data source is already tested with using older dojox.grid.DataGrid
it seems that main problem is with the rendering
Thanks for any help or advice!
You need to specify the field attribute in your columns that match with the response data object, for example:
request(invoicesDataUrl, {
handleAs: "json"
}).then(function (response) {
var store = new Memory({ data: response });
var grid = new OnDemandGrid({
region: "center",
store: store,
columns: {
invoice_id: { label: "FID", field: "invoice_id" },
user_id: { label: "UID", field: "user_id" },
invoice_no: { label: "Číslo", field: "invoice_no" },
user_fullname: { label: "Plátce", field: "user_fullname" },
created_formatted: { label: "Vystavena", field: "created_formatted" },
payment_date_formatted: { label: "Splatnost", field: "payment_date_formatted" },
payment_total: { label: "Částka", field: "payment_total" }
}
}, "invoicesGridTab2");
grid.startup();
});
I do not know if those field names are correct, but I assume you would. :)
I want to group the values in grid panel
Below is the code:
var store = Ext.create('Ext.data.TreeStore', {
root: {
expanded: true,
children: [
{ text: "School Friends", expanded: true, children: [
{ text: "Mike", leaf: true, name: "Mike", email: "mike#stackoverflow.com", phone: "345-2222"},
{ text: "Laura", leaf: true, name: "Laura", email: "laura#stackoverflow.com", phone: "345-3333"}
] },
{ text: "Facebook Friend", expanded: true, children: [
{ text: "Steve", leaf: true, name: "Steve", email: "steve#stackoverflow.com", phone: "345-2222"},
{ text: "Lisa", leaf: true, name: "Lisa", email: "lisa#stackoverflow.com", phone: "345-3333"}
] },
]
}});
Ext.create('Ext.tree.Panel', {
title: 'All My Friends',
width: 200,
height: 150,
store: store,
rootVisible: false,
renderTo: Ext.getBody(),
listeners : {
itemdblclick : function(tree, record, index){
Ext.getStore('simpsonsStore').loadRawData([record.raw], true);
}
}});
Ext.create('Ext.data.Store', {
storeId:'simpsonsStore',
fields:['name', 'email', 'phone'],
data:{'items':[
{ 'name': 'Bart', "email":"bart#simpsons.com", "phone":"555-222-1234" },
{ 'name': 'Homer', "email":"home#simpsons.com", "phone":"555-222-1244" },
{ 'name': 'Marge', "email":"marge#simpsons.com", "phone":"555-222-1254" }
]},
proxy: {
type: 'memory',
reader: {
type: 'json',
root: 'items'
}
}});
Ext.create('Ext.grid.Panel', {
title: 'Best Friends',
store: Ext.data.StoreManager.lookup('simpsonsStore'),
columns: [
{ text: 'Name', dataIndex: 'name' },
{ text: 'Email', dataIndex: 'email', flex: 1 },
{ text: 'Phone', dataIndex: 'phone' }
],
height: 200,
width: 400,
renderTo: Ext.getBody()});
From the above code I am able to get the values from treepanel to grid panel by double clicking.
I want an extra column to group values if we double click the same leaf in the treepanel.
For example if we double click Bart 6 times
Name email phonenumber groupby(number of times)
Bart bart#simpsons.com 555-222-1234 6
It should not append same value in the grid panel.
Could any one please help me.
Regards,
sreekanth
You'll need to add a count field to your store's fields. Then, you'll need to add the field to your grid. When you double-click the tree, you'll need to check the store to see if the record already exists. If it does, change the value in the count field; otherwise, add a new row.
itemdblclick: function (tree, record, index) {
var s = Ext.getStore('simpsonsStore'),
existingRecIdx = s.findBy(function (r) {
return r.get('email') === record.raw['email'];
});
if (existingRecIdx === -1) { //row not found
record.raw.clickCt = 1;
s.loadRawData([record.raw], true);
} else {
var r = s.getAt(existingRecIdx);
r.data.clickCt++;
grid.getView().refresh(); //once the data has changed
//refresh the grid
}
}
See http://jsfiddle.net/Kk7gL/