Find multiple features in a layer under mouse position arcgis onlne - arcgis

I want to see all the features in a graphicsLayer that match an x,y from a mouse. The hitTest() method works for the topmost one:
mapView.on("pointer-move", function(event) { // HANDLE HOVER
let screenPoint={ x: event.x, y: event.y };
mapView.hitTest(screenPoint).then(function(response) {
if (response.results.length) {
DO SOMETHING...
}
});
But, when I'm zoomed out, the points overlay into one. How can I know that there are others and get access to them?
Google Earth used to have a function that automatically displayed them in a circle. It would be great if arcGis has that, but I'm with doing it the hard way.

In the new version of the API, 4.x, what usually was a the GraphicLayer purpose (handling client side features) became part of FeatureLayer or other layers like GeoJSONLayer or CSVLayer.
Now, the recomendation is to use FeatureLayer,
It is generally preferred to construct a FeatureLayer with its source property when working with client-side graphics since the FeatureLayer has more capabilities than the GraphicsLayer, including rendering, querying, and labeling.
ArcGIS JavaScript API - GraphicLayer
In regard to visualization, your could use clustering on FeatureLayer.
Take a look at this example I made for you base on ArcGIS JavaScript Examples - Point clustering.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="initial-scale=1,maximum-scale=1,user-scalable=no"
/>
<title>FeatureLayer Cluster - 4.15</title>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
</style>
<link
rel="stylesheet"
href="https://js.arcgis.com/4.15/esri/themes/light/main.css"
/>
<script src="https://js.arcgis.com/4.15/"></script>
<script>
require([
"esri/Map",
"esri/views/MapView",
"esri/layers/FeatureLayer",
"esri/Graphic",
"esri/geometry/Point",
"esri/widgets/Legend",
"esri/widgets/Expand"
], function(
Map,
MapView,
FeatureLayer,
Graphic,
Point,
Legend,
Expand
) {
function getRandomNumber(min, ref) {
return Math.random() * ref + min;
}
function getGraphics() {
const graphics = [];
let location = null;
// generate random points features
let oid = 0;
for (let i = 0; i <= getRandomNumber(20, 50); i++) {
location = new Point({
latitude: getRandomNumber(10, 50),
longitude: -getRandomNumber(50, 50)
});
for (let j = 0; j <= getRandomNumber(0, 50); j++) {
graphics.push(
new Graphic({
geometry: location,
attributes: {
OBJECTID: oid,
name: `${i}-${j}`
}
})
);
oid++;
}
}
return graphics;
}
const graphics = getGraphics();
function popupTemplateContent(feature) {
const location = feature.graphic.geometry;
return `lat:${location.latitude.toFixed(2)} lon:${location.longitude.toFixed(2)}`;
}
const clusterConfig = {
type: "cluster",
clusterRadius: "100px",
popupTemplate: {
content: "{cluster_count} features."
}
};
function createLayer() {
return new FeatureLayer({
source: graphics,
objectIdField: "OBJECTID",
fields: [
{
name: "OBJECTID",
type: "oid"
},
{
name: "name",
type: "string"
}
],
featureReduction: clusterConfig,
popupTemplate: {
title: '{name}',
content: popupTemplateContent
},
renderer: {
type: "simple",
field: "mag",
symbol: {
type: "simple-marker",
size: 4,
color: "#fc3232",
outline: {
color: [50, 50, 50]
}
}
}
});
}
const layer = createLayer();
const view = new MapView({
map: new Map({
basemap: "gray-vector"
}),
container: "viewDiv",
zoom: 2,
center: [-75, 35]
});
view
.when()
.then(addLayerToView)
.catch(function(e) {
console.error("Creating FeatureLayer failed", e);
});
function addLayerToView() {
view.map.add(layer);
}
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: true
}),
"top-left"
);
const toggleButton = document.getElementById("cluster");
toggleButton.addEventListener("click", function() {
const fr = layer.featureReduction;
layer.featureReduction =
fr && fr.type === "cluster" ? null : clusterConfig;
toggleButton.innerText =
toggleButton.innerText === "Enable Clustering"
? "Disable Clustering"
: "Enable Clustering";
});
});
</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>
In the example, when you select if clustering is on it will show how many features there are, and if clustering is off you will get all features.

