@@ -40,7 +40,7 @@ import { LinearInterpolator, FlyToInterpolator } from 'deck.gl';
4040import { HeatmapLayer } from 'deck.gl' ;
4141import { InvertColorsOff , ShopTwoOutlined } from '@mui/icons-material' ;
4242
43- import { getCountyNodes , ExtractFirstTimeSlice , ExtractFlowData , getBarNet , getPoints , getGeneration , getLoad , getContours } from "./src/dataprocess" ;
43+ import { getCountyNodes , ExtractFirstTimeSlice , ExtractFlowData , getBarNet , getPoints , getGeneration , getLoad , getContours , getAreas , getZones } from "./src/dataprocess" ;
4444import { LineColor , FlowColor , FillColor , fillGenColumnColor , fillGenColumnColorCap , getVoltageFillColor } from "./src/color"
4545
4646import 'core-js/actual/structured-clone' ;
@@ -72,6 +72,9 @@ var data = ExtractFirstTimeSlice(geodata);
7272const countyloaddata = getCountyNodes ( data ) ;
7373data = countyloaddata . updatedata ;
7474
75+ const areas = getAreas ( casedata ) ;
76+
77+ const zones = getZones ( casedata ) ;
7578
7679const flowdata = ExtractFlowData ( data ) ;
7780
@@ -146,9 +149,15 @@ export default function App({ refdata = data, refflowdata = flowdata, ggdata = g
146149 const [ busNameSelectItems , setBusNameSelectItems ] = useState ( [ ] ) ;
147150
148151 const [ busNameItems , setbusNameItems ] = useState ( data . features
149- . filter ( f => f . geometry . type == "Point" ) . map ( ( f ) => ( f . properties . NAME ) ) ) ;
152+ . filter ( f => f . geometry . type == "Point" ) . map ( ( f ) => ( f . properties . NAME ) ) ) ;
153+
154+ const [ areaNameSelectItems , setAreaNameSelectItems ] = useState ( [ ] ) ;
150155
156+ const [ areaNameItems , setAreaNameItems ] = useState ( areas . features . map ( f => f . properties . name ) ) ;
151157
158+ const [ zoneNameSelectItems , setZoneNameSelectItems ] = useState ( [ ] ) ;
159+
160+ const [ zoneNameItems , setZoneNameItems ] = useState ( zones . features . map ( f => f . properties . name ) ) ;
152161
153162 const [ countyNameSelectItems , setCountyNameSelectItems ] = useState ( [ ] ) ;
154163
@@ -430,6 +439,54 @@ export default function App({ refdata = data, refflowdata = flowdata, ggdata = g
430439
431440 } ) ;
432441
442+ const zoomToAreaName = useCallback ( ( filterareas , minLng , minLat , maxLng , maxLat ) => {
443+ var viewport = new WebMercatorViewport ( INITIAL_VIEW_STATE ) ;
444+
445+ const { longitude, latitude, zoom } = viewport . fitBounds ( [ [ minLng , minLat ] , [ maxLng , maxLat ] ] ) ;
446+
447+ setInitialViewState ( viewState => ( {
448+ ...viewState ,
449+ latitude : latitude ,
450+ longitude : longitude ,
451+ pitch : 50 ,
452+ traansitionInterpolator : transitionFlyToInterpolator ,
453+ transitionDuration : 5000 ,
454+ zoom : 7.5 ,
455+ onTransitionEnd : activatePopup
456+ } ) )
457+
458+ var popup = { display : false , name : '' , info : '' } ; // Will be displayed after transition end only
459+ popup . name = "Area " + filterareas . properties . name ;
460+ // popup.info = "Area: " + info.object.properties.name;
461+ setShowPopup ( showPopup => ( { ...showPopup , ...popup } ) ) ;
462+
463+ } ) ;
464+
465+ const zoomToZoneName = useCallback ( ( filterzones , minLng , minLat , maxLng , maxLat ) => {
466+ var viewport = new WebMercatorViewport ( INITIAL_VIEW_STATE ) ;
467+
468+ const { longitude, latitude, zoom } = viewport . fitBounds ( [ [ minLng , minLat ] , [ maxLng , maxLat ] ] ) ;
469+
470+ setInitialViewState ( viewState => ( {
471+ ...viewState ,
472+ latitude : latitude ,
473+ longitude : longitude ,
474+ pitch : 50 ,
475+ traansitionInterpolator : transitionFlyToInterpolator ,
476+ transitionDuration : 5000 ,
477+ zoom : 7.5 ,
478+ onTransitionEnd : activatePopup
479+ } ) )
480+
481+ var popup = { display : false , name : '' , info : '' } ; // Will be displayed after transition end only
482+ popup . name = "Zone " + filterzones . properties . name ;
483+ // popup.info = "Zone: " + info.object.properties.name;
484+ setShowPopup ( showPopup => ( { ...showPopup , ...popup } ) ) ;
485+
486+ } ) ;
487+
488+
489+
433490 const zoomToCounty = useCallback ( ( info ) => {
434491 if ( ! info ) return null ;
435492
@@ -456,7 +513,73 @@ export default function App({ refdata = data, refflowdata = flowdata, ggdata = g
456513
457514 var popup = { display : false , name : '' , info : '' } ; // Will be displayed after transition end only
458515 popup . name = info . object . properties . NAME ;
459- popup . info = "Load: " + info . object . properties . Pd . toFixed ( 2 ) + "MW" ;
516+ popup . info = "Load loss: " + info . object . properties . Pd . toFixed ( 2 ) + "MW" ;
517+ setShowPopup ( showPopup => ( { ...showPopup , ...popup } ) ) ;
518+
519+
520+ }
521+ } ) ;
522+
523+ const zoomToArea = useCallback ( ( info ) => {
524+ if ( ! info ) return null ;
525+
526+ if ( info . layer . id == 'AreaLayer' ) {
527+ var layer = info . layer ;
528+ var { viewport } = layer . context ;
529+
530+ var cbounds = bbox ( info . object ) ;
531+ var c1 = [ cbounds [ 0 ] , cbounds [ 1 ] ] ;
532+ var c2 = [ cbounds [ 2 ] , cbounds [ 3 ] ] ;
533+ var areabounds = [ c1 , c2 ] ;
534+ const { longitude, latitude, zoom } = viewport . fitBounds ( areabounds ) ;
535+
536+ setInitialViewState ( viewState => ( {
537+ ...viewState ,
538+ latitude : latitude ,
539+ longitude : longitude ,
540+ pitch : 50 ,
541+ traansitionInterpolator : transitionFlyToInterpolator ,
542+ transitionDuration : 5000 ,
543+ zoom : zoom - 0.25 ,
544+ onTransitionEnd : activatePopup
545+ } ) )
546+
547+ var popup = { display : false , name : '' , info : '' } ; // Will be displayed after transition end only
548+ popup . name = "Area " + info . object . properties . name ;
549+ // popup.info = "Area: " + info.object.properties.name;
550+ setShowPopup ( showPopup => ( { ...showPopup , ...popup } ) ) ;
551+
552+
553+ }
554+ } ) ;
555+
556+ const zoomToZone = useCallback ( ( info ) => {
557+ if ( ! info ) return null ;
558+
559+ if ( info . layer . id == 'ZoneLayer' ) {
560+ var layer = info . layer ;
561+ var { viewport } = layer . context ;
562+
563+ var cbounds = bbox ( info . object ) ;
564+ var c1 = [ cbounds [ 0 ] , cbounds [ 1 ] ] ;
565+ var c2 = [ cbounds [ 2 ] , cbounds [ 3 ] ] ;
566+ var zonebounds = [ c1 , c2 ] ;
567+ const { longitude, latitude, zoom } = viewport . fitBounds ( zonebounds ) ;
568+
569+ setInitialViewState ( viewState => ( {
570+ ...viewState ,
571+ latitude : latitude ,
572+ longitude : longitude ,
573+ pitch : 50 ,
574+ traansitionInterpolator : transitionFlyToInterpolator ,
575+ transitionDuration : 5000 ,
576+ zoom : zoom - 0.25 ,
577+ onTransitionEnd : activatePopup
578+ } ) )
579+
580+ var popup = { display : false , name : '' , info : '' } ; // Will be displayed after transition end only
581+ popup . name = "Zone " + info . object . properties . name ;
582+ // popup.info = "Zone: " + info.object.properties.name;
460583 setShowPopup ( showPopup => ( { ...showPopup , ...popup } ) ) ;
461584
462585
@@ -487,10 +610,9 @@ export default function App({ refdata = data, refflowdata = flowdata, ggdata = g
487610 const [ genlayeractive , setGenLayerActive ] = useState ( false ) ;
488611 const [ genlayercapactive , setGenLayerCapActive ] = useState ( false ) ;
489612 const [ voltagelayeractive , setVoltageLayerActive ] = useState ( false ) ;
490-
491-
492-
493-
613+ const [ zonelayeractive , setZoneLayerActive ] = useState ( false ) ;
614+ const [ arealayeractive , setAreaLayerActive ] = useState ( false ) ;
615+
494616 const handleUserInput = ( inputText ) => {
495617 console . log ( `New message incoming! ${ inputText } ` ) ;
496618 // Now send the message to GPT and get response
@@ -612,6 +734,31 @@ export default function App({ refdata = data, refflowdata = flowdata, ggdata = g
612734 } ) ) )
613735 } ;
614736
737+ const handleAreaLayerChange = ( event ) => {
738+ setAreaLayerActive ( event . target . checked ) ;
739+ // setVoltageFilterValue([0.89, 1.11]);
740+
741+ event . target . checked && ( setInitialViewState ( viewState => ( {
742+ ...viewState ,
743+ pitch : 40 ,
744+ traansitionInterpolator : transitionFlyToInterpolator ,
745+ transitionDuration : 2000 ,
746+ } ) ) )
747+ } ;
748+
749+ const handleZoneLayerChange = ( event ) => {
750+ setZoneLayerActive ( event . target . checked ) ;
751+ // setVoltageFilterValue([0.89, 1.11]);
752+
753+ event . target . checked && ( setInitialViewState ( viewState => ( {
754+ ...viewState ,
755+ pitch : 40 ,
756+ traansitionInterpolator : transitionFlyToInterpolator ,
757+ transitionDuration : 2000 ,
758+ } ) ) )
759+ } ;
760+
761+
615762 const handleGenLayerChange = ( event ) => {
616763 setGenLayerActive ( event . target . checked ) ;
617764 setGenFilterValue ( [ gendata . minPg , gendata . maxPg ] ) ;
@@ -910,6 +1057,59 @@ export default function App({ refdata = data, refflowdata = flowdata, ggdata = g
9101057 }),
9111058 */
9121059
1060+
1061+ new GeoJsonLayer ( {
1062+ id : 'AreaLayer' ,
1063+ data : areas ,
1064+ pickable : arealayeractive ,
1065+ visible : arealayeractive ,
1066+ stroked : true ,
1067+ filled : true ,
1068+ extruded : true ,
1069+ wireframe : true ,
1070+ lineWidthMinPixels : 1 ,
1071+ getPolygon : d => d . geometry . coordinates ,
1072+ // getElevation: d => d.properties.Pd*5.0,
1073+ getFillColor : [ 255 , 192 , 203 ] ,
1074+ getLineColor : [ 80 , 80 , 80 ] ,
1075+ getLineWidth : d => 1 ,
1076+ opacity : 0.1 ,
1077+ onClick : zoomToArea ,
1078+ // extensions: [new DataFilterExtension({ filtersize: 1 })],
1079+ // getFilterValue: getLoadFilterValue,
1080+ // filterRange: loadfiltervalue,
1081+
1082+ // updateTriggers: {
1083+ // getFilterValue: [netfiltervalue, countyNameSelectItems]
1084+ // }
1085+ } ) ,
1086+
1087+ new GeoJsonLayer ( {
1088+ id : 'ZoneLayer' ,
1089+ data : zones ,
1090+ pickable : zonelayeractive ,
1091+ visible : zonelayeractive ,
1092+ stroked : true ,
1093+ filled : true ,
1094+ extruded : true ,
1095+ wireframe : true ,
1096+ lineWidthMinPixels : 1 ,
1097+ getPolygon : d => d . geometry . coordinates ,
1098+ // getElevation: d => d.properties.Pd*5.0,
1099+ getFillColor : [ 252 , 245 , 95 ] ,
1100+ getLineColor : [ 80 , 80 , 80 ] ,
1101+ getLineWidth : d => 1 ,
1102+ opacity : 0.1 ,
1103+ onClick : zoomToZone ,
1104+ // extensions: [new DataFilterExtension({ filtersize: 1 })],
1105+ // getFilterValue: getLoadFilterValue,
1106+ // filterRange: loadfiltervalue,
1107+
1108+ // updateTriggers: {
1109+ // getFilterValue: [netfiltervalue, countyNameSelectItems]
1110+ // }
1111+ } ) ,
1112+
9131113 new GeoJsonLayer ( {
9141114 id : 'PolygonLayerload' ,
9151115 data : countyload ,
@@ -1104,6 +1304,56 @@ export default function App({ refdata = data, refflowdata = flowdata, ggdata = g
11041304 }
11051305 }
11061306
1307+ const handleAreaMultiselect = ( selectItem , metadata ) => {
1308+
1309+ const selected = areaNameSelectItems . indexOf ( metadata . dataItem )
1310+ console . log ( selected ) ;
1311+ if ( selected >= 0 ) { //if is selected, remove
1312+ const newArray = [ ...areaNameSelectItems . slice ( 0 , selected ) , ...areaNameSelectItems . slice ( selected + 1 ) ] ;
1313+ setAreaNameSelectItems ( newArray )
1314+
1315+ } else { //add to array
1316+ setAreaNameSelectItems ( areaNameSelectItems => ( [ ...areaNameSelectItems , metadata . dataItem ] ) )
1317+ const filterareas = areas . features . filter ( area => area . properties . name === metadata . dataItem )
1318+ if ( filterareas . length > 0 ) {
1319+ const longs = filterareas [ 0 ] . geometry . coordinates [ 0 ] . map ( d => d [ 0 ] )
1320+ const lats = filterareas [ 0 ] . geometry . coordinates [ 0 ] . map ( d => d [ 1 ] )
1321+ const minLng = Math . min ( ...longs )
1322+ const maxLng = Math . max ( ...longs )
1323+ const minLat = Math . min ( ...lats )
1324+ const maxLat = Math . max ( ...lats )
1325+
1326+ zoomToAreaName ( filterareas [ 0 ] , minLng , minLat , maxLng , maxLat )
1327+ }
1328+ }
1329+ }
1330+
1331+ const handleZoneMultiselect = ( selectItem , metadata ) => {
1332+
1333+ const selected = zoneNameSelectItems . indexOf ( metadata . dataItem )
1334+ console . log ( selected ) ;
1335+ if ( selected >= 0 ) { //if is selected, remove
1336+ const newArray = [ ...zoneNameSelectItems . slice ( 0 , selected ) , ...zoneNameSelectItems . slice ( selected + 1 ) ] ;
1337+ setZoneNameSelectItems ( newArray )
1338+
1339+ } else { //add to array
1340+ setZoneNameSelectItems ( zoneNameSelectItems => ( [ ...zoneNameSelectItems , metadata . dataItem ] ) )
1341+ const filterzones = zones . features . filter ( area => area . properties . name === metadata . dataItem )
1342+ if ( filterzones . length > 0 ) {
1343+ const longs = filterzones [ 0 ] . geometry . coordinates [ 0 ] . map ( d => d [ 0 ] )
1344+ const lats = filterzones [ 0 ] . geometry . coordinates [ 0 ] . map ( d => d [ 1 ] )
1345+ const minLng = Math . min ( ...longs )
1346+ const maxLng = Math . max ( ...longs )
1347+ const minLat = Math . min ( ...lats )
1348+ const maxLat = Math . max ( ...lats )
1349+
1350+ zoomToZoneName ( filterzones [ 0 ] , minLng , minLat , maxLng , maxLat )
1351+ }
1352+ }
1353+ }
1354+
1355+
1356+
11071357 const renderItem = ( {
11081358 id,
11091359 name
@@ -1477,6 +1727,44 @@ export default function App({ refdata = data, refflowdata = flowdata, ggdata = g
14771727 </ AccordionDetails >
14781728 </ Accordion >
14791729
1730+ < Accordion defaultExpanded = { false } >
1731+ < AccordionSummary style = { { height : "20px" , minHeight : "30px" , paddingRight : "40px" , paddingLeft : "0px" } }
1732+ expandIcon = { < ArrowDropDownIcon /> } >
1733+ < Typography >
1734+ < Checkbox checked = { arealayeractive } style = { { color : "primary" } } onChange = { handleAreaLayerChange } /> Show Areas
1735+ </ Typography >
1736+ </ AccordionSummary >
1737+ < AccordionDetails >
1738+ < Typography component = "div" >
1739+ { arealayeractive && ( < div style = { { paddingRight : "40px" } } > < Multiselect
1740+ defaultValue = { areaNameSelectItems }
1741+ data = { areaNameItems }
1742+ placeholder = { 'Search for areas' }
1743+ onChange = { handleAreaMultiselect }
1744+ /> </ div > ) }
1745+ </ Typography >
1746+ </ AccordionDetails >
1747+ </ Accordion >
1748+
1749+ < Accordion defaultExpanded = { false } >
1750+ < AccordionSummary style = { { height : "20px" , minHeight : "30px" , paddingRight : "40px" , paddingLeft : "0px" } }
1751+ expandIcon = { < ArrowDropDownIcon /> } >
1752+ < Typography >
1753+ < Checkbox checked = { zonelayeractive } style = { { color : "primary" } } onChange = { handleZoneLayerChange } /> Show Zones
1754+ </ Typography >
1755+ </ AccordionSummary >
1756+ < AccordionDetails >
1757+ < Typography component = "div" >
1758+ { zonelayeractive && ( < div style = { { paddingRight : "40px" } } > < Multiselect
1759+ defaultValue = { zoneNameSelectItems }
1760+ data = { zoneNameItems }
1761+ placeholder = { 'Search for zones' }
1762+ onChange = { handleZoneMultiselect }
1763+ /> </ div > ) }
1764+ </ Typography >
1765+ </ AccordionDetails >
1766+ </ Accordion >
1767+
14801768 </ div >
14811769
14821770 { /* <br></br> */ }
0 commit comments