DataTables image (or at least image title) export to PDF - pdf

Using DataTables and Buttons (NOT TableTools, which is retired) extension. Some cells have progressbars and small icons. Is there a way to export these images (or at least their titles) to PDF? Found some possible hacks on this page, but all of them were for retired TableTools.
Checked https://datatables.net/reference/button/pdf and https://datatables.net/reference/api/buttons.exportData%28%29 but couldn't find any method to achieve this goal. Tested by adding this code:
stripHtml: false
but whole HTML code (like img src=...) was included in PDF file instead of images.
If exporting images isn't possible, is there a way to export at least alt or title attribute of each image? That would be enough.

I assume you are using pdfHtml5. dataTables is using pdfmake in order to export pdf files. When pdfmake is used from within a browser it needs images to be defined as base64 encoded dataurls.
Example : You have rendered a <img src="myglyph.png"> in the first column of some of the rows - those glyphs should be included in the PDF. First create an Image reference to the glyph :
var myGlyph = new Image();
myGlyph.src = 'myglyph.png';
In your customize function you must now
1) build a dictionary with all images that should be included in the PDF
2) replace text nodes with image nodes to reference images
buttons : [
{
extend : 'pdfHtml5',
customize: function(doc) {
//ensure doc.images exists
doc.images = doc.images || {};
//build dictionary
doc.images['myGlyph'] = getBase64Image(myGlyph);
//..add more images[xyz]=anotherDataUrl here
//when the content is <img src="myglyph.png">
//remove the text node and insert an image node
for (var i=1;i<doc.content[1].table.body.length;i++) {
if (doc.content[1].table.body[i][0].text == '<img src="myglyph.png">') {
delete doc.content[1].table.body[i][0].text;
doc.content[1].table.body[i][0].image = 'myGlyph';
}
}
},
exportOptions : {
stripHtml: false
}
}
Here is a an example of a getBase64Image function
function getBase64Image(img) {
var canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
return canvas.toDataURL("image/png");
}
If you just want to show the title of images in the PDF - or in any other way want to manipulate the text content of the PDF - then it is a little bit easier. The content of each column in each row can be formatted through the exportOptions.format.body callback :
buttons : [
{
extend : 'pdfHtml5',
exportOptions : {
stripHtml: false
format: {
body: function(data, col, row) {
var isImg = ~data.toLowerCase().indexOf('img') ? $(data).is('img') : false;
if (isImg) {
return $(data).attr('title');
}
return data;
}
}
}
]
The reason format.body cannot be used along with images is that is only let us pass data back to the text node part of the PDF document.
See also
http://pdfmake.org/#/gettingstarted (look for Images section)
https://github.com/bpampuch/pdfmake/blob/master/examples/images.js

Since no suggestions received, I had to make a hack in order to get PDF file formatted the way I want.
In case someone has the same issue, you can use hidden span to display image alt/title near image itself. I'm sure it's not the best practice, but it will do the trick. So the code will look like:
<img src='image.png' alt='some_title'/><span class='hidden'>some_title</span>
This way datatables will show only the image, while PDF file will contain text you need.

This is my CODE!
HTML
<div class="dt-btn"></div>
<table>
<thead><tr><th>No</th><th>IMAGE</th><th>NOTE</th></tr></thead>
<tbody>
<tr>
<td>{{$NO}}</td>
<td>{{$imgSRC}}</td>
<td>{{$NAME}}<br />
{{$GRADE}}<br />
{{$PROFILE}}<br />
{{$CODE}}<br />
</td>
</tr>
</tbody>
</table>
JAVASCRIPT
$.extend( true, $.fn.dataTable.defaults, {
buttons: [{
text: '<i class="bx bx-download font-medium-1"></i><span class="align-middle ml-25">Download PDF</span>',
className: 'btn btn-light-secondary mb-1 mx-1 dnPDF',
extend: 'pdfHtml5',
pageSize: 'A4',
styles: {
fullWidth: { fontSize: 11, bold: true, alignment: 'left', margin: [0,0,0,0] }
},
action: function ( e, dt, node, config ) {
var that = this;
setTimeout( function () {
$.fn.dataTable.ext.buttons.pdfHtml5.action.call(that, e, dt, node, config);
$( ".donePDF" ).remove();
$( ".dnPDF" ).prop("disabled", false);
}, 50);
},
customize: function(doc) {
doc.defaultStyle.fontSize = 11;
doc.defaultStyle.alignment = 'left';
doc.content[1].table.dontBreakRows = true;
if (doc) {
for (var i = 1; i < doc.content[1].table.body.length; i++) {
// 1st Column - display IMAGE
var imgtext = doc.content[1].table.body[i][0].text;
delete doc.content[1].table.body[i][0].text;
jQuery.ajax({
type: "GET",
dataType: "json",
url: "{{route('base64')}}",
data: { src: imgtext },
async: false,
success: function(resp) {
//console.log(resp.data);
doc.content[1].table.body[i][0] = {
margin: [0, 0, 0, 3],
alignment: 'center',
image: resp.data,
width: 80,
height: 136
};
}
});
// 2nd Column - display NOTE(4 line)
var bodyhtml = doc.content[1].table.body[i][1].text;
var bodytext = bodyhtml.split("\n");
var bodystyle = []
for (var j = 0; j < bodytext.length; j++) {
switch(j) {
case 0:
// NAME
var _text = { margin:[0, 0, 0, 3], color:"#000000", fillColor:'#ffffff', bold:true, fontSize:13, alignment:'center', text:bodytext[j] };
break;
case 1:
// GRADE
var _text = { margin:[0, 0, 0, 3], color:"blue", fillColor:'#ffffff', bold:false, fontSize:11, alignment:'left', text:bodytext[j] };
break;
case 3:
// CODE
var _text = { margin:[0, 0, 0, 3], color:"#000000", fillColor:'#ffffff', bold:true, fontSize:11, alignment:'left', text:bodytext[j] };
break;
default:
// OTHERS
var _text = { margin:[0, 0, 0, 3], color:"#000000", fillColor:'#ffffff', bold:false, fontSize:11, alignment:'left', text:bodytext[j] };
break;
}
bodystyle[j] = _text;
};
doc.content[1].table.body[i][1] = bodystyle;
}
}
},
exportOptions: {
columns: [ 1, 2 ],
stripNewlines: false,
stripHtml: true,
modifier: {
page: 'all' // 'all', 'current'
},
}
}],
columns: [
{ className: 'iNo', orderable: true, visible: true},
{ className: 'iIMG', orderable: false, visible: false },
{ className: 'iPDF', orderable: false, visible: false, responsivePriority: 10001 } ]
});
var table = $('#table').DataTable();
table.buttons().container().appendTo('.dt-btn');
$('.dnPDF').on('click', function(){
$(this).append('<span class="spinner-border spinner-border-sm donePDF" role="status" aria-hidden="true"></span>').closest('button').attr('disabled','disabled');
});
$.fn.dataTable.Buttons.defaults.dom.container.className = '';
$.fn.dataTable.Buttons.defaults.dom.button.className = 'btn';
PHP
public function base64(Request $request)
{
$request->validate([
'src' => 'required|string'
]);
$fTYPE = pathinfo($request->src, PATHINFO_EXTENSION);
$fDATA = #file_get_contents($request->src);
$imgDATA = base64_encode($fDATA);
$imgSRC = 'data:image/' . $fTYPE . ';base64,'.$imgDATA;
$error = ($imgDATA!='') ? 0 : 1;
$msg = ($error) ? 'Error' : 'Success';
return response()->json([ 'msg' => $msg, 'error'=> $error, 'data' => $imgSRC]);
}
[Sample][1]: https://i.stack.imgur.com/35Wlm.jpg

In addition to davidkonrad's answer. I created dynamically all base64 images and used them in Datatables pdfmake like this:
for (var i = 1; i < doc.content[2].table.body.length; i++) {
if (doc.content[2].table.body[i][1].text.indexOf('<img src=') !== -1) {
html = doc.content[2].table.body[i][1].text;
var regex = /<img.*?src=['"](.*?)['"]/;
var src = regex.exec(html)[1];
var tempImage = new Image();
tempImage.src = src;
doc.images[src] = getBase64Image(tempImage)
delete doc.content[2].table.body[i][1].text;
doc.content[2].table.body[i][1].image = src;
doc.content[2].table.body[i][1].fit = [50, 50];
}
//here i am removing the html links so that i can use stripHtml: true,
if (doc.content[2].table.body[i][2].text.indexOf('<a href="details.php?') !== -1) {
html = $.parseHTML(doc.content[2].table.body[i][2].text);
delete doc.content[2].table.body[i][1].text;
doc.content[2].table.body[i][2].text = html[0].innerHTML;
}
}

Related

How to get value for selected place in particular area when draw polyline or polygon through Javascript ArcGIS Api from TileLayer?

Actually I am using ArcGIS API for JavaScript 4.7 and i have a custom internal layer . I want to get name of place particular area when draw polyline the column name is (PLC_NAME) . How to achieve that ?
Suppose I draw a area through polyline. In this area there are places . Now I need to get name of these places .
you can find the using code in below i am using the TileLayer.
require([
"esri/views/MapView",
"esri/Map",
"esri/Basemap",
"esri/layers/TileLayer",
"esri/layers/MapImageLayer",
"esri/widgets/Sketch/SketchViewModel",
"esri/geometry/geometryEngine",
"esri/widgets/CoordinateConversion",
"esri/geometry/support/webMercatorUtils",
"esri/Graphic",
"esri/layers/GraphicsLayer",
"esri/config",
"esri/core/urlUtils",
"esri/widgets/Search",
"esri/tasks/Locator",
"esri/layers/FeatureLayer",
"esri/widgets/Expand",
"dojo/domReady!"
], function (
MapView, Map, Basemap, TileLayer, MapImageLayer,
SketchViewModel,
geometryEngine,
CoordinateConversion,
webMercatorUtils,
Graphic, GraphicsLayer, esriConfig, urlUtils,Search,Locator,FeatureLayer,Expand
) {
esriConfig.request.proxyUrl = "xxxxxxxxxxxxxxx";
urlUtils.addProxyRule({
urlPrefix: "xxxxxxxxxxxxxxxxxxx",
proxyUrl: "xxxxxxxxxxxxxxxxxx"
});
var tempGraphicsLayer = new GraphicsLayer();
var saveGraphicsLayer = new GraphicsLayer();
var updateGraphic;
let highlight = null;
'xxxxxxxxxxxxxxxxxxxxxxxxx';
var myMap;
var layer = new TileLayer({
url: mapUrl
});
var towerLayer = new MapImageLayer({
url: 'xxxxxxxxxxxxxxxxxxxxxxx'
});
myMap = new Map({
layers: [layer, tempGraphicsLayer, saveGraphicsLayer]
});
myMap.add(towerLayer);
view = new MapView({
center: [-55.1683665, 39.951817],
container: "viewDiv",
map: myMap,
zoom: 14
});
var ccWidget = new CoordinateConversion({
view: view
});
// Adds the search widget below other elements in
// the top left corner of the view
view.ui.add(searchWidget, {
position: "top-right",
index: 1
});
view.ui.add(ccWidget, "bottom-left");
view.ui.add("topbar", "top-right");
var pointSymbol = { // symbol used for points
type: "simple-marker", // autocasts as new SimpleMarkerSymbol()
style: "square",
color: "#8A2BE2",
size: "16px",
outline: { // autocasts as new SimpleLineSymbol()
color: [255, 255, 255],
width: 3 // points
}
}
var polylineSymbol = { // symbol used for polylines
type: "simple-line", // autocasts as new SimpleLineSymbol()
color: "#8A2BE2",
width: "4",
style: "dash"
}
var polygonSymbol = { // symbol used for polygons
type: "simple-fill", // autocasts as new SimpleFillSymbol()
color: "rgba(138,43,226, 0.8)",
style: "solid",
outline: {
color: "white",
width: 1
}
}
var polygonBoundrySymbol = { // symbol used for polygons
type: "simple-line", // autocasts as new SimpleFillSymbol()
color: "red"
}
// ################## U R HERE ################## ################## U R HERE ##################
################## U R HERE ##################
let drawBoundry = function(){
//let boundryJson = '&G_GEO_LIMITS.';
let boundryJson = $v('P0_USER_LIMITS');
if(boundryJson){
// let boundry = Graphic.fromJSON(JSON.parse('&G_GEO_LIMITS.'));
let boundry = Graphic.fromJSON(JSON.parse(boundryJson));
boundry.symbol = polygonBoundrySymbol;
tempGraphicsLayer.add(boundry);
return boundry;
}
}
/*
let boundry = drawBoundry();
*/
view.when(function () {
$('.esri-view-root').on('click', '.esri-print__export-button', function(e){
//console.log('event bubbling', e);
//console.log('event bubbling this', this);
e.preventDefault();
saveExportedImg();
});
// create a new sketch view model
var sketchViewModel = new SketchViewModel({
view: view,
layer: tempGraphicsLayer,
pointSymbol: pointSymbol,
polylineSymbol: polylineSymbol,
polygonSymbol: polygonSymbol
});
//setUpClickHandler();
// ************************************************************
// Get the completed graphic from the event and add it to view.
// This event fires when user presses
// * "C" key to finish sketching point, polygon or polyline.
// * Double-clicks to finish sketching polyline or polygon.
// * Clicks to finish sketching a point geometry.
// ***********************************************************
sketchViewModel.on("draw-complete", addGraphic);
sketchViewModel.on("update-complete", addGraphic);
sketchViewModel.on("update-cancel", addGraphic);
sketchViewModel.on("vertex-add", addGraphic);
function addGraphic(evt) {
// console.log ('graphic.geometry',evt.geometry)
//let currentGraphic = popActiveGraphic(tempGraphicsLayer);
let currentGraphic = saveGraphicsLayer.graphics.items.pop();
var geometry = evt.geometry;
var vertices = evt.vertices;
var symbol;
var attr = {
Name: "Selected Area",
X: $v('P24_X'),
Y: $v('P24_Y')
};
// Choose a valid symbol based on return geometry
switch (geometry.type) {
case "point":
symbol = pointSymbol;
break;
case "polyline":
symbol = polylineSymbol;
break;
default:
symbol = polygonSymbol;
break;
}
// Create a new graphic; add it to the GraphicsLayer
// console.log("b4 graphic");
geometry = webMercatorUtils.webMercatorToGeographic(geometry)
/*if(boundry){
var contains = geometryEngine.contains(boundry.geometry, geometry);
var within = geometryEngine.within(geometry, boundry.geometry);
} else {*/
var within = true;
//}
if(within){
let graphic = new Graphic({
geometry: geometry,
symbol: symbol,
//attributes: attr,
popupTemplate: {
title: "{Name}",
content: [{
type: "fields",
fieldInfos: [{
fieldName: "X"
}, {
fieldName: "Y"
}]
}]
}
});
tempGraphicsLayer.add(graphic);
if(currentGraphic){
//currentGraphic.geometry.rings.push(geometry.rings[0]);
geometry.rings.forEach( ring => currentGraphic.geometry.addRing(ring));
//currentGraphic.geometry.addRing(geometry.rings);
//console.log('current active', geometry);
// console.log('current graphic', currentGraphic.geometry);
graphic = currentGraphic;
}
var saveObj = graphic.toJSON();
// console.log('saveObj', saveObj);
$x('P24_JSON').value = JSON.stringify(saveObj);
} else {
apex.message.alert('&G_MAP_BOUNDRY_MSG.');
}
updateGraphic = null;
}
function addMultiGraph(evt1) {
//let currentGraphic = popActiveGraphic(tempGraphicsLayer);
let currentGraphic = saveGraphicsLayer.graphics.items.pop();
var geometry = evt1.geometry;
var vertices = evt1.vertices;
var symbol;
// Choose a valid symbol based on return geometry
switch (geometry.type) {
case "point":
symbol = pointSymbol;
break;
case "polyline":
symbol = polylineSymbol;
break;
default:
symbol = polygonSymbol;
break;
}
//console.log("ring",geometry.rings )
let graphic = new Graphic({
geometry: geometry,
symbol: symbol,
//attributes: attr,
popupTemplate: {
title: "{Name}",
content: [{
type: "fields",
fieldInfos: [{
fieldName: "X"
}, {
fieldName: "Y"
}]
}]
}
});
tempGraphicsLayer.add(graphic);
if(currentGraphic){
geometry.rings.forEach( ring => currentGraphic.geometry.addRing(ring));
}
var saveObj1 = graphic.toJSON();
//console.log('saveObj', graphic);
$x('P24_JSON').value = JSON.stringify(saveObj1);
updateGraphic = null;
}
window.loadGraphic = function(polygon){
if(polygon===undefined || polygon === ''){
console.error('no polygon');
} else {
var graphic = Graphic.fromJSON(JSON.parse(polygon));
if (graphic.geometry){
addMultiGraph(graphic);
//*********************************************************************
view.center.longitude = graphic.geometry.centroid.longitude;
view.center.latitude = graphic.geometry.centroid.latitude;
view.center = [graphic.geometry.centroid.longitude,
graphic.geometry.centroid.latitude];
view.zoom = 12;
}
}
}
// *************************************
// activate the sketch to create a point
// *************************************
var drawPointButton = document.getElementById("pointButton");
drawPointButton.onclick = function () {
// set the sketch to create a point geometry
sketchViewModel.create("point");
setActiveButton(this);
};
// ****************************************
// activate the sketch to create a polyline
// ****************************************
var drawLineButton = document.getElementById("polylineButton");
drawLineButton.onclick = function () {
// set the sketch to create a polyline geometry
sketchViewModel.create("polyline");
setActiveButton(this);
};
var drawPolygonButton = document.getElementById("polygonButton");
drawPolygonButton.onclick = function () {
// set the sketch to create a polygon geometry
sketchViewModel.create("polygon");
setActiveButton(this);
};
// ***************************************
// activate the sketch to create a rectangle
// ***************************************
var drawRectangleButton = document.getElementById(
"rectangleButton");
drawRectangleButton.onclick = function () {
// set the sketch to create a polygon geometry
sketchViewModel.create("rectangle");
setActiveButton(this);
};
document.getElementById("resetBtn").onclick = function () {
sketchViewModel.reset();
tempGraphicsLayer.removeAll();
saveGraphicsLayer.removeAll();
setActiveButton();
drawBoundry();
};
function setActiveButton(selectedButton) {
// focus the view to activate keyboard shortcuts for sketching
view.focus();
var elements = document.getElementsByClassName("active");
for (var i = 0; i < elements.length; i++) {
elements[i].classList.remove("active");
}
if (selectedButton) {
selectedButton.classList.add("active");
}
}
// ************************************************************************************
// set up logic to handle geometry update and reflect the update on "tempGraphicsLayer"
// ************************************************************************************
function setUpClickHandler() {
view.on("click", function (evt) {
view.hitTest(evt).then(function (response) {
var results = response.results;
// Found a valid graphic
if (results.length && results[results.length - 1]
.graphic) {
// Check if we're already editing a graphic
if (!updateGraphic) {
// Save a reference to the graphic we intend to update
updateGraphic = results[results.length - 1].graphic;
// Remove the graphic from the GraphicsLayer
// Sketch will handle displaying the graphic while being updated
tempGraphicsLayer.remove(updateGraphic);
sketchViewModel.update(updateGraphic.geometry);
}
}
});
});
}
function errorCallback(error) {
console.log('error:', error);
}
// ************************************************************************************
// returns graphic object if drawn on the map to contcat new graphics to it
// ************************************************************************************
function popActiveGraphic(graphicsLayer){
let length = graphicsLayer.graphics.length;
let count = 0;
if($v('P0_USER_LIMITS').length > 0){
count++;
}
if(length > count){ //active drawing detected
let result = graphicsLayer.graphics.items[length-1];
graphicsLayer.remove(result);
return result;
}
}
});
});
OK, you can resolve the queries on the client or on the server. Depends on your task what options you can pick on.
If you are going to use a spatial query, like the one you mention, and you will apply it on a FeatureLayer, you could solve it on the client. This is a good solution because you already have the features, you are seeing them. Here you have a question whis this situation, how-to-get-get-name-of-hospital-or-street-in-particular-area-when-draw-polyline.
Now, If you need to query something that might not be in your extent (you don't have the features) or you are not using a FeatureLayer, you probably will need to command the server to do this. But don't worry the library has several tools to work with, like QueryTask.
Here you have the same example of the answer link before but using QueryTask.
<html>
<head>
<meta charset='utf-8'>
<meta name='viewport' content='initial-scale=1, maximum-scale=1, user-scalable=no'>
<title>Select Feature With Polygon</title>
<style>
html,
body {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
#viewDiv {
padding: 0;
margin: 0;
height: 400px;
width: 100%;
}
#namesDiv {
margin: 10px;
height: 200px;
width: 100%;
font-style: italic;
font-weight: bold;
font-family: Arial, Helvetica, sans-serif;
font-size: 16px;
color: green;
overflow: auto;
}
</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/layers/MapImageLayer',
'esri/layers/GraphicsLayer',
'esri/widgets/Sketch/SketchViewModel',
'esri/Graphic',
'esri/widgets/Expand',
'esri/tasks/QueryTask',
'esri/tasks/support/Query'
], function (
Map,
MapView,
MapImageLayer,
GraphicsLayer,
SketchViewModel,
Graphic,
Expand,
QueryTask,
Query
) {
let highlight = null;
const states = new MapImageLayer({
url: 'https://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer'
});
const queryTask = new QueryTask({
url: 'https://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer/2'
});
const polygonGraphicsLayer = new GraphicsLayer();
const selected = new GraphicsLayer();
const map = new Map({
basemap: 'streets',
layers: [states, polygonGraphicsLayer, selected]
});
const view = new MapView({
container: 'viewDiv',
map: map,
center: [-75.1683665, 39.951817],
zoom: 8
});
const sketchViewModel = new SketchViewModel({
view: view,
layer: polygonGraphicsLayer,
pointSymbol: {
type: 'simple-marker',
color: [255, 255, 255, 0],
size: '1px',
outline: {
color: 'gray',
width: 0
}
}
});
sketchViewModel.on('create', function (event) {
if (event.state === 'complete') {
polygonGraphicsLayer.remove(event.graphic);
selectFeatures(event.graphic.geometry);
}
});
const namesDiv = document.getElementById('namesDiv');
view.ui.add('select-by-polygon', 'top-left');
const selectButton = document.getElementById('select-by-polygon');
selectButton.addEventListener('click', function () {
clearUpSelection();
sketchViewModel.create('polygon');
});
function selectFeatures(geometry) {
selected.removeAll();
const query = new Query();
query.returnGeometry = true;
query.outFields = ['*'];
query.geometry = geometry;
queryTask
.execute(query)
.then(function (results) {
const graphics = results.features.map(r => {
r.symbol = {
type: 'simple-fill',
fill: 'none',
outline: {
color: 'cyan',
width: 2
}
};
return r;
});
selected.addMany(graphics);
namesDiv.innerHTML = graphics.map(g => g.attributes.NAME).join(',');
})
.catch(errorCallback);
}
function clearUpSelection() {
selected.removeAll();
namesDiv.innerHTML = null;
}
function errorCallback(error) {
console.log('error:', error);
}
});
</script>
</head>
<body>
<div id='viewDiv'>
<div
id="select-by-polygon"
class="esri-widget esri-widget--button esri-widget esri-interactive"
title="Select counties by polygon"
>
<span class="esri-icon-checkbox-unchecked"></span>
</div>
</div>
<div id="namesDiv"></div>
</body>
</html>
To close I leave you this link to the documentation that explains very well all the possibilities, pros and cons.

Multiple renderer in esri map

I have requirement which is using classbreakrenderer for showing clusters size as it breaks down, now i want to use one renderer which shows different different symbol for single cluster based on some attribute value.
I have tried to use UniqueValueRenderer but it not working.
Any suggestion
I have requirement which is using classbreakrenderer for showing clusters size as it breaks down, now i want to use one renderer which shows different different symbol for single cluster based on some attribute value.
I have tried to use UniqueValueRenderer but it not working.
I have requirement which is using classbreakrenderer for showing clusters size as it breaks down, now i want to use one renderer which shows different different symbol for single cluster based on some attribute value.
I have tried to use UniqueValueRenderer but it not working.
<script type="text/javascript">
window.dojoConfig = {
async: true,
packages: [
{
name: 'app',
location: window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/')) + '/src'
}
]};
</script>
<!-- ArcGIS API for JavaScript library references -->
<script src="https://js.arcgis.com/3.15compact"></script>
<script>
require(["esri/map",
"esri/dijit/Geocoder",
"esri/dijit/HomeButton",
"esri/renderers/SimpleRenderer",
"esri/symbols/PictureMarkerSymbol",
"esri/layers/FeatureLayer",
"esri/InfoTemplate",
"esri/graphic",
"esri/graphicsUtils",
"app/clusterfeaturelayer",
"esri/symbols/SimpleMarkerSymbol",
"esri/symbols/SimpleLineSymbol",
"esri/symbols/SimpleFillSymbol",
"esri/symbols/PictureMarkerSymbol",
"esri/renderers/ClassBreaksRenderer",
"esri/renderers/HeatmapRenderer",
"esri/renderers/UniqueValueRenderer",
"dojo/_base/Color",
"dojo/on",
"dojo/dom-style",
"dojo/_base/fx",
"dojo/fx/easing",
"dojo/dom",
"dojo/domReady!"],
function (Map, Geocoder, HomeButton, SimpleRenderer, PictureMarkerSymbol, FeatureLayer, UniqueValueRenderer, InfoTemplate, Graphic, graphicsUtils, ClusterFeatureLayer, SimpleMarkerSymbol, SimpleLineSymbol, SimpleFillSymbol, PictureMarkerSymbol, ClassBreaksRenderer, HeatmapRenderer, Color, on, domStyle, fx, easing, dom) {
// Locals
var map,
popup,
clusterLayer,
geocoder,
infoTemplate,
defaultSym,
selectedSym,
activeClusterElement;
// Create map
map = new Map("mapDiv", {
basemap: "dark-gray",
center: [-120, 50],
zoom: 3
});
// Create widget
geocoder = new Geocoder({
value: "California, United States",
autoNavigate: true,
maxLocations: 25,
autoComplete: true,
arcgisGeocoder: {
outFields: "Place_addr, PlaceName, Score"
},
map: map
}, "search");
geocoder.startup();
var home = new HomeButton({
map: map
}, "homeButton");
home.startup();
// Add raw points
// var featureLayer = new FeatureLayer("http://services.arcgis.com/oKgs2tbjK6zwTdvi/arcgis/rest/services/Major_World_Cities/FeatureServer/0", {
// infoTemplate: infoTemplate,
// outFields: ["*"]
// });
// map.addLayer(featureLayer);
// Add heatmap
// var featureLayer2 = new FeatureLayer("http://services.arcgis.com/oKgs2tbjK6zwTdvi/arcgis/rest/services/Major_World_Cities/FeatureServer/0");
// var heatmapRenderer = new HeatmapRenderer();
// featureLayer2.setRenderer(heatmapRenderer);
// map.addLayer(featureLayer2);
// Add clusters
map.on("load", function () {
// Add layer
addClusterLayer();
addClusterLayerEvents();
});
// Set popup
popup = map.infoWindow;
popup.highlight = false;
popup.titleInBody = false;
popup.domNode.className += " light";
//popup.domNode.style.marginTop = "-17px"; // for pins only
// Popup content
//infoTemplate = new InfoTemplate("Seismic Activity > 4.0", "<p>Location: ${NAME}</p><p>Magnitude: ${OTHER_MAG1}</p><p>Date: ${YEAR}/${MONTH}/${DAY}</p>");
infoTemplate = new InfoTemplate("<b>${CITY_NAME}</b>", "<p>COUNTRY: ${CNTRY_NAME}</p><p>STATE/PROVINCE: ${ADMIN_NAME}</p><p>POPULATION: ${POP}</p>");
// Option 1: Esri marker for single locations and selections
// defaultSym = new createPictureSymbol("./images/blue-cluster-pin.png", 0, 8, 9, 16);
// selectedSym = new createPictureSymbol("./images/blue-cluster-pin.png", 0, 9, 11, 20);
// Option 2: Use circle markers for symbols - Red
defaultSym = new SimpleMarkerSymbol("circle", 16,
new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([102,0,0, 0.55]), 3),
new Color([255, 255, 255, 1]));
selectedSym = new SimpleMarkerSymbol("circle", 16,
new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([102,0,0, 0.85]), 3),
new Color([255, 255, 255, 1]));
// Create a feature layer to get feature service
function addClusterLayer() {
var renderer,
renderer1,
small,
medium,
large,
xlarge;
// Add cluster renderer
clusterLayer = new ClusterFeatureLayer({
"url": "http://services.arcgis.com/P3ePLMYs2RVChkJx/arcgis/rest/services/World_Cities/FeatureServer/0",
//"url": "http://services.arcgis.com/BG6nSlhZSAWtExvp/arcgis/rest/services/GlobalSeismographyNetwork/FeatureServer/0",
// "url": "http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/Earthquakes/Since_1970/MapServer/0",
"distance": 95,
"id": "clusters",
"labelColor": "#fff",
"resolution": map.extent.getWidth() / map.width,
//"singleColor": "#888",
"singleSymbol": defaultSym,
"singleTemplate": infoTemplate,
"useDefaultSymbol": false,
"zoomOnClick": false,
"showSingles": true,
"objectIdField": "FID",
outFields: ["*"]
});
renderer = new ClassBreaksRenderer(defaultSym, "clusterCount");
// Red Clusters
small = new SimpleMarkerSymbol("circle", 25,
new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([212,116,60,0.5]), 15),
new Color([212,116,60,0.75]));
medium = new SimpleMarkerSymbol("circle", 50,
new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([178,70,37,0.5]), 15),
new Color([178,70,37,0.75]));
large = new SimpleMarkerSymbol("circle", 80,
new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([144,24,13,0.5]), 15),
new Color([144,24,13,0.75]));
xlarge = new SimpleMarkerSymbol("circle", 110,
new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([102,0,0,0.5]), 15),
new Color([102,0,0,0.75]));
// Break values - can adjust easily
renderer.addBreak(2, 50, small);
renderer.addBreak(50, 250, medium);
renderer.addBreak(250, 1000, large);
renderer.addBreak(1000, 50000, xlarge);
// Providing a ClassBreakRenderer is also optional
clusterLayer.setRenderer(renderer);
//added second renderer
var renderer1 = new UniqueValueRenderer(defaultSymbol, "CNTRY_NAME");
//add symbol for each possible value
renderer1.addValue("United States", new PictureMarkerSymbol({
"angle": 0,
"xoffset": 0,
"yoffset": 8,
"type": "esriPMS",
"url": "./images/blue-pin.png",
"contentType": "image/png",
"width": 24,
"height": 24
}));
renderer1.addValue("Argentina", new PictureMarkerSymbol({
"angle": 0,
"xoffset": 0,
"yoffset": 12,
"type": "esriPMS",
"url": "./images/blue-cluster-pin.png",
"contentType": "image/png",
"width": 24,
"height": 24
}));
//added to cluster
clusterLayer.setRenderer(renderer1);
map.addLayer(clusterLayer);
}
// Create png marker
// function createPictureSymbol(url, xOffset, yOffset, xWidth, yHeight) {
// return new PictureMarkerSymbol(
// {
// "angle": 0,
// "xoffset": xOffset,
// "yoffset": yOffset,
// "type": "esriPMS",
// "url": url,
// "contentType": "image/png",
// "width": xWidth,
// "height": yHeight
// }
// );
// }
// Create new graphic and add to map.graphics
function addSelectedFeature() {
var selIndex = map.infoWindow.selectedIndex,
selFeature;
if (selIndex !== -1) {
selFeature = map.infoWindow.features[selIndex];
// Remove old feature first
removeSelectedFeature();
// Add new graphic
map.infoWindow._lastSelected = new Graphic(selFeature.toJson());
map.infoWindow._lastSelected.setSymbol(selectedSym);
map.graphics.add(map.infoWindow._lastSelected);
}
}
// Remove graphic from map.graphics
function removeSelectedFeature() {
if (map.infoWindow._lastSelected) {
map.graphics.remove(map.infoWindow._lastSelected);
map.infoWindow._lastSelected = null;
}
}
// Highlight clusters
function setActiveClusterOpacity(elem, fillOpacity, strokeOpacity) {
var textElm;
if (elem) {
elem.setAttribute("fill-opacity", fillOpacity);
elem.setAttribute("stroke-opacity", strokeOpacity);
// Overide inherited properties for the text in the circle
textElm = elem.nextElementSibling;
if (textElm && textElm.nodeName === "text") {
textElm.setAttribute("fill-opacity", 1);
}
}
}
// Hide popup if selected feature is clustered
function onClustersShown(clusters) {
var i = 0,
extent;
if (map.infoWindow.isShowing && map.infoWindow._lastSelected) {
for (i; i < clusters.length; i++) {
if (clusters[i].attributes.clusterCount > 1) {
extent = clusterLayer._getClusterExtent(clusters[i]);
if (extent.contains(map.infoWindow._lastSelected.geometry)) {
map.infoWindow.hide();
break;
}
}
}
}
}
// Wire cluster layer events
function addClusterLayerEvents() {
// Mouse over events
clusterLayer.on("mouse-over", onMouseOverCluster);
clusterLayer.on("mouse-out", onMouseOutCluster);
// Clusters drawn
clusterLayer.on("clusters-shown", onClustersShown);
}
// Save the last selected graphic so we can highlight it
map.infoWindow.on("selection-change", function () {
addSelectedFeature();
animateInfoWindow();
});
// Clear selected graphic when infoWindow is hidden
map.infoWindow.on("hide", function () {
// re-activate cluster
setActiveClusterOpacity(activeClusterElement, 0.75, 0.5);
removeSelectedFeature();
});
// Popup enhancements
function onMouseOverCluster(e) {
if (e.graphic.attributes.clusterCount === 1) {
e.graphic._graphicsLayer.onClick(e);
} else {
if (e.target.nodeName === "circle") {
activeClusterElement = e.target;
setActiveClusterOpacity(activeClusterElement, 1, 1);
} else {
setActiveClusterOpacity(activeClusterElement, 1, 1);
}
}
}
function onMouseOutCluster(e) {
if (e.graphic.attributes.clusterCount > 1) {
if (e.target.nodeName === "circle" || e.target.nodeName === "text") {
setActiveClusterOpacity(activeClusterElement, 0.75, 0.5);
setActiveClusterOpacity(e.target, 0.75, 0.5);
}
}
}
function animateInfoWindow() {
domStyle.set(map.infoWindow.domNode, "opacity", 0);
fx.fadeIn({node: map.infoWindow.domNode,
duration: 150,
easing: easing.quadIn}).play();
}
// Click to close
map.on('click', function () {
if (map.infoWindow.isShowing) {
map.infoWindow.hide();
}
});
// ESC is pressed
map.on('key-down', function (e) {
if (e.keyCode === 27) {
map.infoWindow.hide();
}
});
// Dynamically reposition popups when map moves
map.on('extent-change', function () {
if (map.infoWindow.isShowing) {
map.infoWindow.reposition();
}
});
// Auto recenter map - optional
autoRecenter(map);
function autoRecenter(map) {
on(map, 'load', function (map) {
on(window, 'resize', map, map.resize);
});
on(map, 'resize', function(extent, width, height) {
map.__resizeCenter = map.extent.getCenter();
setTimeout(function() {
map.centerAt(map.__resizeCenter);
}, 100);
});
}
});
</script>
</head>
<body>
<div id="mapDiv"></div>
<div id="search"></div>
<div id="homeButton"></div>
</body>
</html>

