Esri Print Task doesnt render certain graphics on the map - graphics

My team is building a web application with angular 7 as front end and .net core as back-end.
We are using the print task widget function to generate the image of the map. The problem we are facing is that we have some graphics layers that indicate the position of roadblocks on the map and these roadblocks dont show up on the map when you print it. We have a polygon that the user draws on the map and it shows up , but not the roadblocks.
The code for printing the map can be found in this post of mine.
Esri proxy for Angular 7 project to screenshot
following is a code snippet of how i am setting the roadblock symbol
// symbols
this.roadblockPointSymbol = { // symbol used for points
type: 'picture-marker', // autocasts as new PictureMarkerSymbol()
url: 'assets/img/button-roadblock.png',
width: '20px',
height: '20px'
};
this is the screenshot of the map. The red symbols depicts the roadblocks.
however when i print the map,this is the result i get
Has anyone encountered this issue?

Related

ArcGIS - How to move a graphic or symbol on the map

I'm trying to create an overlay in ArcGIS that has moving graphics/symbols which are updated by coordinates received from roving devices. I'm able to display a simple symbol initially but cannot get it to move on the map. My test code is
GraphicsOverlay machineOverlay = new GraphicsOverlay();
MainMapView.GraphicsOverlays.Add(machineOverlay);
MapPointBuilder rdLocation = new MapPointBuilder(150.864119200149, -32.3478640837185, SpatialReferences.Wgs84);
SimpleMarkerSymbol sRD1234 = new SimpleMarkerSymbol()
{
Color = System.Drawing.Color.Red,
Size = 10,
Style = SimpleMarkerSymbolStyle.Circle
};
Graphic graphicWithSymbol = new Graphic(rdLocation.ToGeometry(), sRD1234);
machineOverlay.Graphics.Add(graphicWithSymbol);
// here the red circle is displayed correctly on the map
rdLocation.SetXY(150.887115, -32.357600);
rdLocation.ReplaceGeometry(rdLocation.ToGeometry());
// here I expect the red circle to move but it doesn't
Do I need to trigger an event to "re-render" or refresh the overlay, or what do I need to do to get the graphic to move on my map?
There was a similar question here and the answer was "just update the geometry" which is what I'm attempting to do, but with no success.
If there is an entirely different or better approach to moving markers on a map please suggest, I'm just getting started in the ArcGIS runtime.
Thanks
After a lot of searching I replaced one line of code and its now working
//rdLocation.ReplaceGeometry(rdLocation.ToGeometry());
graphicWithSymbol.Geometry = rdLocation.ToGeometry();
It seems I misunderstood the function of ReplaceGeometry(). Any clarification on this would be helpful.

PIXI Sprite displays in black

