Experience builder custom widget

3211
5
Jump to solution
12-12-2023 07:14 AM
ErsiLover
Occasional Contributor

I'm trying to make a simple custom widget that on the button press adds a random point on the map and I'm stuck, this is how my code looks:

import React from 'react';

import { JimuMapView } from 'jimu-arcgis';
import SimpleMarkerSymbol from '@arcgis/core/symbols/SimpleMarkerSymbol';
import { AllWidgetProps } from 'jimu-core';


export interface State{
jimuMapView: JimuMapView | undefined;
}
export default class Widget extends React.PureComponent<AllWidgetProps<any>, State> {
Graphic: any;
Point: any;
GraphicsLayer: any;
constructor(props) {
super(props);
this.state = {
jimuMapView : undefined,
};
}
addPointToMap = () => {

const pointSymbol = new SimpleMarkerSymbol({
type: 'simple-marker',
style: 'square',
color: 'blue',
size: '8px',
outline: {
color: [255, 255, 0],
width: 3,
},
});
const graphicB = new this.Graphic({
geometry: new this.Point({ x: 42.34123, y: 21.12341 }),
symbol: pointSymbol
});

const layer = new this.GraphicsLayer({
graphics: [graphicB]
});


this.state.jimuMapView.view.map.add(layer);
};

render() {
return (
<div>
<button onClick={this.addPointToMap}>Add Point</button>
</div>
);
}
}

 

0 Kudos
1 Solution

Accepted Solutions
Grant-S-Carroll
Esri Contributor

There are a few issues here.

First you need to import Graphic, GraphicsLayer and Point.

import Graphic from 'esri/Graphic'
import GraphicsLayer from 'esri/layers/GraphicsLayer'
import Point from 'esri/geometry/Point'

 

Remove the declaration of Graphic, Point and GraphicsLayer at the start of your class

export default class Widget extends React.PureComponent<AllWidgetProps<any>, State> {

constructor(props) {
    super(props);
    this.state = {
      jimuMapView : undefined,
    };
}

 

Next when creating the new point and graphic, don't use the this. prefix.

 

const graphicB = new Graphic({
    geometry: new Point({ x: 42.34123, y: 21.12341 }),
    symbol: pointSymbol
});

const layer = new GraphicsLayer({
   graphics: [graphicB]
});

 

Finally, you are trying to add the graphic to the map view, but there is nowhere, where you are getting a reference to it. You need to let the widget know which map to add the graphics too. Have a look at this sample here, This shows how to create a settings page so you can assign your widget a map, then it has a handle within the render method which will get the map when it loaded and ready.

Also, you do not need to export your state interface. You only need to export something from a file if you intend to use it in other parts of your project or in an another file. Otherwise you do not need need the export statement.

 

View solution in original post

5 Replies
JeffreyThompson2
MVP Regular Contributor

Can you explain more about what problems you are having? Are you seeing any errors in the console?

I strongly recommend writing your widgets in function based React, rather than class based. Function based React is the modern style with much simpler syntax.

Here is some starter code for a function based widget that uses API components. https://community.esri.com/t5/experience-builder-tips-and-tricks/boilerplate-for-a-map-related-custo...

GIS Developer
City of Arlington, Texas
Grant-S-Carroll
Esri Contributor

There are a few issues here.

First you need to import Graphic, GraphicsLayer and Point.

import Graphic from 'esri/Graphic'
import GraphicsLayer from 'esri/layers/GraphicsLayer'
import Point from 'esri/geometry/Point'

 

Remove the declaration of Graphic, Point and GraphicsLayer at the start of your class

export default class Widget extends React.PureComponent<AllWidgetProps<any>, State> {

constructor(props) {
    super(props);
    this.state = {
      jimuMapView : undefined,
    };
}

 

Next when creating the new point and graphic, don't use the this. prefix.

 

const graphicB = new Graphic({
    geometry: new Point({ x: 42.34123, y: 21.12341 }),
    symbol: pointSymbol
});

const layer = new GraphicsLayer({
   graphics: [graphicB]
});

 

Finally, you are trying to add the graphic to the map view, but there is nowhere, where you are getting a reference to it. You need to let the widget know which map to add the graphics too. Have a look at this sample here, This shows how to create a settings page so you can assign your widget a map, then it has a handle within the render method which will get the map when it loaded and ready.

Also, you do not need to export your state interface. You only need to export something from a file if you intend to use it in other parts of your project or in an another file. Otherwise you do not need need the export statement.

 

BluntBSE
Emerging Contributor

Hi, Grant.

How do I actually add graphics to a Jimu Map View? Several tutorials on the JS Api propose something like "view.graphics.add()", but JMV.view doesn't seem to have any "graphics" property. I have something similar to the OP, but can't for the life of me figure out how to throw a graphic on top of the point generated by the handler.

0 Kudos
Grant-S-Carroll
Esri Contributor

Hi,

Without seeing the code, I suspect whats happening is that maybe you have done something like this when you set the JimuMapView.

 

activeViewChangeHandler = (jmv: JimuMapView) => {
    if (!(jmv && jmv.view)) {
        return;
    }
    this.setState({jimuMapView:jmv});
}

 

Or alternatively, you have set the view in state, eg

activeViewChangeHandler = (jmv: JimuMapView) => {
    if (!(jmv && jmv.view)) {
        return;
    }
    this.setState({jimuMapView:jmv.view});
}

In which case you have a JimuMapView in state, a JimuMapView is not the same as a MapView or a SceneView, you need to access the view property on the JimuMapView, in the example above where we set the JimuMapView in to state, it would then be, 

 

//do this.
this.state.jimuMapView.view.graphics.add(graphic);

//not this
this.state.jimuMapView.graphics.add(graphic);

 

 

Or if you have set the view in to state, then its.:

//do this.
this.state.jimuMapView.graphics.add(graphic);

//not this
this.state.jimuMapView.view.graphics.add(graphic);

 

The details of the properties on a JimuMapView are here

If you see a message saying the a property doesn't exist, then I would recommend setting a breakpoint at the point where you are trying to access the object, and inspect it using the debugging tools in the browser. See an example below, where I have a breakpoint set as the JimuMapView is being checked. In the right hand pane, under Local section, you can see the details of the JimuMapView, you can see the methods and properties it has, you can see it has a view property, but not a graphics property

GrantSCarroll_0-1703632011228.png

 

The other thing I do a lot, is log stuff to the console so I can check the values of properties that have been set or to track my progress through code, simple as:

 

console.log(this.state.jimuMapView)

 

 

This way you can check that the value expect to be there, is the value you expect. 

Hope that helps

 

BluntBSE
Emerging Contributor

Hi there, I just wanted to say thank you for your helpful response and (somewhat belatedly) let you know that I've since gotten graphics working in my application, and will refer to your post again in the future for sure.

0 Kudos