data is shown on chartjs-vue only after resizing browser or opening developer tools

im having hard time fixing this problem.
i get my data with a get request, after opening developer tools or resizing browser the data is shown.
i have tried some delay or timeout solutions but sadly could not make it work. i need the fastest solution, even if it is a "dirty hack" sort of solution.
im using vue 2.9.1 and chartjs-vue 2.7.1.
thank you!
this is my code:
import {Line} from 'vue-chartjs'
export default {
name: 'Events',
extends: Line,
created: function () {
this.getEvents();
},
data () {
return {
gradient: null,
gradient2: null,
datesList : [],
avgList: []
}
},
methods:{
graphClickEvent(event, array){
var points = this.getElementAtEvent(event)
},
getEvents () {
this.$http.get('http://localhost:8081/users/getAllEvents'
,{headers: {'Content-Type': 'application/json',
'Authorization': localStorage.getItem('token'),}
}).then((res) => {
// res.body = array of event object
var eventsArr = res.body;
var arrayLength = eventsArr.length;
for (var i = 0; i < arrayLength; i++) {
var date = new Date(parseInt(eventsArr[i].startTime))
var day = date.getDate()
var month = date.getMonth()
var year = date.getFullYear()
var hours = date.getHours()
hours = ("0" + hours).slice(-2);
var minutes = date.getMinutes()
minutes = ("0" + minutes).slice(-2);
var str = day;
var str = day + "." + (month + 1) + "." + year +" - " + hours + ":" + minutes
this.datesList.push(str);
}
for (var i = 0; i < arrayLength; i++) {
var evnt = eventsArr[i];
this.avgList.push({label: evnt.name,y: evnt.pulseAverage ,tag: evnt.tag, id: evnt.id });
}
})
}
},
mounted () {
this.gradient = this.$refs.canvas.getContext('2d').createLinearGradient(0, 0, 0, 450)
this.gradient2 = this.$refs.canvas.getContext('2d').createLinearGradient(0, 0, 0, 450)
this.gradient.addColorStop(0, 'rgba(255, 0,0, 0.5)')
this.gradient.addColorStop(0.5, 'rgba(255, 0, 0, 0.25)');
this.gradient.addColorStop(1, 'rgba(255, 0, 0, 0)');
this.gradient2.addColorStop(0, 'rgba(0, 231, 255, 0.9)')
this.gradient2.addColorStop(0.5, 'rgba(0, 231, 255, 0.35)');
this.gradient2.addColorStop(1, 'rgba(0, 231, 255, 0)');
this.renderChart({
labels: this.datesList,
datasets: [
{
label: 'Events',
borderColor: '#05CBE1',
pointBackgroundColor: 'white',
pointBorderColor: 'white',
borderWidth: 2,
backgroundColor: this.gradient2,
data: this.avgList
},
]
,
options: {
scales: {
xAxes: [{
ticks: {
beginAtZero:true
}
}]
}
}
}
//
,{ onClick: function(event){
var activePoints = this.getElementAtEvent(event)
var firstPoint = activePoints[0];
if(firstPoint !== undefined){
var label = this.data.labels[firstPoint._index];
var value = this.data.datasets[firstPoint._datasetIndex].data[firstPoint._index];
var location = "eventGraph?id=" + value.id;
window.location.href = location;
}
}
, responsive: true, maintainAspectRatio: false,fontColor: '#66226',
tooltips: {
enabled: true,
mode: 'single',
callbacks: {
title: function(tooltipItems, data) {
var evnt = data.datasets[0].data[tooltipItems[0].index].label;
return evnt
},
label: function(tooltipItems, data) {
var avg = 'Average heart: ' + [tooltipItems.yLabel];
var evnt = 'Type: ' + data.datasets[0].data[tooltipItems.index].tag;
return [avg,evnt];
}
}
}
})
}
}
It sounds like an initialization issue where the chart is initially rendered in an element that is not visible or it can't determine the size of the parent.
I see similar issues doing a Google:
ChartJS won't draw graph inside bootstrap tab until window resize #17
Charts rendered in hidden DIVs will not display until browser resize #29
Chart.js not rendering properly until window resize or toggling line in legend
One suggested doing a chart refresh when everything is visible:
setTimeout(function() { myChart.update(); },1000);
In think in vue this could be done in the mount function.
I'm sure there is a more elegant way to handle this with a watch function or something similar for instance.
Updated:
As mentioned in the comments, I've seen references to people firing a window resize event manually using:
window.dispatchEvent(new Event('resize'));
I think it would probably work in the mounted function of the vue component:
export default {
name: 'graphs-component',
mounted: function(){
window.dispatchEvent(new Event('resize'));
}
}
You might even wrap it in a setTimeout to ensure everything is loaded.

