How to view Google Maps in "print" mode? - css

I'm using the Google Maps API v2 and I'd like to be able to print the map the same way as Google does on its Maps page.
You can click the little printer icon and it creates a new popup window with the same map but all the unprintable stuff (like the controls) is taken out.
I know that they use #media print to achieve that effect when you hit "Print preview" or "Print" in the navigator. However, the popup window isn't in print mode.
Is there any way of doing the magic trick they're doing, like setting the current media type to "print"? Or or they cheating and setting a custom CSS style cheat?
I've got a Silverlight plugin and a Google Map on the same page and I want to be able to create a popup window containing just the map ready for printing (like Google is doing).
Thanks to http://abcoder.com/google/google-map-api/print-button-for-google-map-api/ I know how to get the HTML content but I can only get the content with all the controls etc on it (which I don't want).
Any help will be appreciated.

Google maps put a class gmnoprint on all elements that they do not want to print .. so setting this to display:none in your print css file or popup window will hide them ..
.gmnoprint{
display:none;
}
Of'course this will hide whatever google deems as not-for-printing.. If you want to select other items you will have to somehow parse their html code :(

I was having the same problem with a custom map image overlay added via kml. Gaby's heads-up about the gmnoprint class was the key. In my case, the div with the gmnoprint class applied was the direct parent of my img element that was getting disappeared. I basically created a "make overlay printable link":
$("#printable-map").click(function() {
if($(this).text() == "Include overlay when printing") {
$(this).text("Exclude overlay when printing");
$("[src$=blah.png]").parent().removeClass("gmnoprint");
} else {
$(this).text("Include overlay when printing");
$("[src$=blah.png]").parent().addClass("gmnoprint");
}
});
Tested and works in Safari, FF, and Chrome.

Another useful approach for printing google maps is to use the Google Static Maps API. You can generate an static image based on a range of display paramters (location, zoom level, size, markers etc...) and include that image in your print view page.

Related

Webpage using appScript: innerHTML assignment not working

I have a simple WebApp application that reads the data from google sheet and displays in HTML using materialize css( 1.0.0), JS. I am new to this stack of tools. HTML page has 2 containers and bottom one supposed to be populated (using innerHTML assignment)based on the selection on the top container. The bottom container content is simple card contents in table format. I want to put a HTML Select object with List of values to be displayed and created a Appscript function. I am assigning the function output to innerHTML like this.
-- JS
function generateCards(text_card){
document.getElementById("container-id").innerHTML += text_card;
}
function createAuthorCards(authorName) {
document.getElementById("container-id").innerHTML = "";
google.script.run.withSuccessHandler(generateCards).getCardDynamicText(authorName) ;
}
--
If put copy/paste the function output in HTML it works( goes through rendering when refereshing), but if i use InnerHTML, the listbox is disabled, but all else seems ok. needed imageplease see the 2 attachments needed and missing_listbox images.enter image description here Is there any limitations of using innerHTML in webApp?
I was using google Webapp. It looks google doesn't allow the editing of dynamically created items. So I ended up using Modals to make the selections and save it.

Adobe Scene7 BasicZoomViewer: How to reset zoom