Related

arcgis goTo feature and open popup

I am new to Arcgis maps and using ArcGIS Javascript 4.2 library. Currently the features are showing up on the map and I am trying to go to feature and open it's popup programmatically. below is my code to query the features which is working fine.
var query = layer.createQuery();
query.where = "key= " + dataItem.key+ "";
query.returnGeometry = true;
query.returnCentroid = true;
query.returnQueryGeometry = true;
layer.queryFeatures(query).then(function (results) {
//I am getting the feature results here.
//trying to navigate to feature and open popup
});
Note: I tried using the following code from documentation which is working fine but I don't have the center as the features are polylines in my case.
view.goTo({center: [-126, 49]})
First, View goTo method has several options, including just using a geometry wich I think would be a better option for your case, zoom to a polyline.
Second to open the popup you just need to use the open method and you can pass there the features to show.
Check this example I put for you, has both suggestions,
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">
<title>ArcGIS API for JavaScript Hello World App</title>
<style>
html,
body {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
#selectDiv {
height: 30px;
width: 100%;
margin: 5px;
}
#cableNameSelect {
height: 30px;
width: 300px;
}
#cableGoToButton {
height: 30px;
width: 100px;
}
#viewDiv {
height: 500px;
width: 100%;
}
</style>
<link rel="stylesheet" href="https://js.arcgis.com/4.15/esri/css/main.css">
</head>
<body>
<div id="selectDiv">
<select id="cableNameSelect"></select>
<button id="cableGoToButton">GO TO</button>
</div>
<div id="viewDiv">
</div>
<script src="https://js.arcgis.com/4.15/"></script>
<script>
require([
'esri/Map',
'esri/views/MapView',
'esri/layers/FeatureLayer'
], function (Map, MapView, FeatureLayer) {
const cableNameSelect = document.getElementById("cableNameSelect");
const cableGoToButton = document.getElementById("cableGoToButton");
const map = new Map({
basemap: 'hybrid'
});
const view = new MapView({
container: 'viewDiv',
map: map,
zoom: 10,
center: {
latitude: 47.4452,
longitude: -121.4234
}
});
view.popup.set("dockOptions", {
buttonEnabled: false,
position: "top-right"
});
const layer = new FeatureLayer({
url: "https://services.arcgis.com/V6ZHFr6zdgNZuVG0/ArcGIS/rest/services/cables/FeatureServer/0",
popupTemplate: {
title: "{NAME}",
outFields: ["*"],
content: [{
type: 'fields',
fieldInfos: [
{
fieldName: "length"
},
{
fieldName: "owners"
},
{
fieldName: "rfs"
}
]
}],
}
});
map.add(layer);
layer.queryFeatures({
where: "1=1",
outFields: ["Name"],
returnGeometry: false
}).then(function(results) {
for(const graphic of results.features) {
cableNameSelect.appendChild(new Option(graphic.attributes.Name, graphic.attributes.Name));
}
});
cableGoToButton.onclick = function() {
if (!cableNameSelect.value) {
return;
}
cableGoToButton.disabled = true;
layer.queryFeatures({
where: `Name='${cableNameSelect.value}'`,
outFields: ["*"],
returnGeometry: true
}).then(function (results) {
cableGoToButton.disabled = false;
if (!results.features) {
return;
}
view.goTo(results.features[0].geometry);
view.popup.open({
features: [results.features[0]]
})
})
};
});
</script>
</body>
</html>

ESRI ArcGIS: Pan and Zoom to fit markers