I am trying to set a Sprite as a background in my viewport. The grid.png is 23040 x 9984 pixels.
this.app.loader
.add("grid", require("./assets/grid.png"))
.load((loader, resources) => {
const grid = new PIXI.Sprite(resources.grid.texture);
grid.anchor.set(0, 0);
grid.scale.set(1);
this.container.addChild(grid);
});
The Sprite shows in my Container but only in black. If I try with a smaller png (25 x 25 pixels) it works.
I also made sure my viewport world width and height were big enough :
this.viewport = new Viewport({
screenWidth: 953,
screenHeight: 409,
worldWidth: 25000,
worldHeight: 10000,
interaction: this.app.renderer.plugins.interaction
});
Here is the sandbox code
https://codesandbox.io/s/pixi-sprite-loading-cn7re?file=/src/App.vue:572-875
You see sprite as black (in chrome) because is too big and you add it using "require":
.add("grid", require("./assets/grid.png"))
this does basically following:
.add("grid", "data:image/png;base64,iVBORwA<MoreBase64StringHere>")
which is too much for browser when grid.png has such big dimensions.
You should add it by passing url to the image - instead of requiring whole inlined image:
.add({
name: "grid",
url: "grid-small.png",
crossOrigin: "anonymous"
})
Note that grid-small.png should be in "public" dir of codesandbox, and crossOrigin: "anonymous" is to avoid problems with cross-origin when image is loaded.
Such big images (especially if it consist basically many copies of same image) should be avoided. You should try using for example some small/medium chunk of the image (the mentioned grid-small.png) and TilingSprite technique. In such way you can easily have 25000 x 10000 grid - as you can see in codesandbox below.
You shouldnt keep Pixi objects inside Vue component state - i already told you in other post about it ( https://stackoverflow.com/a/62094101/3174731 ) - you are not listening ;) . Why do you want Vue to analyze Pixi objects? Is not its job. Vue should be about what is going on in DOM etc - not about whats in canvas. See codesandbox linked below how much faster everything is if you keep Pixi related objects outside of Vue component (myPixi variable).
You can see how above optimizations work in following codesandbox (modified version of yours) : https://codesandbox.io/s/pixi-sprite-loading-3vsne?file=/src/App.vue

Silent printing in electron

I am currently building an electron app. I have a PDF on my local file system which I need to silently print out (on the default printer). I came across the node-printer library, but it doesn't seem to work for me. Is there an easy solution to achieve this?
Well first of all it is near impossible to understand what you mean with "silent" print. Because once you send a print order to your system printer it will be out of your hand to be silent at all. On Windows for example once the order was given, at least the systemtray icon will indicate that something is going on. That said, there are very good described features for printing with electron even "silent" is one of them:
You need to get all system printers if you do not want to use the default printer:
contents.getPrinters()
Which will return a PrinterInfo[] Object.
Here is an example how the object will look like from the electron PrtinerInfo Docs:
{
name: 'Zebra_LP2844',
description: 'Zebra LP2844',
status: 3,
isDefault: false,
options: {
copies: '1',
'device-uri': 'usb://Zebra/LP2844?location=14200000',
finishings: '3',
'job-cancel-after': '10800',
'job-hold-until': 'no-hold',
'job-priority': '50',
'job-sheets': 'none,none',
'marker-change-time': '0',
'number-up': '1',
'printer-commands': 'none',
'printer-info': 'Zebra LP2844',
'printer-is-accepting-jobs': 'true',
'printer-is-shared': 'true',
'printer-location': '',
'printer-make-and-model': 'Zebra EPL2 Label Printer',
'printer-state': '3',
'printer-state-change-time': '1484872644',
'printer-state-reasons': 'offline-report',
'printer-type': '36932',
'printer-uri-supported': 'ipp://localhost/printers/Zebra_LP2844',
system_driverinfo: 'Z'
}
}
To print your file you can do it with
contents.print([options])
The options are descriped in the docs for contents.print():
options Object (optional):
silent Boolean (optional) - Don’t ask user for print settings. Default is false.
printBackground Boolean (optional) - Also prints the background color and image of the web page. Default is false.
deviceName String (optional) - Set the printer device name to use. Default is ''.
Prints window’s web page. When silent is set to true, Electron will pick the system’s default printer if deviceName is empty and the default settings for printing.
Calling window.print() in web page is equivalent to calling webContents.print({silent: false, printBackground: false, deviceName: ''}).
Use page-break-before: always; CSS style to force to print to a new page.
So all you need is to load the PDF into a hidden window and then fire the print method implemented in electron with the flag set to silent.
// In the main process.
const {app, BrowserWindow} = require('electron');
let win = null;
app.on('ready', () => {
// Create window
win = new BrowserWindow({width: 800, height: 600, show: false });
// Could be redundant, try if you need this.
win.once('ready-to-show', () => win.hide())
// load PDF.
win.loadURL(`file://directory/to/pdf/document.pdf`);
// if pdf is loaded start printing.
win.webContents.on('did-finish-load', () => {
win.webContents.print({silent: true});
// close window after print order.
win = null;
});
});
However let me give you a little warning:
Once you start printing it can and will get frustrating because there are drivers out there which will interpret data in a slightly different way. Meaning that margins could be ignored and much more. Since you already have a PDF this problem will most likely not happen. But keep this in mind if you ever want to use this method for example contents.printToPDF(options, callback). That beeing said there are plently of options to avoid getting frustrated like using a predefined stylesheet like descriped in this question: Print: How to stick footer on every page to the bottom?
If you want to search for features in electron and you do not know where they could be hidden, all you have to do is to go to "all" docs and use your search function: https://electron.atom.io/docs/all/
regards,
Megajin
I recently published NPM package to print PDF files from Node.js and Electron. You can send a PDF file to the default printer or to a specific one. Works fine on Windows and Unix-like operating systems: https://github.com/artiebits/pdf-to-printer.
It's easy to install, just (if using yarn):
yarn add pdf-to-printer
or (if using npm):
npm install --save pdf-to-printer
Then, to silently print the file to the default printer you do:
import { print } from "pdf-to-printer";
print("assets/pdf-sample.pdf")
.then(console.log)
.catch(console.error);
To my knowledge there is currently no way to do this directly using Electron because while using contents.print([]) does allow for 'silently' printing HTML files, it isn't able to print PDF views. This is currently an open feature request: https://github.com/electron/electron/issues/9029
Edit: I managed to work around this by converting the PDF to a PNG and then using Electron's print functionality (which is able to print PNGs) to print the image based view. One of the major downsides to this is that all of the PDF to PNG/JPEG conversion libraries for NodeJS have a number of dependencies, meaning I had to implement them in an Express server and then have my Electron app send all PDFs to the server for conversion. It's not a great option, but it does work.

Leaflet geojson layer with customized divIcon for each feature

I'm trying to set a different divIcon for each point on a leaflet geoJson layer. I have tried everything under the sun but it just doesn't work for me. This is what I'm doing
geoJsonLayer = L.geoJson(null, {
pointToLayer: function(feature, latlng) {
var smallIcon = L.DivIcon.extend({
options: {
iconSize: [27, 27],
html: "<div>" + feature.properties.FEATURE_STYLE.SVG_ELEMENT + "</div>"
}
});
return L.marker(latlng, {icon: new smallIcon()});
},
style: getLayerStyle,
onEachFeature: setFeatureProperties,
});
geoJsonLayer.addTo(baseMap);
feature.properties.FEATURE_STYLE.SVG_ELEMENT is an html <svg> containing the icon.
The icons are displayed ok, but every feature display the same icon.
I've also tried doing the following:
using L.Icon with different .png in iconUrl for each feature
using L.circleMarker with different colors for each feature
They both works as expected (different color / icon per feature). But I can't seem to get the divIcon to display differently for each feature.
Anyone have idea why this is the case?
Thanks in advance.
UPDATE:
This is what feature.properties.FEATURE_STYLE.SVG_ELEMENT looks like
Your code to instantiate a new L.divIcon is more complicated than really necessary, but it works, not considering the SVG part:
https://jsfiddle.net/3v7hd2vx/236/
That being said, please note that:
style option is used for vector layers. Therefore in the case of Point features that are rendered as L.divIcon's, it is not used.
onEachFeature option is applied after the pointToLayer one, because the latter is needed to create the layer that is fed to onEachFeature. Therefore if you build the feature.properties.FEATURE_STYLE.SVG_ELEMENT in there (as the name of your function setFeatureProperties suggests), it is too late.
If you need further help, you would very probably need to share more code, e.g. the style and onEachFeature options, and some sample data, in particular with feature.properties.FEATURE_STYLE.SVG_ELEMENT.

Example to show how mobify works

I have been looking at the mobify.js website for a while now, but I fail to understand the benefits of using it. (I am stumped to see why would one replace all the images on the page by GrumpyCat image?).
Could you kindly point me to a clear and lucid example, wherein, I can see that depending on the browser resolution my image size changes.
I have done the following tasks till now:
0. Included mobify.js header information
1. Used the mountains.jpg and forest.jpg image in my hosted website (The page contains only these two images)
2. Request the page from a desktop machine, from a tablet (Samsung Galaxy 10 inch), from an android mobile phone.
3. In all the three cases, I see the same image getting downloaded, the size of the image stays the same in all the cases.
I understand that the magic of size reduction can't happen on the fly, but how do I achieve this?
I realize that the Grumpy Cat example is a bit cheeky, but the same concept applies to solve your problem. Instead of replacing the images with Grumpy Cat images, you could write some logic to replace the images with lower-resolution images (i.e. mountains-320.jpg and forest-320.jpg).
With Mobify.js, you need to write the adaptations in the JavaScript snippet that you added to your site. So, to load smaller images for mobile, you could define the path to the lower resolution image in your original HTML like this:
<img src="mountain.jpg" data-mobile-src="mountain-320.jpg" />
<img src="forest.jpg" data-mobile-src="forest-320.jpg" />
Then, in the JavaScript snippet, you could modify it to grab the image in the data-mobile-src attribute instead like this:
if (capturing) {
// Grab reference to a newly created document
Mobify.Capture.init(function(capture){
// Grab reference to the captured document in progres
var capturedDoc = capture.capturedDoc;
var imgs = capturedDoc.getElementsByTagName("img[data-mobile-src]");
for(var i = 0; i < imgs.length; i++) {
var img = imgs[i];
var ogImage = img.getAttribute("x-src");
var mobileImage = img.getAttribute("data-mobile-src");
img.setAttribute("x-src", mobileImage);
img.setAttribute("old-src", ogImage);
}
// Render source DOM to document
capture.renderCapturedDoc();
});
}
Then, you'll see that the mobile site will download and render mountain-320.jpg or forest-320.jpg, but it will not download mountain.jpg or forest.jpg.
Just out of curiousity, what site are you wanting to use Mobify.js on?

Resources