Question
I'm working with Adobe Scene7 BasicZoomViewer and I'm looking for a way to tell the ZoomViewer to reset the zoom so that the user is no longer zoomed in on an image but instead will show the default "zoom" level.
What I've found
The closest thing I found to what I need is this reset property ZoomView.reset which "Resets the viewport when the frame (image) changes. If set to 0 it preserves the current viewport with the best possible fit while preserving the aspect ratio of the newly set image".
This looks close to something I need but it states that it will reset or preserve the aspect ratio when a new image has been inserted but I am not inserting new images.
Demo from Adobe
There is a button on the image that the API inserts into the page that resets the zoom level. Adobe provides a demo page that shows what I'm working with. If you look at the bottom left, the right-most button is the reset button. When clicked, it has to make some kind of API call and I need to figure out which one it is.
Edit
I've been able to find a minified version of the BasicZoomViewer and I am currently attempting to make sense of the code.
There is an event listener placed on the "Zoom Reset Button" that just simply calls a reset() method on line 274 in the uglified version of the file. Currently, I am trying to make sense of the file and figure out how to access this method.
c.zoomResetButton.addEventListener("click", function () {
c.zoomView.zoomReset()
});
I will be answering my own question. If someone finds a better way please feel free to answer as well.
tldr;
Create a variable to hold the instance of your s7viewers.BasicZoomViewer() and inside of that you can access the event handlers and much more.
Example of calling the reset zoom handler
// instantiate the s7viewers class and save it in a variable
var s7BasicZoomViewer = new s7viewers.BasicZoomViewer({
containerId: 's7viewer',
params: {
asset: assetUrl,
serverurl: serverUrl
})
// example of how to call the "zoomReset()" method
s7BasicZoomViewer.zoomResetButton.component.events.click[0].handler()
Explanation
After digging through the minified code that was uglified I found an event listener on the s7zoomresetbutton DOM class name, or perhaps it's watching for the ID of that DOM element which is the same ID as the container div for your S7 BasicZoom Viewer plus some added text to make this ID unique. For example, if the container div is s7viewer then the reset zoom button will have an ID of s7viewer_zoomresetbutton.
Now, going through the code I found this event listener which let me know there must be some way to call the zoomReset() method.
c.zoomResetButton.addEventListener("click", function () {
c.zoomView.zoomReset()
});
In the code above, the value of c is this or in other words it's the instance of your S7 BasicViewerZoom and in my case I have multiple depending on how many images I need to zoom on.
When instantiating the s7viewers class you can then reference that instance later and access the event handlers on each button and other properties and methods.
From there it was just looking through the object returned from the instance and calling the handler for the reset button.

How can I change the font of the Time4J CalendarPicker in JavaFX?

Is there a way to change the font of Time4J CalenderPicker in css-style?
I needed a Persian DatePicker in my program so i used Time4J CalenderPicker.
using this code i could change only the font of cells:
CalendarPicker<PersianCalendar> MyDatePicker = CalendarPicker.persianWithSystemDefaults();
MyDatePicker.setCellCustomizer(
(cell, column, row, model, date) -> {
cell.setStyle("-fx-font-family: MyFont;");
}
);
I tried this code but nothing changed:
MyDatePicker.setStyle("-fx-font-family: MyFont;");
But i want to change the font of hole CalendarPicker.
In order to apply the changes, you need to use the following code and set new css styles for calender picker and applying the customizations.
private CalendarPicker<PersianCalendar> MyDatePicker = CalendarPicker.persianWithSystemDefaults();
MyDatePicker.getStylesheets().add("/MyCSS-Style.css");
The following gif, demonstrates my customizations.
The calendar picker itself is only the combination of a text editor and a popup button (bundled in a HBox). However, the calendar view is another component which pops up if users press the button. And this component whose font you wish to change is not yet publicly accessible (with the exception of the cells via a special customizer).
I agree that this should be more flexible. Therefore I have opened a new issue to track this request for enhancement.
Feel free to fork Time4J and do your experiments and submit a pull request on time4j-github. Actually I am busy with other things but can look deeper then.

Print Friendly Page

So I would like to be able to have a print button for entries in our database so users can print an entry via a print friendly "form".
My thought was to create a separate page, add labels and have those labels pull the relevant information.
I know I can add the open widget information via this code:
app.datasources.ModelName.selectKey(widget.datasource.item._key);
app.showPage(app.pages.TestPrint);
But I'm running into a few problems:
I can't get the page to open in a new window. Is this possible?
window.open(app.pages.TestPrint);
Just gives me a blank page. Does the browser lose the widget source once the new window opens?
I can't get the print option (either onClick or onDataLoad) to print JUST the image (or widget). I run
window.print();
And it includes headers + scroll bars. Do I need to be running a client side script instead?
Any help would be appreciated. Thank you!
To get exactly what you'd want you'd have to do a lot of work.
Here is my suggested, simpler answer:
Don't open up a new tab. If you use showPage like you mention, and provide a "back" button on the page to go back to where you were, you'll get pretty much everything you need. If you don't want the back to show up when you print, then you can setVisibility(false) on the button before you print, then print, then setVisibility(true).
I'll give a quick summary of how you could do this with a new tab, but it's pretty involved so I can't go into details without trying it myself. The basic idea, is you want to open the page with a full URL, just like a user was navigating to it.
You can use #TestPrint to indicate which page you want to load. You also need the URL of your application, which as far as I can remember is only available in a server-side script using the Apps Script method: ScriptApp.getService().getUrl(). On top of this, you'll probably need to pass in the key so that your page knows what data to load.
So given this, you need to assemble a url by calling a server script, then appending the key property to it. In the end you want a url something like:
https://www.script.google.com/yourappaddress#TestPage?key=keyOfYourModel.
Then on TestPage you need to read the key, and load data for that key. (You can read the key using google.script.url).
Alternatively, I think there are some tricks you can play by opening a blank window and then writing directly to its DOM, but I've never tried that, and since Apps Script runs inside an iframe I'm not sure if it's possible. If I get a chance I'll play with it and update this answer, but for your own reference you could look here: create html page and print to new tab in javascript
I'm imagining something like that, except that your page an write it's html content. Something like:
var winPrint = window.open('', '_blank', 'left=0,top=0,width=800,height=600,toolbar=0,scrollbars=0,status=0');
winPrint.document.write(app.pages.TestPage.getElement().innerHTML);
winPrint.document.close();
winPrint.focus();
winPrint.print();
winPrint.close();
Hope one of those three options helps :)
So here is what I ended up doing. It isn't elegant, but it works.
I added a Print Button to a Page Fragment that pops up when a user edits a database entry.
Database Edit Button code:
app.datasources.ModelName.selectKey(widget.datasource.item._key);
app.showDialog(app.pageFragments.FragmentName);
That Print Button goes to a different (full) Page and closes the Fragment.
Print Button Code:
app.datasources.ModelName.selectKey(widget.datasource.item._key);
app.showPage(app.pages.ModelName_Print);
app.closeDialog();
I made sure to make the new Print Page was small enough so that Chrome fits it properly into a 8.5 x 11" page (728x975).
I then created a Panel that fills the page and populated the page with Labels
#datasource.item.FieldName
I then put the following into the onDataLoad for the Panel
window.print();
So now when the user presses the Print Button in the Fragment they are taken to this new page and after the data loads they automatically get a print dialog.
The only downside is that after printing the user has to use a back button I added to return to the database page.
1.
As far as I know, you cannot combine window.open with app.pages.*, because
window.open would require url parameter at least, while app.pages.* is essentially an internal routing mechanism provided by App Maker, and it returns page object back, suitable for for switching between pages, or opening dialogs.
2.
You would probably need to style your page first, so like it includes things you would like to have printed out. To do so please use #media print
ex: We have a button on the page and would like to hide it from print page
#media print {
.app-NewPage-Button1 {
display : none;
}
}
Hope it helps.
1. Here is how it is done, in a pop up window, without messing up the current page (client script):
function print(widget, title){
var content=widget.getElement().innerHTML;
var win = window.open('', 'printWindow', 'height=600,width=800');
win.document.write('<head><title>'+title+'/title></head>');
win.document.write('<body>'+content+'</body>');
win.document.close();
win.focus();
win.print();
win.close();
}
and the onclick handler for the button is:
print(widget.root.descendants.PageFragment1, 'test');
In this example, PageFragment1 is a page fragment on the current page, hidden by adding a style with namehidden with definition .hidden{display:none;} (this is different than visible which in App Maker seems to remove the item from the DOM). Works perfectly...
2. You cannot open pages from the app in another tab. In principle something like this would do it:
var w=window.parent.parent;
w.open(w.location.protocol+'//'+w.location.host+w.location.pathname+'#PrintPage', '_blank');
But since the app is running in frame nested two deep from the launching page, and with a different origin, you will not be able to access the url that you need (the above code results in a cross origin frame access error). So you would have to hard code the URL, which changes at deployment, so it gets ugly very fast. Not that you want to anyway, the load time of an app should discourage you from wanting to do that anyway.