I am new to ESRI ArcGIS. We are considering as a replacement for Google Maps. In this post https://www.esri.com/arcgis-blog/products/js-api-arcgis/announcements/migrating-from-google-maps-javascript-api-to-arcgis-api-for-javascript/ they explain how easy it should be to migrate to ArcGIS, but it seems like beyond the examples they provide, I am stuck.
I loaded a bunch of markers in a map. I am trying to have the map pan and zoom to fit all markers, and I have been unable to find any code that does that.
On Google Maps I'd do something like this:
myMap.options.center = new google.maps.LatLng(0,0);
myMap.options.mapTypeId = google.maps.MapTypeId[myMap.options.mapTypeId];
myMap.bounds = new google.maps.LatLngBounds();
myMap.map = new google.maps.Map(document.getElementById('cat-map'), myMap.options);
google.maps.event.addListenerOnce(myMap.map, 'bounds_changed', function(event){
myMap.map.fitBounds(myMap.bounds);
myMap.map.panToBounds(myMap.bounds);
});
for (var i = 0; i < myMap.items.length; i++) {
var itemLatlng = new google.maps.LatLng(myMap.items[i].lat, myMap.items[i].lng);
myMap.bounds.extend(itemLatlng);
new google.maps.Marker({
position: itemLatlng,
map: myMap.map,
});
}
But I have been unable to find the equivalent on ESRI ArcGIS.
Anyone has some guidance?
You have the right idea. In ArcGIS API Extent class has union method that extend the caller to include the geometry extent pass as parameter. Because you are using Point you can't use union method, Point extent is null. But no worries you can achieve this just iterating the graphics and extending the extent yourself.
Look at this example I made for you using as base the link of your question,
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">
<title>ArcGIS API for JavaScript Hello World App</title>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
#zoomBtn {
margin: .5rem;
}
</style>
<link rel="stylesheet" href="https://js.arcgis.com/4.15/esri/css/main.css">
<script src="https://js.arcgis.com/4.15/"></script>
<script>
require([
"esri/Map",
"esri/views/MapView",
'esri/geometry/Extent'
], function (Map, MapView, Extent) {
const map = new Map({
basemap: "streets-navigation-vector"
});
const view = new MapView({
container: "viewDiv",
map: map,
zoom: 12,
center: {
latitude: 32.7353,
longitude: -117.1490
}
});
function popupContent (feature) {
const div = document.createElement("div");
div.innerHTML = `Address: ${feature.graphic.attributes.addrs} <br>` +
`<a href='${feature.graphic.attributes.url}'>Web</a>`;
return div;
}
function toGraphic(color, lon, lat, title, addrs, url) {
return {
symbol: {
type: "text",
color,
text: "\ue61d",
font: {
size: 30,
family: "CalciteWebCoreIcons"
}
},
geometry: {
type: "point",
longitude: lon,
latitude: lat
},
attributes: {
title,
addrs,
url
},
popupTemplate: {
title: '{title}',
outfields: ['*'],
content: popupContent
}
}
}
const graphics = [
toGraphic(
'gray',
-117.1560632,
32.727482,
'Automotive Museum',
'2080 Pan American Plaza, San Diego, CA 92101, United States',
'http://sdautomuseum.org/'
),
toGraphic(
'gray',
-117.1763293,
32.7136902,
'USS Midway Museum',
'910 N Harbor Dr, San Diego, CA 92101, United States',
'http://www.midway.org/'
),
toGraphic(
'blue',
-117.2284536,
32.7641112,
'SeaWorld',
'500 Sea World Dr, San Diego, CA 92109, United States',
'https://seaworld.com/san-diego'
),
toGraphic(
'green',
-117.1557741,
32.7360032,
'Zoo',
'2920 Zoo Dr, San Diego, CA 92101, United States',
'https://zoo.sandiegozoo.org/'
)
];
view.graphics.addMany(graphics);
function maxExtent(graphics) {
const e = graphics
.map(g => g.geometry)
.reduce(
(acc, geom) => (
{
xmin: Math.min(acc.xmin, geom.longitude),
ymin: Math.min(acc.ymin, geom.latitude),
xmax: Math.max(acc.xmax, geom.longitude),
ymax: Math.max(acc.ymax, geom.latitude)
}
),
{
xmin: Number.MAX_SAFE_INTEGER,
ymin: Number.MAX_SAFE_INTEGER,
xmax: Number.MIN_SAFE_INTEGER,
ymax: Number.MIN_SAFE_INTEGER
}
);
return new Extent(e);
}
document.getElementById('zoomBtn')
.addEventListener(
'click',
_ => {
const ext = maxExtent(graphics);
console.log(`View Extent: ${JSON.stringify(view.extent)} Graphics Extent:${JSON.stringify(ext)}`);
view.extent = ext.expand(2); // expand a little so border points shows
}
);
});
</script>
</head>
<body>
<div class="esri-widget">
<button id="zoomBtn" class="esri-button">Zoom To Graphics</button>
</div>
<div id="viewDiv"></div>
</body>
</html>