How to Display Show Attachment in Info Window

I am using below code to display identifier popup.if I click on particular point it will display all the information about that point in info window(popup).but even if I specify show attachments true it will not display the attachments.In Map server I have an image for points.so I need to display info window as well as the image.
map.on("load", mapReady);
var parcelsURL = "MY MAP SERVER";
//map.addLayer(new ArcGISDynamicMapServiceLayer(parcelsURL,
// { opacity: 20 }));
function mapReady() {
map.on("click", executeIdentifyTask);
//create identify tasks and setup parameters
identifyTask = new IdentifyTask(parcelsURL);
identifyParams = new IdentifyParameters();
identifyParams.tolerance = 3;
identifyParams.returnGeometry = true;
identifyParams.layerIds = [0];
identifyParams.layerOption = IdentifyParameters.LAYER_OPTION_ALL;
identifyParams.width = map.width;
identifyParams.height = map.height;
}
function executeIdentifyTask(event) {
identifyParams.geometry = event.mapPoint;
identifyParams.mapExtent = map.extent;
var deferred = identifyTask
.execute(identifyParams)
.addCallback(function (response) {
// response is an array of identify result objects
// Let's return an array of features.
return arrayUtils.map(response, function (result) {
var feature = result.feature;
var layerName = result.layerName;
feature.attributes.layerName = layerName;
if (layerName === 'GridPoint') {
var popupTemplate = new PopupTemplate({
title: "",
fieldInfos: [
{
fieldName: "XX",
visible: true,
label: "XX"
},
{
fieldName: "YY",
visible: true,
label: "YY"
}
],
showAttachments: true
});
//var taxParcelTemplate = new InfoTemplate("",
// "XX: ${XX} <br/> YY: ${YY} <br/> Sample Point Number: ${Sample Point Number} <br/> Point Collected: ${Point Collected} <br/> Major Rabi Crops: ${ Major Rabi Crops} <br/> Major Summer Crop: ${Major Summer Crop} <br/> Soil Type: ${Soil Type} <br/> Major Kharif Crops: ${Major Kharif Crops}");
feature.setInfoTemplate(popupTemplate);
}
//else if (layerName === 'Grid') {
// console.log(feature.attributes.objectid);
// var buildingFootprintTemplate = new InfoTemplate("",
// "OBJECTID: ${OBJECTID}");
// feature.setInfoTemplate(buildingFootprintTemplate);
//}
return feature;
});
});
map.infoWindow.setFeatures([deferred]);
map.infoWindow.show(event.mapPoint);
}
});
someone please help me to display attachments(image) in info window.