Google maps api v3 custom control is moving to the left after execution of panorama.setPosition function

i have a problem on my map application, i am trying to put a coustom control on a Panorama and when users click to this custom button, panorama informations wll be saved.
For this purpose, i am using a function to check if there is a panaroma data exists
function checkforstreetview(mapid){
service.getPanoramaByLocation(markers[mapid].getPosition(), 50, function(r,status){
if(status==google.maps.StreetViewStatus.OK){
google.maps.event.addListener(markers[mapid], 'click', function (e) {
panorama[mapid].setVisible(true);
return false;
});
panorama[mapid].setPosition(markers[mapid].getPosition()); // custom control is moving to the left occurs here
}
});
}
as first, i am getting marker position on the map and check for panorama within 50m then if there is a panorama data, i am binding an click event to the marker for switching to panorama.
I am placing customdiv control via;
panorama[mapid].controls[google.maps.ControlPosition.TOP_CENTER].push(customdiv[0]);
Html markup of custom control is:
<div id="customdiv" title="Get data" style="height:10%;cursor:pointer;margin:0 auto;"><img src="/customdiv.jpg" style="height:100%;float:right;margin:5px;"/></div>
At the same time, i've assigned a function for drag and drop event for marker (with addlistener method), so if the marker drag'n drop to another position, checkforstreetview function is executed again.
So, what is the main problem?
In first execution there is no problem, when i click to the marker, panorama opens correctly and custom control is correctly placed but after close the panorama, drag'n drop marker to another position and click to marker again to show new panorama for new position, custom control moving to the left of panorama view.
Correct positioning (when system is initially loaded)
And buggy positioning (when i switch to panorama view in second time with marker click)
Extra information :
Because of google maps need to know height and width of container to work properly, i am using visibility: hidden rule for map container, not display:none but i think this cannot be problem bacause, on system load everything works correctly.
I've tested on Windows 7 / Firefox - Chrome - Opera - Safari - IE (lastest versions)
Tried solutions:
Many CSS hacks
Re-positioning custom control via google.maps.ControlPosition.TOP_CENTER
I've tried to put custom control to another positions BOTTOM_CENTER, LEFT_BOTTOM, .. etc but every time, custom control is moving to another position (shifting to the right, top, left )
Finally, i've commented out panorama[mapid].setPosition(markers[mapid].getPosition()); line and i've used standard packman to panorama/map switching then there is no problem on custom control positioning.
EDIT : Another interesting point is, after wrong positioning of custom control (and adress bar) when i click to next/previous arrows for next/previous images of panorama, custom control and adress bar becomes normal (correct position)
What can be the solution to stop shifting/moving costom control?
Thanks right now...
You cannot designate static CSS for the API, you must tell the maps API what you want your CSS to be (assign CSS properties in javascript):
https://developers.google.com/maps/documentation/javascript/examples/control-custom
I've resolved the issue by below function
google.maps.event.addListener(panorama[mapid], 'position_changed', function() {
google.maps.event.trigger(panorama[mapid],'resize');
});

Resources