ArcGIS Javascript API 4.14 popup field attributes not showing

I am using webamp to show the map created in ArcGIS (Javascript API in PHP website). In the map, a popup also appears when clicking on the layer's points. Recently I have updated the version 4.14 from 4.13. After updating it, the popup is not working properly. I have a custom popup template. After research in the documentation, I came to know there required a return function to show the custom div on the popup. The below code I have added to show my custom popups.
var template = { content: function(){ var div = document.createElement("div"); div.className = "myClass"; div.innerHTML = "<span>My custom content!</span>"; return div; } }
layers[layerIndex].popupTemplate = template;
Now the popup appears fine. But I have to show the field values on the popup. I have used the required field attributes in double brackets eg: {Name}. But in the latest version, the field values are not appearing when I used the same.
The code I have used in version 4.13 and it was working,
popupTemplate = {
title: "{Name}",
content: '<div id="popup_address">{Address}</div><div class="right"><div href="#" id="popupRight" class="toggle"><p onClick="openPopupDetails({FACILITYID})">+</p></div></div>' };
layers[layerIndex].popupTemplate = popupTemplate;
Please help me to fix this issue.
Thanks.
The complete code for the Webmap and custom popup
map.js
// The map classes and includ1a65d527bfd04cc180c87edf0908907bes
require([
"esri/views/MapView",
"esri/WebMap",
"esri/widgets/Search",
"esri/widgets/Zoom",
"esri/widgets/Locate"
], function(MapView, WebMap, Search, Zoom, Locate) {
var webmap = new WebMap({
portalItem: {
id: "d1ca798d8c7d4afab8983d911df8326b"
}
});
var view = new MapView({
map: webmap,
container: "map",
center: [-95.9406, 41.26],
zoom: 16,
maxZoom: 21,
minZoom: 13,
basemap: "topo",
ui: {
components: ["attribution"]
}
});
webmap
.load()
.then(function() {
return webmap.basemap.load();
})
.then(function() {
let allLayers = webmap.allLayers;
console.log(allLayers);
var promises = allLayers.map(function(layer) {
return layer.load();
});
return Promise.all(promises.toArray());
})
.then(function(layers) {
// Position of the popup in relation to the selected feature.
view.popup.alignment = "top-center";
// To disable the collapse functionality
view.popup.collapseEnabled = false;
// A spinner appear at the pointer
view.popup.spinnerEnabled = false;
// To disable the dock (The popup will be appear in bottom or any corner of the window)
view.popup.dockEnabled = false;
// Disable the pagination
view.popup.featureNavigationEnabled = false;
// Popup template details, Keep only name and address in the popup and avoid all other details
view.popup.viewModel.actions.getItemAt(0).visible = false;
// view.on("click", function(event) {
// keep a delay to align the popup and the pointer together positioned to the map center
// Add animation only if the browser not IE
// });
layers.forEach(function(popupLayers, layerIndex) {
console.log(popupLayers);
var template = {
title: "{Name}",
content: function() {
var div = document.createElement("div");
div.className = "myClass";
div.innerHTML = "<span>{Address}</span>";
return div;
}
};
layers[layerIndex].popupTemplate = template;
// popupTemplate = {
// title: "{Name}",
// content:
// '<div id="popup_address">{Address}</div><div class="right"><div href="#" id="popupRight" class="toggle"><p onClick="openPopupDetails({FACILITYID})">+</p></div></div>'
// };
// layers[layerIndex].popupTemplate = popupTemplate;
});
// To close the popup when hit on esc button
document.onkeyup = function(evt) {
var key = evt.keyCode;
if (key == 27) {
view.popup.close();
}
};
})
.catch(function(error) {
// console.log(error);
});
});
Index.php
<html>
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="initial-scale=1,maximum-scale=1,user-scalable=no"
/>
<title>Load a basic WebMap - 4.14</title>
<style>
html,
body,
#map {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
</style>
<link
rel="stylesheet"
href="https://js.arcgis.com/4.14/esri/themes/light/main.css"
/>
<script src="https://js.arcgis.com/4.14/"></script>
<script src="map.js"></script>
</head>
<body>
<div id="map"></div>
</body>
</html>
I have modified the code,
for (let i = 2; i < layers.length; i++) {
var template = {
title: "{Name}",
content: function() {
var div = document.createElement("div");
div.innerHTML =
'<div id="popup_address">{Address}</div><div class="right"><div href="#" id="popupRight" class="toggle"><p onClick="openPopupDetails({FACILITYID})">+</p></div></div>';
return div;
}
};
layers[i].popupTemplate = template;
console.log(layer[i]);
}
When I apply custom div, the {Address} part is not rendering. It appears like {Address} itself.
I think you are a bit confuse, you still can use a string, or you can use a function for the content of the popup template. So if you want to use a function, you can use something like this,
popupTemplate = {
title: "{Name}",
content: popupContentChange
}
layers[layerIndex].popupTemplate = template;
function popupContentChange(feature) {
let div = document.createElement("div");
div.className = "myClass";
div.innerHTML = "<span>"+feature.graphic.attributes.Address+"</span>";
return div;
}
There are several examples in the API documentation, take a look there. Just to reference one, ArcGIS JavaScript API Examples - Intro to Popups
Here an example I made for you taking your code as base adding some fixes to display what you want.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="initial-scale=1,maximum-scale=1,user-scalable=no"
/>
<title>Sketch Feature Coords</title>
<link
rel="stylesheet"
href="https://js.arcgis.com/4.14/esri/themes/light/main.css"
/>
<script src="https://js.arcgis.com/4.14/"></script>
<style>
html,
body,
#map {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
</style>
<script>
require([
"esri/views/MapView",
"esri/WebMap",
"esri/widgets/Search",
"esri/widgets/Zoom",
"esri/widgets/Locate"
], function(MapView, WebMap, Search, Zoom, Locate) {
var webmap = new WebMap({
portalItem: {
id: "d1ca798d8c7d4afab8983d911df8326b"
}
});
var view = new MapView({
map: webmap,
container: "map",
center: [-95.9406, 41.26],
zoom: 16,
maxZoom: 21,
minZoom: 13,
basemap: "topo",
ui: {
components: ["attribution"]
}
});
webmap
.load()
.then(function() {
return webmap.basemap.load();
})
.then(function() {
let allLayers = webmap.allLayers;
console.log(allLayers);
var promises = allLayers.map(function(layer) {
return layer.load();
});
return Promise.all(promises.toArray());
})
.then(function(layers) {
// Position of the popup in relation to the selected feature.
view.popup.alignment = "top-center";
// To disable the collapse functionality
view.popup.collapseEnabled = false;
// A spinner appear at the pointer
view.popup.spinnerEnabled = false;
// To disable the dock (The popup will be appear in bottom or any corner of the window)
view.popup.dockEnabled = false;
// Disable the pagination
view.popup.featureNavigationEnabled = false;
// Popup template details, Keep only name and address in the popup and avoid all other details
view.popup.viewModel.actions.getItemAt(0).visible = false;
// it is only going to work on the last two layers
// those are the one that have fields: Name and Address
for (let i = 2; i < layers.length; i++) {
var template = {
title: "{Name}",
content: "<span>Address: {Address}</span>"
};
layers[i].popupTemplate = template;
console.log(layer[i]);
}
// To close the popup when hit on esc button
document.onkeyup = function(evt) {
var key = evt.keyCode;
if (key == 27) {
view.popup.close();
}
};
})
.catch(function(error) {
console.log(error);
});
});
</script>
</head>
<body>
<div id="map"></div>
</body>
</html>
If you want to use a function as content, you have to set the outFields parameter to include the fields you want to use in the function. The selected feature is pass as a parameter to the function, and inside you use feature.graphic.attributes to access the attributes. This should work,
var template = {
title: "{Name}",
// content: "<span>Address: {Address}</span>"
content: function(feature) {
console.log(feature);
var div = document.createElement("div");
div.className = "myClass";
div.innerHTML = "<span>Address:"+feature.graphic.attributes.Address+"</span>";
return div;
},
outFields: ["Name", "Address"]
};
featureNavigationEnabled is deprecated as of version 4.15. Use Popup.visibleElements.featureNavigation instead.
https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Popup.html#featureNavigationEnabled

