COG on Google Cloud Storage - error using OpenLayers without NodeJS - google-cloud-platform

I'm playing with OpenLayers to display COG files uploaded on GCS.
Using the NodeJS, an index.html and a main.js files, then building with Parcel (or others), everything works fine.
When I tried to skip using NodeJS, coding an HTML files with the CDN imports, and the inline JavaScript, it looks like OpenLayers is not able to retrieve all the needed dependencies. In particular in the network request/response, I have:
Request URL: https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v6.14.1/build/231.ol.js
Request Method: GET
Status Code: 403
Remote Address: 151.101.241.229:443
Referrer Policy: strict-origin-when-cross-origin
and if I try to hit directly the URL in the Browser:
https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v6.14.1/build/231.ol.js
I got:
Package size exceeded the configured limit of 50 MB. Try https://github.com/openlayers/openlayers.github.io/tree/master/en/v6.14.1/build/231.ol.js instead.
Why?
Below the content of the HTML file I stored on GCS (layer styling omitted),
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>COG on Google Cloud Storage</title>
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v6.14.0/build/ol.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v6.14.0/css/ol.css">
<style>
html, body {
margin: 0;
height: 100%;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
<script type="text/javascript">
var cogSource = new ol.source.GeoTIFF (
{
normalize: true,
sources: [
{
url: 'https://storage.googleapis.com/fao-gismgr-cache/TEST/L1_AETI_21.tif',
min: -9999,
max: 16000
}
],
transition: 0
}
);
var cogLayer = new ol.layer.WebGLTile (
{
source: cogSource
}
);
var cogView = new ol.View (
{
projection: 'EPSG:4326',
minZoom: 0,
maxZoom: 12,
center: [0,0],
zoom: 4
}
);
var map = new ol.Map({
target: 'map',
maxTilesLoading: 32,
layers: [cogLayer],
view: cogView
});
</script>
</body>
</html>
The COG and HTML file are on a public GCS bucket.
To test, I use Chrome with web-security disabled (CORS policies)
open -na Google\ Chrome --args --user-data-dir=/tmp/temporary-chrome-profile-dir --disable-web-security --disable-site-isolation-trials
Could you help me?
Thanks in advance,
Davide

Thanks #Mike, I was having the same problem and tried your solution both with local and remote files and it worked without any problem.
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v6.12.0/build/ol.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v6.12.0/css/ol.css">

Related

Power Bi and WebBrowser control

It is possible to render a power bi report in a windows form web browser control? I created an html file and added to navigate method but is not working. Also I added the html content to the documenttext property and is not working.
I'm using the embed for customer.. approach but I only get a blank page. This is the code that I pass to the webbrowser control. Do you have a sample using the windows forms project?
<!DOCTYPE html>
<html lang='en' xmlns='http://www.w3.org/1999/xhtml'>
<head>
<meta charset='utf-8' />
<title></title>
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js' referrerpolicy='no-referrer'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/powerbi-client/2.19.1/powerbi.min.js' integrity='sha512-JHwXCdcrWLbZo78KFRzEdGcFJX1DRR+gj/ufcoAVWNRrXCxUWj2W2Hxnw61nFfzfWAdWchR9FQcOFjCNcSJmbA==' crossorigin='anonymous' referrerpolicy='no-referrer'></script>
</head>
<body>
<div id='embedContainer'></div>
<script type="text/javascript">
const reportContainer = $('#embedContainer')[0];
const accessToken = 'token.....';
const embedUrl = 'https://xxx.powerbi.com/reportEmbed?reportId=0b0fe232.....';
const embedReportId = '0b0fe232.....';
const tokenExpiry = '5/20/2022 5:42:13 PM';
const models = window['powerbi-client'].models;
const config = {
type: 'report',
tokenType: models.TokenType.Embed,
accessToken: accessToken,
embedUrl: embedUrl,
id: embedReportId,
permissions: models.Permissions.All,
settings:
{
filterPaneEnabled: true,
navContentPaneEnabled: true
}
};
const report = powerbi.embed(reportContainer, config);
</script>
</body>
</html>
Thanks,
Ev
Yes. There are a number of approaches you can consider.
Power BI Secure Embedding just uses an IFrame and the desktop user will need to authenticate to Power BI. Minimally generate the embedding link from Power BI
and embed it in an a static HTML page like this:
<html>
<iframe title="Some Report"
style="position: absolute; height: 100%; width: 100%; border: none"
src="https://xxx.powerbi.com/reportEmbed?reportId=d12ecc27-a855-4b27-9..."
frameborder="0"
allowFullScreen="true">
</iframe>
</html>
Or you can build and register full web app to do embedding using either the Embed For Your Customers, or the Embed For Your Organization workflow. This adds a javascript API to control and interact with the embedded reports from your hosting application.

How can I embed an Autodesk Forge Viewer to a Flask App without CORS errors?

I followed the Developer's Guide (step 1-3) to create an html file to view my BIM model - this worked fine.
But if I put the same code into a flask app I am not able to view the BIM model. I looked at the requests and found a couple of CORS errors while loading the document with Autodesk.Viewing.Document.load:
If I hover over CORS error I got a small popup telling me: "Cross origin resource sharing error: HeaderDisallowedByPreflightResponse".
I tried to change the callback url of my forge app to http://localhost:5001 and http://localhost:5001/* but this had no impact.
How can I embed an Autodesk Forge Viewer to a Flask App without CORS errors?
Why are there CORS errors on localhost but not on file:///.../index.html?
update:
Here is my html file - which works (I removed secrets here). I basically just put the same code into a flask app...
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=no"/>
<meta charset="utf-8">
<title>Axpo BIM Viewer</title>
<link rel="stylesheet" href="https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/style.min.css"
type="text/css">
<script src="https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/viewer3D.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.js"></script>
<style>
body {
margin: 0;
}
#forgeViewer {
width: 100%;
height: 800px;
margin: 0;
background-color: #F0F8FF;
}
#forgeViewer > div {
height: 800px !important;
}
</style>
<script>
$(() => {
let client_id = '__client_id__'
let client_secret = '__client_secret__'
let documentId = 'urn:__documentId__'
let htmlDiv = document.getElementById('forgeViewer');
let viewer = new Autodesk.Viewing.GuiViewer3D(htmlDiv);
get_an_account(client_id, client_secret).then(function (response) {
initialize_viewer(viewer, response.access_token)
load_document(viewer, documentId)
});
});
async function get_an_account(client_id, client_secret) {
var request = {
"url": 'https://developer.api.autodesk.com/authentication/v1/authenticate',
"method": "POST",
"timeout": 0,
"headers": {
'Content-Type': 'application/x-www-form-urlencoded'
},
"data": {
client_id: client_id,
client_secret: client_secret,
grant_type: 'client_credentials',
scope: 'code:all data:write data:read bucket:create bucket:delete bucket:read'
}
};
return $.ajax(request);
}
function initialize_viewer(viewer, token) {
var options = {
env: 'AutodeskProduction2',
api: 'streamingV2', // for models uploaded to EMEA change this option to 'streamingV2_EU'
getAccessToken: function (onTokenReady) {
var timeInSeconds = 3600; // Use value provided by Forge Authentication (OAuth) API
onTokenReady(token, timeInSeconds);
}
};
Autodesk.Viewing.Initializer(options, () => {
var startedCode = viewer.start();
if (startedCode > 0) {
console.error('Failed to create a Viewer: WebGL not supported.');
return;
}
console.log('Initialization complete, loading a model next...');
});
}
function load_document(viewer, documentId) {
Autodesk.Viewing.Document.load(documentId, (viewerDocument) => {
var defaultModel = viewerDocument.getRoot().getDefaultGeometry();
viewer.loadDocumentNode(viewerDocument, defaultModel);
}, () => {
console.error('Failed fetching Forge manifest');
});
}
</script>
</head>
<body>
<div id="forgeViewer"></div>
</body>
</html>
I could not reproduce the issue, however, one thing that will be causing problems is that you're not waiting for initialize_viewer() to finish before trying to load a document. Looks like when using the file:// protocol, you don't run into problems with that though.
I turned that function into a Promise so that we can await it.
Also, it's better to keep the client secret on the server side, so I added that to the code too. You'll just have to update the variables in server.py
This solution worked fine for me. Maybe your Flask app has some different settings that cause the issue?
I had index.html in the templates folder:
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=no" />
<meta charset="utf-8" />
<title>Axpo BIM Viewer</title>
<link rel="stylesheet" href="https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/style.min.css" type="text/css" />
<script src="https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/viewer3D.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<style>
body {
margin: 0;
}
#forgeViewer {
width: 100%;
height: 800px;
margin: 0;
background-color: #f0f8ff;
}
#forgeViewer>div {
height: 800px !important;
}
</style>
<script>
$(async() => {
let documentId = "urn:{{ documentId }}";
let htmlDiv = document.getElementById("forgeViewer");
let viewer = new Autodesk.Viewing.GuiViewer3D(htmlDiv);
await initialize_viewer(viewer);
load_document(viewer, documentId);
});
async function get_access_token(onTokenReady) {
var request = {
url: "/access_token",
method: "GET",
};
let res = await $.ajax(request);
console.log(res);
onTokenReady(res.access_token, res.expires_in);
}
async function initialize_viewer(viewer) {
return new Promise(resolve => {
var options = {
env: "AutodeskProduction2",
api: "streamingV2", // for models uploaded to EMEA change this option to 'streamingV2_EU'
getAccessToken: get_access_token,
};
Autodesk.Viewing.Initializer(options, () => {
var startedCode = viewer.start();
if (startedCode > 0) {
console.error("Failed to create a Viewer: WebGL not supported.");
return;
}
console.log("Initialization complete, loading a model next...");
resolve();
});
})
}
function load_document(viewer, documentId) {
console.log("Loading document");
Autodesk.Viewing.Document.load(
documentId,
(viewerDocument) => {
var defaultModel = viewerDocument.getRoot().getDefaultGeometry();
viewer.loadDocumentNode(viewerDocument, defaultModel);
},
() => {
console.error("Failed fetching Forge manifest");
}
);
}
</script>
</head>
<body>
<div id="forgeViewer"></div>
</body>
</html>
server.py
from flask import Flask, render_template
import requests
app = Flask(__name__)
# Update variable values
document_id=""
client_id=""
client_secret=""
#app.route("/")
def run():
return render_template('index.html', documentId=document_id)
#app.route("/access_token")
def get_access_token():
headers = {"Content-Type": "application/x-www-form-urlencoded"}
body = (
f"client_id={client_id}"
f"&client_secret={client_secret}"
"&grant_type=client_credentials"
"&scope=viewables:read"
)
print(body)
res = requests.post("https://developer.api.autodesk.com/authentication/v1/authenticate", data=body, headers=headers)
data = res.json()
return data
"Why are there CORS errors on localhost but not on file:///.../index.html?"
I guess the browser has different security concerns for the different protocols. The Viewer does not support the file:// protocol (only http:// / https://) and with some models you'll run into issues because of that - e.g. like this:

