I’m working with Arcgis version 4.25 (javascript) and using cluster. I used the sample https://developers.arcgis.com/javascript/latest/sample-code/sandbox/?sample=featurereduction-cluster and want to show Browse Features content window on opening popup instead of showing summary.
How can I do that programmatically?
enter image description here
Basically, you have to query the layer view with the aggregatedId. The aggregated id is the objectId of the selected cluster feature.
Here I put an example for you using the esri sample you use as base. The key part, is when the CustomContent is render (the creator method).
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<title>
Point clustering - basic configuration | Sample | ArcGIS Maps SDK for
JavaScript 4.25
</title>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
background: rgba(50, 50, 50);
}
#infoDiv {
padding: 10px;
}
</style>
<link rel="stylesheet" href="https://js.arcgis.com/4.25/esri/themes/dark/main.css" />
<script src="https://js.arcgis.com/4.25/"></script>
<script>
require([
"esri/Map",
"esri/layers/FeatureLayer",
"esri/layers/GeoJSONLayer",
"esri/views/MapView",
"esri/widgets/Legend",
"esri/widgets/Expand",
"esri/widgets/Home",
"esri/popup/content/CustomContent"
], (Map, FeatureLayer, GeoJSONLayer, MapView, Legend, Expand, Home, CustomContent) => {
const layer = new GeoJSONLayer({
title: "Earthquakes from the last month",
url: "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_month.geojson",
copyright: "USGS Earthquakes",
outFields: ["*"],
popupTemplate: {
title: "Magnitude {mag} {type}",
content: "Magnitude {mag} {type} hit {place} on {time}"
},
renderer: {
type: "simple",
field: "mag",
symbol: {
type: "simple-marker",
size: 4,
color: "#69dcff",
outline: {
color: "rgba(0, 139, 174, 0.5)",
width: 5
}
}
}
});
const baseLayer = new FeatureLayer({
portalItem: {
id: "2b93b06dc0dc4e809d3c8db5cb96ba69"
},
legendEnabled: false,
popupEnabled: false,
renderer: {
type: "simple",
symbol: {
type: "simple-fill",
color: [65, 65, 65, 1],
outline: {
color: [50, 50, 50, 0.75],
width: 0.5
}
}
},
spatialReference: {
wkid: 5936
}
});
const map = new Map({
layers: [baseLayer, layer]
});
const view = new MapView({
container: "viewDiv",
extent: {
spatialReference: {
wkid: 5936
},
xmin: 1270382,
ymin: -1729511,
xmax: 2461436,
ymax: -953893
},
spatialReference: {
// WGS_1984_EPSG_Alaska_Polar_Stereographic
wkid: 5936
},
constraints: {
minScale: 15469455
},
map: map
});
view.popup.viewModel.includeDefaultActions = false;
view.whenLayerView(layer).then(lv => {
const layerView = lv;
const customContentPromise = new CustomContent({
outFields: ["*"],
creator: (event) => {
const query = layerView.createQuery();
query.aggregateIds = [event.graphic.getObjectId()];
console.log(query);
return layerView.queryFeatures(query).then(result => {
console.log(result.features);
const contentDiv = document.createElement("div");
const featuresUl = document.createElement("ul");
let featureLi;
for (const feature of result.features) {
featureLi = document.createElement("li");
featureLi.innerText = `Magnitude ${feature.attributes.mag} ${feature.attributes.type} hit ${feature.attributes.place} on ${feature.attributes.time}`;
featuresUl.appendChild(featureLi);
}
contentDiv.appendChild(featuresUl);
return contentDiv
});
}
});
const clusterConfig = {
type: "cluster",
clusterRadius: "100px",
popupTemplate: {
title: "Cluster summary",
outFields: ["*"],
content: [customContentPromise],
actions: []
},
clusterMinSize: "24px",
clusterMaxSize: "60px",
labelingInfo: [
{
deconflictionStrategy: "none",
labelExpressionInfo: {
expression: "Text($feature.cluster_count, '#,###')"
},
symbol: {
type: "text",
color: "#004a5d",
font: {
weight: "bold",
family: "Noto Sans",
size: "12px"
}
},
labelPlacement: "center-center"
}
]
};
layer.featureReduction = clusterConfig;
const toggleButton = document.getElementById("cluster");
toggleButton.addEventListener("click", () => {
let fr = layer.featureReduction;
layer.featureReduction =
fr && fr.type === "cluster" ? null : clusterConfig;
toggleButton.innerText =
toggleButton.innerText === "Enable Clustering"
? "Disable Clustering"
: "Enable Clustering";
});
});
view.ui.add(
new Home({
view: view
}),
"top-left"
);
const legend = new Legend({
view: view,
container: "legendDiv"
});
const infoDiv = document.getElementById("infoDiv");
view.ui.add(
new Expand({
view: view,
content: infoDiv,
expandIconClass: "esri-icon-layer-list",
expanded: false
}),
"top-left"
);
});
</script>
</head>
<body>
<div id="viewDiv"></div>
<div id="infoDiv" class="esri-widget">
<button id="cluster" class="esri-button">Disable Clustering</button>
<div id="legendDiv"></div>
</div>
</body>
</html>
Related
I am trying to draw graph in joint.js with tree layout , without any layout it works fine and edges responses properly ,but when changed to tree layout edges does not move with node in proper way if anyone knows how to workaround with edges in joint.js please response
var namespace = joint.shapes;
var graph = new joint.dia.Graph({}, { cellNamespace: namespace });
var graphLayout = new joint.layout.TreeLayout({
graph: graph,
parentGap: 30,
siblingGap: 40
});
var paper = new joint.dia.Paper({
el: document.getElementById('myholder'),
model: graph,
width: 600,
height: 1000,
gridSize: 10,
drawGrid: true,
background: {
color: 'rgba(0, 255, 0, 0.3)'
},
cellViewNamespace: namespace
});
var rect = new joint.shapes.standard.Rectangle();
rect.position(100, 30);
rect.resize(100, 40);
rect.attr({
body: {
fill: 'blue'
},
label: {
text: 'Hello',
fill: 'white'
}
});
rect.addTo(graph);
var rect2 = rect.clone();
rect2.translate(0, 300);
rect2.attr('label/text', 'World!');
rect2.addTo(graph);
var link = new joint.shapes.standard.Link(
{
router: {
name: "manhattan",
},
connector: {
name: "rounded",
},
attrs: {
line: {
stroke: "#25085b",
},
}
});
link.source(rect);
link.target(rect2);
link.addTo(graph);
var root = graph.getElements()[0].position(100, 100);
graphLayout.layout();
<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>
<script src="https://resources.jointjs.com/demos/rappid/build/package/rappid.js"></script>
<div id="myholder" style="width: 100%"></div>
If you are referring to the unusual curve / loop between the two nodes, you can change the router setting to metro, and that will resolve the issue.
So, instead of this:
router: {
name: "manhattan",
},
do this
router: {
name: "metro",
},
var namespace = joint.shapes;
var graph = new joint.dia.Graph({}, { cellNamespace: namespace });
var graphLayout = new joint.layout.TreeLayout({
graph: graph,
parentGap: 30,
siblingGap: 40
});
var paper = new joint.dia.Paper({
el: document.getElementById('myholder'),
model: graph,
width: 600,
height: 1000,
gridSize: 10,
drawGrid: true,
background: {
color: 'rgba(0, 255, 0, 0.3)'
},
cellViewNamespace: namespace
});
var rect = new joint.shapes.standard.Rectangle();
rect.position(100, 30);
rect.resize(100, 40);
rect.attr({
body: {
fill: 'blue'
},
label: {
text: 'Hello',
fill: 'white'
}
});
rect.addTo(graph);
var rect2 = rect.clone();
rect2.translate(0, 300);
rect2.attr('label/text', 'World!');
rect2.addTo(graph);
var link = new joint.shapes.standard.Link(
{
router: { name: 'metro' },
connector: { name: 'rounded' },
attrs: {
line: {
stroke: '#333333',
strokeWidth: 3
}
}
});
link.source(rect);
link.target(rect2);
link.addTo(graph);
var root = graph.getElements()[0].position(100, 100);
graphLayout.layout();
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jointjs/3.6.5/joint.core.min.css" integrity="sha512-BSPFEtqveOD7IH9Oka9zaaMZqy9CUW0iBgag5tZozZYfFvWH5TuVCpdie9TpZ4UEYLkkOTnq6VmppA89CgVxYg==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<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>
<script src="https://resources.jointjs.com/demos/rappid/build/package/rappid.js"></script>
<div id="myholder" style="width: 100%"></div>
How can i modify the popupTemplate in esri? is it possible for me to modify the popupTemplate according to my design?
I have a popupTemplate
popupTemplate: {
content: [{
type: "fields",
fieldInfos: [{
fieldName: "Name"
}, {
fieldName: "Owner"
}, {
fieldName: "Length"
}]
}]
}
this is the result
what i want design
resource https://totalapis.github.io/sample-code/popup-custom-action/index.html
Update, I am having trouble on my react , when i clicked the icon there is no popup template show
useEffect(() => {
if (mapDiv.current) {
esriConfig.apiKey = process.env.ARCGIS_API;
const map = new Map({
basemap: 'arcgis-light-gray'
});
const view = new MapView({
center: [123.5504, 12.3574], // Longitude, latitude
container: mapDiv.current,
map: map,
zoom: 13, // Zoom level
});
view
.when((r) => {})
.then(() => {
mapDiv.current = view;
setMapView(view);
});
var list= [{
type: "fields",
fieldInfos: [{
fieldName: "Name "
}, {
fieldName: "Owner"
}, {
fieldName: "Length"
}]
},
{
type: "text",
text: "<div class=\"icontain\"></><a class=\"ic\"><i class=\"bi bi-star\"></i></a><a class=\"ic\"><i class=\"bi bi-geo-alt-fill\"></i></a></div>"
}]
var Stack= {
content: list
}
var featureLayer = new FeatureLayer({
url: "https://services.arcgis.com/V6ZHFr6zdgNZuVG0/ArcGIS/rest/services/Beverly%20Hills%20Trees%20By%20Block/FeatureServer/0",
popupTemplate: Stack,
outFields: ["*"]
});
map.add(featureLayer);
}
}, []);
const displayLocation = (locations) => {
mapView.center = [
locations.data[0].geoCode.longitude,
locations.data[0].geoCode.latitude,
];
locations.data.map((location) => {
const point = new Graphic({
geometry: {
latitude: location.geoCode.latitude,
longitude: location.geoCode.longitude,
type: 'point',
},
symbol: LocationPin,
});
mapView.graphics.add(point);
});
};
return <div className="mapDiv layers" ref={mapDiv}></div>;
}
Hello, a quick solution to modify the Popup template is to add another object with text and text type properties to the template array. the text value will be html code where we will create a div that will show the icons, these with their respective css classes. The most is CSS. Here is an example of the Popup template:
popupTemplate: {[{
type: "fields",
fieldInfos: [{
fieldName: "Name "
}, {
fieldName: "Owner"
}, {
fieldName: "Length"
}]
},
{
type: "text",
text: "<div class=\"icontain\"></><a class=\"ic\"><i class=\"bi bi-star\"></i></a><a class=\"ic\"><i class=\"bi bi-geo-alt-fill\"></i></a></div>"
}]
}
I put an example of this code in operation already with the css, for a better compression. Your remaining task is to play with CSS to make the icon div responsive. For a better visualization of the example, run it in full screen. Another detail is that the example takes time to load due to the multiple CDNs that it needs
require([
"esri/Map",
"esri/views/MapView",
"esri/layers/FeatureLayer",
"dojo/domReady!"
], function(Map, MapView, FeatureLayer) {
// Create the Map
var map = new Map({
basemap: "streets-navigation-vector"
});
var view = new MapView({
container: "mapDiv",
map: map,
center: [-118.399400711028, 34.08713590709093],
zoom: 16,
// Since there are many elements, it is best to dock the popup so
// the elements display better rather than have to scroll through them all.
popup: {
dockEnabled: true,
dockOptions: {
buttonEnabled: false,
breakpoint: false
}
}
});
var list= [{
type: "fields",
fieldInfos: [{
fieldName: "Name "
}, {
fieldName: "Owner"
}, {
fieldName: "Length"
}]
},
{
type: "text",
text: "<div class=\"icontain\"></><a class=\"ic\"><i class=\"bi bi-star\"></i></a><a class=\"ic\"><i class=\"bi bi-geo-alt-fill\"></i></a></div>"
}]
var Stack= {
content: list
}
var featureLayer = new FeatureLayer({
url: "https://services.arcgis.com/V6ZHFr6zdgNZuVG0/ArcGIS/rest/services/Beverly%20Hills%20Trees%20By%20Block/FeatureServer/0",
popupTemplate: Stack,
outFields: ["*"]
});
map.add(featureLayer);
});
html,
body,
#mapDiv {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
.esri-popup__main-container{
border: solid 1px gray;
border-radius: 10px;
}
.icontain{
position: absolute;
top: 0;
height: 100%;
left: -17px;
display: flex;
flex-direction: column;
/* margin-top: auto; */
/* margin-bottom: auto; */
/* align-items: center; */
justify-content: center;
}
.ic{
border: solid 1px gray;
border-radius: 50%;
width: 33px;
height: 33px;
display: flex;
justify-content: center;
align-items: center;
background: white;
margin-top: 4px;
margin-bottom: 4px;
}
<!DOCTYPE html>
<html dir="ltr">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"
/><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons#1.7.2/font/bootstrap-icons.css">
<title>Multiple popup elements - 4.4</title>
<link rel="stylesheet" href="https://js.arcgis.com/4.4/esri/css/main.css">
<link rel="stylesheet" href="https://js.arcgis.com/4.4/dijit/themes/claro/claro.css">
<script src="https://js.arcgis.com/4.4/"></script></head>
<body>
<div id="mapDiv"></div>
</body>
</html>
Update
run this code in your environment. The popup should appear, you should only add the styles
useEffect(() => {
if (mapDiv.current) {
esriConfig.apiKey = process.env.ARCGIS_API_KEY;
const map = new Map({
basemap: 'arcgis-light-gray', // Basemap layer service
// portalItem:{
// id: "2d11c8164ce04843a38bfde68e00e6e7"
// }
});
const view = new MapView({
center: [123.5504, 12.3574], // Longitude, latitude
container: mapDiv.current,
map: map,
zoom: 13, // Zoom level
});
view
.when((r) => {})
.then(() => {
mapDiv.current = view;
setMapView(view);
});
}
}, []);
const displayLocation = (locations) => {
mapView.center = [
locations.data[0].geoCode.longitude,
locations.data[0].geoCode.latitude,
];
locations.data.map((location) => {
const point = new Graphic({
geometry: {
latitude: location.geoCode.latitude,
longitude: location.geoCode.longitude,
type: 'point',
},
symbol: LocationPin,
popupTemplate: {
title: "Sample",
content: [{
type: "fields",
fieldInfos: [{
fieldName: "Name"
}, {
fieldName: "Owner"
}, {
fieldName: "Length"
}]
},{
type: "text",
text: "<div class=\"icontain\"></><a class=\"ic\"><i class=\"bi bi-star\"></i></a><a class=\"ic\"><i class=\"bi bi-geo-alt-fill\"></i></a></div>"
}]
}
});
mapView.graphics.add(point);
});
};
update css for button close
.esri-popup__header-buttons{
position: absolute;
top: 100px;
margin: 0;
left: -17px;
padding: 0;
background: white;
border-radius: 50%;
border: solid 1px;
width: 32px;
height: 32px;
display: flex;
justify-content: center;
align-items: center;
}
.esri-popup__button {
z-index: 10;
}
try with this class and styles, to customize the close button
I'm having a problem with C# asp.net mvc. The line in my chart is not getting displayed. I tried many different charts but it's not working. The objective is using my database values to draw the line.
My View: Estatisticas.cshtml
#model Estágio_TP.Models.Alerta
#{
ViewBag.Title = "Estatisticas";
}
<h2>Estatisticas de #Html.DisplayFor(model => model.nomeAlerta)</h2>
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<script type="text/javascript" src="https://canvasjs.com/assets/script/jquery-1.11.1.min.js"></script>
<script type="text/javascript" src="https://canvasjs.com/assets/script/canvasjs.min.js"></script>
<title>Doughnut Chart</title>
<meta name="viewport" content="width=device-width" />
<script type="text/javascript" src="https://canvasjs.com/assets/script/jquery-1.11.1.min.js"></script>
<script type="text/javascript" src="https://canvasjs.com/assets/script/canvasjs.min.js"></script>
<title>Gráfico Chart</title>
<script src="~/Content/js/Chart_est.js"></script>
</head>
<body>
<div id="chartContainer1" style="width: 100%; height: 500px;display: inline-block;"></div>
<br /><br /><br />
<div id="chartContainer2" style="width: 100%; height: 500px;display: inline-block;"></div>
<!--<div class="card-body">
<div class="chart-area">
<canvas id="teste_est"style="width: 100%; height: 500px;display: inline-block;"></canvas>
</div>
</div>-->
<script type="text/javascript">
function chart1(){
var chart1 = new CanvasJS.Chart("chartContainer1", {
title: {
text: " #Html.DisplayFor(model => model.nomeTrigger)"
},
animationEnabled: true,
legend: {
fontSize: 20,
fontFamily: "Helvetica"
},
theme: "light2",
data: [
{
type: "doughnut",
indexLabelFontFamily: "Garamond",
indexLabelFontSize: 20,
indexLabel: "{label} {y}%",
startAngle: -20,
showInLegend: true,
toolTipContent: "{legendText} {y}%",
dataPoints: [
{ y: #ViewData["valor"], legendText: "Em Uso", label: "Em Uso"
},
{ y: 100 - #ViewData["valor"], legendText: "Livre", label: "Livre" },
],
//dataPoints: #Html.Raw(ViewBag.DataPoints),
}
]
});
chart1.render();
}
$(document).ready(function () {
showChart3();
});
function showChart3() {
$.get("/alertas/json/", function (data) {
var tempo = [];
var valor = [];
for (var i in data) {
tempo.push(data[i].tempo);
valor.push(data[i].valor);
}
var chart = new CanvasJS.Chart("chartContainer2", {
animationEnabled: true,
theme: "light2",//light1
title: {
text: "Gráfico ao Longo do Dia"
},
data: [
{
// Change type to "bar", "splineArea", "area", "spline", "pie",etc.
type: "line",
dataPoints: data
}
]
});
chart.render();
});
}
function start() {
chart1();
showChart3();
}
window.onload = start();
</script>
<!-- <script src="~/Content/js/teste_estatistica.js"></script>-->
</body>
</html>
Controller:
public ContentResult JSON(string id)
{
var teste_xx = db.Conteudos.Where(a => a.nomeAl == id)
.Where(a => a.Data_cont.Day == DateTime.Now.Day)
.OrderBy(a => a.Data_cont)
.Select(a => new
{
valor = a.max_valor,
tempo = a.Data_cont //.ToString("hh:mm")
});
List<DataPoint> dataPoints;
dataPoints = new List<DataPoint>();
foreach (var result in teste_xx)
{
//list2.Add(result.tempo.ToString());
//list2.Add(result.valor.ToString());
var tempo = result.tempo;
var valor = result.valor;
dataPoints.Add(new DataPoint(tempo, valor));
}
JsonSerializerSettings _jsonSetting = new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore };
return Content(JsonConvert.SerializeObject(dataPoints, _jsonSetting), "application/json");
}
}
DB: Only need the DateTime("hh:mm:ss") and the max_value
Database
There are many problems that they should be modified.
You import canvasjs.min.js twice... just import 1 time.
I only solve your Alertas/Json action, I have no Alertas/Estatisticas's model Estágio_TP.Models.Alerta so the page will not show chartContainer1's solution.
I modify the Json action to return JsonResult. Not ContentResult.
Your Alertas/Json should take one Id parameter, so I hard-code the parameter in the $.get("/alertas/json/1");
I assume some simple db data to show this chart will work.
Assign axisX's properties, including the time format/intervals
Assing dataPoints with x and y as keys, not your tempo and valor as keys.
My version works:
Estatisticas.cshtml
<div id="chartContainer2" style="width: 100%; height: 500px;display: inline-block;"></div>
#section scripts {
<script>
$(document).ready(function () {
showChart3();
});
function showChart3() {
$.get("/alertas/json/1", function (data) {
var dataPoints = [];
for (var i in data) {
dataPoints.push({
x: new Date(parseInt(data[i].tempo.replace("/Date(", "").replace(")/", ""), 10)),
y: data[i].valor
});
}
console.log(dataPoints);
var chart = new CanvasJS.Chart("chartContainer2", {
animationEnabled: true,
theme: "light2",
title: {
text: "Gráfico ao Longo do Dia"
},
axisX: {
interval: 10,
intervalType: "minute",
valueFormatString: "YYYY/MM/DD HH:mm"
},
data: [
{
type: "line",
dataPoints: dataPoints
}
]
});
chart.render();
});
}
</script>
}
Controller
public JsonResult JSON(string id)
{
var db = new List<Conteudos>()
{
new Conteudos()
{
Data_cont = DateTime.Now,
max_valor = 10,
nomeAl = "1"
},
new Conteudos()
{
Data_cont = DateTime.Now.AddHours(1),
max_valor = 40,
nomeAl = "1"
},
new Conteudos()
{
Data_cont = DateTime.Now.AddHours(2),
max_valor = 30,
nomeAl = "1"
},
new Conteudos()
{
Data_cont = DateTime.Now.AddHours(3),
max_valor = 50,
nomeAl = "1"
},
new Conteudos()
{
Data_cont = DateTime.Now.AddHours(4),
max_valor = 60,
nomeAl = "1"
}
};
var teste_xx = db.Where(a => a.nomeAl == id)
.Where(a => a.Data_cont.Day == DateTime.Now.Day)
.OrderBy(a => a.Data_cont)
.Select(a => new
{
valor = a.max_valor,
tempo = a.Data_cont //.ToString("hh:mm")
});
List<DataPoint> dataPoints;
dataPoints = new List<DataPoint>();
foreach (var result in teste_xx)
{
//list2.Add(result.tempo.ToString());
//list2.Add(result.valor.ToString());
var tempo = result.tempo;
var valor = result.valor;
dataPoints.Add(new DataPoint(tempo, valor));
}
return Json(dataPoints, JsonRequestBehavior.AllowGet);
}
I am using the following code to calculate the extent of as KMLfile. How do I do this with a GeoJSON file?
let layer=new KMLLayer({ url:url });
map.add(app.layer);
app.mapView.whenLayerView(layer).then(function(layerView) {
watchUtils.whenFalseOnce(layerView, "updating", function() {
let polygons=layerView.allVisiblePolygons;
let lines=layerView.allVisiblePolylines;
let points=layerView.allVisiblePoints;
let images=layerView.allVisibleMapImages;
let extent=polygons.concat(lines).concat(points).concat(images)
.map(graphic => (graphic.extent ? graphic.extent : graphic.geometry.extent))
.reduce((previous, current) => previous.union(current));
});
You just need to use queryExtent of the GeoJSONLayerView. Take a look the example I made for you based on one of ArcGIS.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="initial-scale=1,maximum-scale=1,user-scalable=no"
/>
<title>GeoJSONLayer - 4.15</title>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
p {
font: 1rem 'Fira Sans', sans-serif;
}
#extentSpan {
color:crimson;
font-style: italic;
}
</style>
<link
rel="stylesheet"
href="https://js.arcgis.com/4.15/esri/themes/light/main.css"
/>
</head>
<body>
<p>Extent: <span id="extentSpan">...</span></p>
<div id="viewDiv"></div>
<script src="https://js.arcgis.com/4.15/"></script>
<script>
require([
"esri/Map",
"esri/layers/GeoJSONLayer",
"esri/views/MapView"
], function(Map, GeoJSONLayer, MapView) {
const renderer = {
type: "simple",
field: "mag",
symbol: {
type: "simple-marker",
color: "orange",
outline: {
color: "white"
}
},
visualVariables: [
{
type: "size",
field: "mag",
stops: [
{
value: 2.5,
size: "4px"
},
{
value: 8,
size: "40px"
}
]
}
]
};
const geojsonLayer = new GeoJSONLayer({
url:
"https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_month.geojson",
copyright: "USGS Earthquakes",
renderer: renderer
});
const map = new Map({
basemap: "gray",
layers: [geojsonLayer]
});
const view = new MapView({
container: "viewDiv",
center: [-168, 46],
zoom: 3,
map: map
});
view.whenLayerView(geojsonLayer).then(function(layerView) {
layerView.watch("updating", function(val) {
if (!val) {
layerView.queryExtent().then(function(response) {
const e = response.extent;
view.goTo(e);
document.querySelector('#extentSpan').textContent =
`${e.xmin} ${e.ymin} ${e.xmax} ${e.ymax}`;
});
}
});
});
});
</script>
</body>
</html>
I've been tweaking the Floor Planner project from GoJS and I want to make my own customized item (grouped elements) in the palette area. I was able to generate an item but the elements within the group are not reacting to the node template map I've set-up as seen in the screenshot below:
What I was expecting is to have a grouped element like this:
This is how I set-up my template maps:
For the blue lines
function makeBlueLine() {
var $ = go.GraphObject.make;
return $(go.Node, "Auto",
{
contextMenu: makeContextMenu(),
selectionObjectName: "SHAPE",
selectionAdorned: false,
resizeAdornmentTemplate: makeWallPartResizeAdornment(),
locationSpot: go.Spot.Left,
toolTip: makeNodeToolTip(),
resizable: true,
resizeObjectName: "SHAPE",
rotatable: true,
doubleClick: function (e) { if (e.diagram.floorplanUI) e.diagram.floorplanUI.hideShow("selectionInfoWindow"); },
},
new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
new go.Binding("visible", "showOnPlan"),
new go.Binding("angle", "angle"),
$(go.Shape,
{ name: "SHAPE", fill: "blue", stroke: "#000", strokeWidth: 1, height: 1, figure: "Rectangle" },
new go.Binding("width", "length").makeTwoWay(),
new go.Binding("stroke", "isSelected", function (s, obj) {
return s ? "green" : "blue";
}).ofObject(),
),
);
}
For the Group
function makeLineContainer() {
var $ = go.GraphObject.make;
return $(go.Group, "Vertical",
{
//isSubGraphExpanded: false,
contextMenu: makeContextMenu(),
doubleClick: function (e) {
if (e.diagram.floorplanUI) e.diagram.floorplanUI.hideShow("selectionInfoWindow");
},
toolTip: makeGroupToolTip()
},
new go.Binding("location", "loc"),
$(go.Panel, "Auto",
$(go.Shape, "RoundedRectangle", { fill: "rgba(0,0,0,0)", stroke: null, name: 'SHAPE', strokeCap: 'square' },
new go.Binding("fill", "isSelected", function (s, obj) {
return s ? "rgba(128, 128, 128, 0.10)" : "rgba(0,0,0,0)";
}).ofObject()
),
$(go.Placeholder, { padding: 5 })
)
)
}
This is my model array set-up:
BLUE_LINE_DATA_ARRAY = [
{
category: "LineParent",
key: "Type1",
isGroup: true,
},
{
category: "BlueLine",
group: "Type1",
loc: '0 0',
angle: 90,
length: 50,
key: "G1",
},
{
category: "BlueLine",
group: "Type1",
loc: '10 10',
angle: 0,
length: 50,
key: "G2",
},
];
For the palette initialization, I haven't done any change except adding the group template map there. Here's the template mapping I've made:
this.nodeTemplateMap.add("BlueLine", makeBlueLine());
this.groupTemplateMap.add("LineParent", makeLineContainer());
I couldn't find what I'm missing. I've also checked on the macros.html sample and everything looks similar.
I just tried implementing such a sample, but I was unable to encounter any problems with groups in a Palette. Here's my code:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- Copyright 1998-2019 by Northwoods Software Corporation. -->
<script src="go.js"></script>
<script>
function init() {
var $ = go.GraphObject.make;
// initialize main Diagram
myDiagram =
$(go.Diagram, "myDiagramDiv",
{ "undoManager.isEnabled": true });
myDiagram.nodeTemplate =
$(go.Node, "Auto",
new go.Binding("location", "location", go.Point.parse).makeTwoWay(go.Point.stringify),
$(go.Shape,
{ fill: "white", stroke: "gray", strokeWidth: 2 },
new go.Binding("stroke", "color")),
$(go.TextBlock,
{ margin: 4 },
new go.Binding("text").makeTwoWay())
);
// initialize Palette
myPalette =
$(go.Palette, "myPaletteDiv",
{ nodeTemplateMap: myDiagram.nodeTemplateMap });
myPalette.model.nodeDataArray = [
{ key: 1, group: 3, text: "blue node", color: "blue", location: "30 0" },
{ key: 2, group: 3, text: "orange node", color: "orange", location: "0 40" },
{ key: 3, isGroup: true, text: "GROUP" }
];
// initialize Overview
myOverview =
$(go.Overview, "myOverviewDiv",
{ observed: myDiagram, contentAlignment: go.Spot.Center });
load();
}
// save a model to and load a model from Json text, displayed below the Diagram
function save() {
var str = myDiagram.model.toJson();
document.getElementById("mySavedModel").value = str;
}
function load() {
var str = document.getElementById("mySavedModel").value;
myDiagram.model = go.Model.fromJson(str);
}
</script>
</head>
<body onload="init()">
<div style="width: 100%; display: flex; justify-content: space-between">
<div style="display: flex; flex-direction: column; margin: 0 2px 0 0">
<div id="myPaletteDiv" style="flex-grow: 1; width: 120px; background-color: whitesmoke; border: solid 1px black"></div>
<div id="myOverviewDiv" style="margin: 2px 0 0 0; width: 120px; height: 100px; background-color: lightgray; border: solid 1px black"></div>
</div>
<div id="myDiagramDiv" style="flex-grow: 1; height: 400px; border: solid 1px black"></div>
</div>
<div id="buttons">
<button id="loadModel" onclick="load()">Load</button>
<button id="saveModel" onclick="save()">Save</button>
</div>
<textarea id="mySavedModel" style="width:100%;height:200px">
{ "class": "go.GraphLinksModel",
"nodeDataArray": [
{"key":1, "text":"hello", "color":"green", "location":"0 0"},
{"key":2, "text":"world", "color":"red", "location":"70 0"}
],
"linkDataArray": [
{"from":1, "to":2}
]}
</textarea>
</body>
</html>
Note how the group appears in the Palette, and when a copy is dropped in the main Diagram. Each of the two member nodes are located according to the binding, and they remain in that relative location, until the user moves a member node in the main diagram.
Tried to look into this some more but unfortunately, I still haven't found a definitive reason or cause of the issue. However, I did find a workaround but it will costed me the ability to have multiple palettes for the floor planner. So basically, I changed the palette constructor of the floor planner package to follow the pattern of the samples for palette found in GoJS website.
How it was declared first:
function FloorplanPalette(div, floorplan, nodeDataArray) {
go.Palette.call(this, div);
var $ = go.GraphObject.make;
this.model = $(go.GraphLinksModel, { nodeDataArray: nodeDataArray });
this.contentAlignment = go.Spot.Center;
this.nodeTemplateMap = floorplan.nodeTemplateMap;
this.groupTemplateMap = floorplan.groupTemplateMap;
this.toolManager.contextMenuTool.isEnabled = false;
// add this new FloorplanPalette to the "palettes" field of its associated Floorplan
floorplan.palettes.push(this);
} go.Diagram.inherit(FloorplanPalette, go.Palette);
My change:
function FloorplanPalette(div, floorplan, nodeDataArray) {
var $ = go.GraphObject.make;
myPalette =
$(go.Palette, div, // must name or refer to the DIV HTML element
{
nodeTemplateMap: floorplan.nodeTemplateMap,
groupTemplateMap: floorplan.groupTemplateMap,
contentAlignment: go.Spot.Center,
});
myPalette.model = new go.GraphLinksModel(nodeDataArray);
}