chart to pdf using echarts and jspdf

I’ve created a graph with echarts and want to include it to a pdf by using jspdf. I found that one way to do so might be to use canvas, transfer the graph to an image and finally include the image to the pdf. However, I fail to transfer the graph to an image. Here comes the code:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<title>Balken</title>
<script src="echarts.js"></script>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.3.4/jspdf.debug.js"></script>
<div id="body">
<div id="chart"></div>
</div>
<!-- prepare a DOM container with width and height -->
<div id="main" style="width: 750px; height: 500px"></div>
<script type="text/javascript">
// based on prepared DOM, initialize echarts instance
var myChart = echarts.init(document.getElementById('main'));
// specify chart configuration item and data
var option = {
color: ['#3398DB'],
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: [
{
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
axisTick: {
alignWithLabel: true
}
}
],
yAxis: [
{
type: 'value'
}
],
series: [
{
name: 'Salami',
type: 'bar',
barWidth: '60%',
data: [10, 52, 200, 334, 390, 330, 220]
}
]
};
// use configuration item and data specified to show chart
myChart.setOption(option);
var canvas = document.getElementById('main');
var dataURL = canvas.toDataURL();
//console.log(dataURL);
$('#exportButton').click(function () {
var pdf = new jsPDF();
pdf.addImage(dataURL, 'JPEG', 0, 0);
pdf.save('download.pdf');
});
</script>
<button id="exportButton" type="button">Export as PDF</button>
</body>
</html>
Any suggestions?
I needed this as well for a commercial product, so I did not give up until I found the solution.
You cannot use the ID of the chart to get the URL for the image, instead you need to search for the canvas.
($('canvas')[0]).toDataURL("image/png");
Notice the "[0]" means it will give your the first canvas, if you have more charts just do:
($('canvas')[0]).toDataURL("image/png");
($('canvas')[1]).toDataURL("image/png");
($('canvas')[2]).toDataURL("image/png");
3 Hours of searching and testing well spent :)
Enjoy!
I would use the toolbox, save as image:
.....
toolbox: {
feature: {
saveAsImage : {show: true}
}
}
.....
This option, among all the existing ones, will show you an icon to save the graphic as an image.
Quedaria así:
enter image description here
For more options with toolbox: http://echarts.baidu.com/echarts2/doc/option-en.html#title~toolbox
I hope it helps you.
You have to import "html2canvas" in order to make this work.
Html2canvas library will get the snapshot and that image should be written to the pdf with jspdf.
I have created a pen for this.
$("#exportButton").click(function(){
html2canvas($("#main"), {
onrendered: function(canvas) {
var dataURL=canvas.toDataURL('image/jpeg');
var pdf = new jsPDF();
pdf.addImage(dataURL, 'JPEG', 0, 0);
pdf.save("download.pdf");
}
});
});
Echart code:
<ReactEcharts
ref={(e) => {
this.echarts_react = e;
}}
option={option}
notMerge
lazyUpdate
/>
Function:
saveAsImage = (uri, name = 'undefine.jpeg') => {
var link = document.createElement('a');
link.download = name;
link.href = uri;
document.body.appendChild(link);
link.click();
};
saveAsPDF = (uri, name = 'undefine.pdf') => {
let height = echartsInstance.getHeight();
let width = echartsInstance.getWidth();
var doc = '';
if (width > height) {
doc = new jsPDF('l', 'mm', [width, height]);
} else {
doc = new jsPDF('p', 'mm', [height, width]);
}
doc.addImage(echartsInstance.getDataURL({ backgroundColor: '#fff' }), 'JPEG', 10, 10);
doc.save(name);
};
function call:
<li className="nav-item inline dropdown">
<span className="nav-link" data-toggle="dropdown">
<i className="fa fa-download" />
</span>
<div className="dropdown-menu dropdown-menu-scale pull-right">
<span
className="dropdown-item"
onClick={() =>
this.saveAsImage(this.echarts_react.getEchartsInstance().getDataURL({ backgroundColor: '#fff' }))
}>
Save as Image
</span>
<span
className="dropdown-item"
onClick={() =>
this.saveAsPDF(this.echarts_react.getEchartsInstance().getDataURL({ backgroundColor: '#fff' }))
}>
Save as PDF
</span>
</div>
</li>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.2.61/jspdf.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.5.0-beta1/html2canvas.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.5.0-beta1/html2canvas.svg.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/amstockchart/3.13.0/exporting/rgbcolor.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/canvg/1.5/canvg.min.js"></script>
<script type="text/javascript">
// $("#list1").on("click",function(){
$("#list1").click(function(){
$("#row").html(option);
var imgData;
var svgElements = $("#row").find('svg');
//replace all svgs with a temp canvas
svgElements.each(function() {
var canvas, xml;
// canvg doesn't cope very well with em font sizes so find the calculated size in pixels and replace it in the element.
$.each($(this).find('[style*=em]'), function(index, el) {
$(this).css('font-size', getStyle(el, 'font-size'));
});
canvas = document.createElement("canvas");
canvas.className = "screenShotTempCanvas";
//convert SVG into a XML string
xml = (new XMLSerializer()).serializeToString(this);
// Removing the name space as IE throws an error
xml = xml.replace(/xmlns=\"http:\/\/www\.w3\.org\/2000\/svg\"/, '');
//draw the SVG onto a canvas
canvg(canvas, xml);
$(canvas).insertAfter(this);
//hide the SVG element
////this.className = "tempHide";
$(this).attr('class', 'tempHide');
$(this).hide();
});
/* html2canvas($("#row"), {
onrendered: function(canvas) {
var imgData = canvas.toDataURL(
'image/png');
var doc = new jsPDF('p', 'mm');
doc.addImage(imgData, 'PNG', 10, 10);
doc.save('sample-file.pdf');
}
});*/
var imgData;
html2canvas($("#row"), {
useCORS: true,
'allowTaint': true,
onrendered: function (canvas) {
imgData = canvas.toDataURL(
'image/jpeg', 1.0);
canvaswidth1=canvas.width/2;
canvasheight1=canvas.height/4;
currentHeight = $("#row").height();
currentHeight2=currentHeight/2;
var imgWidth = 200;
var pageHeight = 260;
var imgHeight = canvas.height * imgWidth / canvas.width;
var heightLeft = imgHeight;
var doc = new jsPDF('p', 'm`enter code here`m','a4');
var position = 35;
doc.setFillColor(52,73,94);
doc.rect(5, 5, 200, 25, "F");
doc.setFontSize(40);
doc.setTextColor(255, 255, 255);
doc.text(80, 23, "Fitview");
doc.addImage(imgData, 'JPEG', 5, position, imgWidth, imgHeight);
heightLeft -= pageHeight;
while (heightLeft >= 0) {
position = heightLeft - imgHeight;
doc.addPage();
doc.addImage(imgData, 'JPEG', 5, position, imgWidth, imgHeight);
heightLeft -= pageHeight;
}
doc.save('healthcheck_Rapportage.pdf');
location.reload();
}
});
$("#row").find('.screenShotTempCanvas').remove();
$("#row").find('.tempHide').show().removeClass('tempHide');
});
</script>

cytoscape js event when all elements rendered?

Is there an event emitted when cy.add(elements) is finished? It appears there's an event fired for each element added, but I don't see an event when all elements have been added and rendered.
ex:
var elements = [ { data: {id: 'n1'} }, { data: {id: 'n2'} }, { data: {id: 'n3'} }, ];
cy.add(elements);
cy.on('add',function(evt){
console.log('Element Added')
})
The log will run three times.
Update I refactored per your comment. This will allow you to detect and do something after each "batch" is added.
I started with an example from the cytoscape.js website and heavily edited it for this answer.
You will probably want to run the snippet full screen to see the canvas and the console at the same time.
// For generating new IDs
var ids = [];
function newId() {
if (!ids.length) {
ids.push('1');
} else {
var id = '' + (parseInt(ids[ids.length - 1]) + 1);
ids.push(id);
}
return ids[ids.length - 1];
}
// Draw for first time
var cy = cytoscape({
container: document.getElementById('cy'),
elements: [], // don't add elements initially
style: [{
selector: 'node',
style: {
'background-color': '#666',
'label': 'data(id)',
'width': 10,
'height': 10
}
}, {
selector: 'edge',
style: {
'width': 3,
'line-color': '#ccc',
'target-arrow-color': '#ccc',
'target-arrow-shape': 'triangle'
}
}],
layout: {
name: 'grid',
rows: 1
}
});
var batchTotal = 0;
var totalAdded = 0;
// Start listening to events
cy.on('add', function(evt) {
console.log('event heard: add');
if (totalAdded < batchTotal) {
totalAdded++;
}
console.log('totalAdded/batchTotal: ', totalAdded + '/' + batchTotal);
if (totalAdded == batchTotal) {
console.log('entire batch added');
// do whatever you want!
}
});
var xStart = 10;
var x = xStart;
var y = 40;
var xInc = 20;
var yInc = 30;
var max = 200;
var addTotal = 2;
// For adding new elements
function add() {
// let's build multiple elements to add at once
var elements = [];
var id;
var el;
for (var i = 0; i < addTotal; i++) {
id = newId();
el = {
data: {
id: id
},
position: {
x: x,
y: y
}
};
elements.push(el);
if (x <= max) {
x += xInc;
} else {
x = xStart;
y += yInc;
}
}
addElements(elements);
}
// wrap the cy.add() method
// so we can inject our total counter
function addElements (elements) {
if (!Array.isArray(elements)) elements = [elements]; // convert to array
// this would be useful in a more robust app where
// addTotal may change
batchTotal = elements.length;
// reset
totalAdded = 0;
cy.add(elements);
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>CytoscapeJS Example</title>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/2.7.0/cytoscape.js"></script>
<style type="text/css">
#cy {
width: 300px;
height: 300px;
display: block;
}
</style>
</head>
<body>
<button onclick="add()">Add</button>
<p>Click add and watch the console. Look for the <strong>entire batch added</strong> message.</p>
<div id="cy"></div>
<script type="text/javascript" src="js/app.js"></script>
</body>
</html>