How to enable swagger UI in AWS

I created the serverless application using .Net core and hosted in AWS. I am able to create swagger.json by publishing API documentation under API gateway.
I am looking for the documentation to create swagger UI for those APIs.
Is any possibility to view the swagger UI in AWS itself.
I do not think AWS built a swagger UI in one of their services. At least, I am not aware of it.
However, it is possible to easily create a swagger visualization using S3.
There is an article on Medium which explains this well. [1]
Basically, what you need to script is:
Creation of an S3 bucket with static website hosting
Downloading the static swagger UI resources from GitHub
Syncing the resources to the S3 bucket
Downloading the swagger.json from API Gateway [2]
Uploading the swagger.json to S3
Modify index.html to point at your swagger.json
These steps are laid out in detail in the Medium article. [1]
References
[1] https://medium.com/nirman-tech-blog/swagger-ui-for-aws-api-gateway-endpoints-a667f25f5a4b
[2] https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-export-api.html
You can easily host self-contained swagger-UI web site in S3.
Here is an example: https://iris-fhir-server.s3.amazonaws.com/swagger-ui.html
Github: https://github.com/intersystems-community/Swagger-IRIS-FHIR
It's essentially your OpenAPI yaml or json files plus single HTML page like:
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link rel="stylesheet" type="text/css" href="https://unpkg.com/swagger-ui-dist#3/swagger-ui.css" >
<style>
html
{
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*,
*:before,
*:after
{
box-sizing: inherit;
}
body
{
margin:0;
background: #fafafa;
}
.errors-wrapper {
display: none !IMPORTANT;
}
</style>
</head>
<body>
<div id="swagger-ui"></div>
<script src="https://unpkg.com/swagger-ui-dist#3/swagger-ui-bundle.js"> </script>
<script src="https://unpkg.com/swagger-ui-dist#3/swagger-ui-standalone-preset.js"> </script> <script>
window.onload = function() {
// Begin Swagger UI call region
const ui = SwaggerUIBundle({
"dom_id": "#swagger-ui",
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout",
validatorUrl: "https://validator.swagger.io/validator",
//url: "https://iris-fhir-server.s3.amazonaws.com/openapi/Patient.yml",
urls: [
{url: "https://iris-fhir-server.s3.amazonaws.com/openapi/Organization.yml", name: "Organization"},
{url: "https://iris-fhir-server.s3.amazonaws.com/openapi/Patient.yml", name: "Patient"},
{url: "https://iris-fhir-server.s3.amazonaws.com/openapi/Practitioner.yml", name: "Practitioner"},
{url: "https://iris-fhir-server.s3.amazonaws.com/openapi/Condition.yml", name: "Condition"},
{url: "https://iris-fhir-server.s3.amazonaws.com/openapi/Medication.yml", name: "Medication"},
{url: "https://iris-fhir-server.s3.amazonaws.com/openapi/Observation.yml", name: "Observation"}
],
"urls.primaryName": "Patient"
})
window.ui = ui
}
</script>
</body>
</html>

ChartJS does not display when using local Chart.js file

I am having a problem getting Chart.js to display a Chart when using the Chart.min.js file that was installed as a result of using:
npm install chart.js --save (However, if use the CDN supplied file - the chart will display)
To avoid putting paths into my code, I copied the Chart.min.js file from the install directory: ./node_modules/chart_js/dist/Chart.min.js to the directory where my web page is. Was this the right file to copy? Anyways, when I reload the App into the Browser, I get a blank display. There are no error messages at all.
However, if I instead use the CDN supplied file: <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/0.2.0/Chart.min.js" type="text/javascript"></script>
Everything works. The Chart fully displays.
Here is the HTML file:
<html>
<head>
<meta charset="utf-8"/>
<title>Chart.js demo</title>
<script src="Chart.min.js" </script>
</head>
<body>
<h1>Chart.js Sample</h1>
<canvas id="countries" width="600" height="400"></canvas>
<script>
var pieData = [
{
value: 20,
color:"#878BB6"
},
{
value : 40,
color : "#4ACAB4"
},
{
value : 10,
color : "#FF8153"
},
{
value : 30,
color : "#FFEA88"
}
];
// Get the context of the canvas element we want to select
var countries= document.getElementById("countries").getContext("2d");
new Chart(countries).Pie(pieData);
</script>
</body>
</html>
So, what am I doing wrong? Is there an issue with the download?
Appreciate any help with this!
I am running on Mac OS X 10.10.5
I have tried this using both the Safari and FireFox browsers,
and have the same issue of the local Chart.min.js file not working.
You better use the latest syntax for creating your chart, instead of old one.
also, this is the correct directory where chart.js file resides, when installed through npm :
./node_modules/chart.js/dist/Chart.min.js
Here is the full code that works perfectly on Chrome, Firefox and Safari :
<html>
<head>
<meta charset="utf-8" />
<title>Chart.js demo</title>
<script src="./node_modules/chart.js/dist/Chart.min.js"></script>
</head>
<body>
<h1>Chart.js Sample</h1>
<div class="chart-container" style="width: 600px; height: 400px">
<canvas id="countries"></canvas>
</div>
<script>
var pieData = {
datasets: [{
data: [20, 40, 10, 30],
backgroundColor: ["#878BB6", "#4ACAB4", "#FF8153", "#FFEA88"]
}]
};
// Get the context of the canvas element we want to select
var countries = document.getElementById("countries").getContext("2d");
new Chart(countries, {
type: 'pie',
data: pieData
});
</script>
</body>
</html>
I think the problem must be the improper closing of the script tag. See below.
Before:
<script src="Chart.min.js" </script>
After:
<script src="Chart.min.js"></script>
Here is a demo with a local Chart.min.js File for your reference!
JSFiddle Demo

Create a map of Canada and USA with Datamaps in a single page

I am using Datamaps to create a map of Canada and USA. I saw the tutorial and/or examples in its website and I saw a "USA map only" example. And I did that:
<script>
var addUSA = new Datamap({
scope: 'usa',
element: document.getElementById('usa-map'),
geographyConfig: {
highlightOnHover: false,
borderColor: '#006298',
borderWidth: 0.8,
popupTemplate: function(geography, data) {
return "<div class='hoverinfo'><strong>" + data.info + "</strong></div>";
}
},
dataUrl: 'data.json',
dataType: 'json',
data: {},
fills: {
defaultFill: '#FFFFFF'
}
});
addUSA.labels();
</script>
So I assume that you can also create a "Canada map only". But the problem is, I don't know how to combine two countries.
I aim for labels, the hover-info and json that's why I'm using Datamaps.
So I've found this URL entitled Custom Map Data in Datamaps by Mark DiMarco and I used and tried copying what he had done. On that link, he created a map of Afghanistan which was not included in his main examples on Datamaps website. But instead of one country, we will combine two countries custom map using Datamaps. This is an experiment I've made but I hope this will be the answer to your problem
First, he created a custom topo json for Afghanistan. He published a tutorial on how to create custom map data but I think I don't have an access 'cause I'm getting 404 or he took it down. Going back, the code he used for that custom topo json can also be found in his other works located at "More Versions" link in Datamaps website. You just need to look for the country/ies you need to make a custom topo json. On your end, look for datamaps.afg.js and datamaps.usa.js; and get the json.
I only have 1 reputation and I am limit with two URLs. Just visit this GitHub site where I put those two custom topo json for Canada and USA.
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="style.css">
<title>Canada and USA</title>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://d3js.org/topojson.v1.min.js"></script>
<script src="http://rawgithub.com/markmarkoh/datamaps/master/dist/datamaps.none.min.js"></script>
<script src="script.js"></script>
</head>
<body>
<!-- CANADA -->
<h1>CANADA</h1>
<div id="canada"></div>
<!-- USA -->
<h1>USA</h1>
<div id="usa"></div>
</body>
</html>
CSS
#canada {
border: 1px solid #000000;
height: 450px;
width: 400px;
}
#usa {
border: 2px solid #EDA552;
height: 400px;
width: 500px;
}
JQUERY
$(function() {
var canadaMap = new Datamap({
element: document.getElementById('canada'),
geographyConfig: {
dataUrl: 'canada.topo.json'
},
scope: 'canada',
fills: {
defaultFill: '#bada55'
},
setProjection: function(element) {
var projection = d3.geo.mercator()
.center([-95, 71])
.scale(200)
.translate([element.offsetWidth / 2, element.offsetHeight / 2]);
var path = d3.geo.path().projection(projection);
return {path: path, projection: projection};
}
});
var USAmap = new Datamap({
element: document.getElementById('usa'),
geographyConfig: {
dataUrl: 'usa.topo.json'
},
scope: 'usa',
fills: {
defaultFill: '#bada55'
},
setProjection: function(element) {
var projection = d3.geo.mercator()
.center([-120, 54])
.scale(250)
.translate([element.offsetWidth / 2, element.offsetHeight / 2]);
var path = d3.geo.path().projection(projection);
return {path: path, projection: projection};
}
});
});
Working code here => JS FIDDLE