svg-edit - set background dynamically

I'm looking at using svg-edit to annotate images in a browser. The image is uploaded on the same page the svg-edit is embedded in and needs to be set dynamically on upload as the background for svg-edit. Can this be done?
You have to call the method of the object i.e svgCanvas.setBackground();
For this you can create an extension e.g : ext-backchange.js
this file look likes this:
svgEditor.addExtension("changeback", function() {
svgCanvas.setBackground('','abc.png');
return {};
});
Then include this extension in svg-edit.js as in the last line :
svgEditor.setConfig(
{
extensions: ['ext-backchange.js']
})
You can use setImageBackground(imageBackground) function
setImageBackground("image.png");
and add this function setImageBackground in svgcanvas.js This image appear on the canvas and can be rotated.
this.setImageBackground= function(val) {
var elem = addSvgElementFromJson({
"element": "image",
"attr": {
"x": ( svgcontent.getAttribute('x') - bgimg_with ) / 2,
"y": ( svgcontent.getAttribute('y') - bgimg_height ) / 2,
"width": bgimg_with,
"height": bgimg_height,
"id": 'ImgBckgd',
"opacity": 1,
"style": "pointer-events:inherit",
}
});
setHref(elem, last_good_img_url);
preventClickDefault(elem);
if(!elem) return;
var attrs = $(elem).attr(['width', 'height']);
var setsize = (!attrs.width || !attrs.height);
var cur_href = getHref(elem);
// Do nothing if no URL change or size change
if(cur_href !== val) {
setsize = true;
} else if(!setsize) return;
var batchCmd = new BatchCommand("Change Image URL");
setHref(elem, val);
batchCmd.addSubCommand(new ChangeElementCommand(elem, {
"#href": cur_href
}));
if(setsize) {
$(new Image()).load(function() {
var changes = $(elem).attr(['width', 'height']);
$(elem).attr({
width: this.width,
height: this.height
});
selectorManager.requestSelector(elem).resize();
batchCmd.addSubCommand(new ChangeElementCommand(elem, changes));
addCommandToHistory(batchCmd);
call("changed", [elem]);
}).attr('src',val);
} else {
addCommandToHistory(batchCmd);
}
};