How can I show a LineLayer based on coordinates returned from an Azure Maps Traffic Flow Segment? - azure-maps

There is a good example for retrieving and showing traffic information using the /traffic/flow/tiles method, but not one for /traffic/flow/segment. The /traffic/flow/tiles example suggests using a VectorTileSource datasource, but it's not clear what the equivalent would be for a segment data (perhaps the DataSource object?)?
Does anyone know what would be the equivalent call to add a datasource based on the coordinates returned as part of the FlowSegmentData. For example, the way shown for traffic/flow/tiles is as follows:
datasource = new atlas.source.VectorTileSource(null, {
tiles: ['https://{azMapsDomain}/traffic/flow/tile/pbf?api-version=1.0&style=relative&zoom={z}&x={x}&y={y}'],
maxZoom: 22
});
map.sources.add(datasource);enter code here
What I'm ultimately trying to do is show LineLayer/animation based on results for a specified traffic flow segments.

The Traffic Flow Segment isn't a tile service, but a query service. You pass in a coordinate, and it returns a nearby road segment with traffic information. To use this you would first need to decide what coordinate you want to use to retrieve the traffic flow segment. Some ideas:
User clicks the map and you use that coordinate.
User does a search for an address, and you use that coordinate.
Use the center of the map (either after the map has moved or when user presses a button. Note that calling this after the map moves could result in a lot of transactions being created leading to high cost).
Assuming you are targeting a web app, you can use the fetch API to call this service. You can then take the response and create a LineString from the coordinates, then use that with a DataSource and LineLayer like any other simple LineString. Here is an example:
<!DOCTYPE html>
<html lang="en">
<head>
<title></title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<!-- Add references to the Azure Maps Map control JavaScript and CSS files. -->
<link href="https://atlas.microsoft.com/sdk/javascript/mapcontrol/2/atlas.min.css" rel="stylesheet" />
<script src="https://atlas.microsoft.com/sdk/javascript/mapcontrol/2/atlas.min.js"></script>
<script>
var map, datasource;
var coordinate = [-122.10565, 47.67498];
var flowSegmentStyle = 'relative'; //options: absolute, relative, relative-delay
var trafficFlowSegmentUrl = `https://{azMapsDomain}/traffic/flow/segment/json?api-version=1.0&style=${flowSegmentStyle}&zoom={zoom}&query={query}`;
function GetMap() {
//Initialize a map instance.
map = new atlas.Map('myMap', {
center: coordinate,
zoom: 14,
view: 'Auto',
authOptions: {
authType: 'subscriptionKey',
subscriptionKey: '[YOUR_AZURE_MAPS_KEY]'
}
});
//Wait until the map resources are ready.
map.events.add('ready', function () {
//Create a data source and add it to the map.
datasource = new atlas.source.DataSource();
map.sources.add(datasource);
//Create a line layer and add logic to determine how to style it.
map.layers.add(new atlas.layer.LineLayer(datasource, null, {
strokeWidth: 6,
//Color the segment based on the current speed (you can pick some other logic or a use a solid color)
strokeColor: [
'interpolate',
['linear'],
['get', 'currentSpeed'],
0, "green",
35, "yellow",
70, "red"
]
}));
//Retrieve a traffic flow segment.
var url = trafficFlowSegmentUrl.replace('{zoom}', Math.ceil(map.getCamera().zoom)).replace('{query}', `${coordinate[1]},${coordinate[0]}`);
processRequest(url).then(r => {
//Turn the cooridnate information into an array of positions.
var positions = [];
r.flowSegmentData.coordinates.coordinate.forEach(c => {
positions.push([c.longitude, c.latitude]);
});
//Create a LineString feature with the positions and retain the segment data as properies. Add the feature to the data source.
datasource.add(new atlas.data.Feature(new atlas.data.LineString(positions), r.flowSegmentData));
});
});
}
//This is a helper function that sets the domain of the request to the same one used by the map (Azure Maps is available in different Azure clouds with different domains e.g. Azure gov cloud).
//This also uses the same authenication as the map, making it easy, regardless of the type of auth you use (key or Azure AD).
function processRequest(url) {
//This is a reusable function that sets the Azure Maps platform domain, sings the request, and makes use of any transformRequest set on the map.
return new Promise((resolve, reject) => {
//Replace the domain placeholder to ensure the same Azure Maps cloud is used throughout the app.
url = url.replace('{azMapsDomain}', atlas.getDomain());
//Get the authentication details from the map for use in the request.
var requestParams = map.authentication.signRequest({ url: url });
//Transform the request.
var transform = map.getServiceOptions().tranformRequest;
if (transform) {
requestParams = transform(url);
}
fetch(requestParams.url, {
method: 'GET',
mode: 'cors',
headers: new Headers(requestParams.headers)
})
.then(r => r.json(), e => reject(e))
.then(r => {
resolve(r);
}, e => reject(e));
});
}
</script>
</head>
<body onload="GetMap()">
<div id="myMap" style="position:relative;width:100%;height:600px;"></div>
</body>
</html>

Related

Pre-render data into SPA application

I've created a .NET Core Web API that uses SPA with React. I want to preload some data into the application.
My startup.cs file looks like this:
app.UseSpa(spa => {
spa.Options.SourcePath = "ClientApp";
spa.UseSpaPrerendering(options => {
options.BootModulePath = $"main.chunk.js";
options.SupplyData = (context, data) => {
data["siteConfiguration"] = "{my custom object}";
};
});
if (env.IsDevelopment()) {
spa.UseReactDevelopmentServer(npmScript: "start");
}
});
I'm getting an error about the BootModulePath is not being found.
Couldn't find any information about this property used with React or how to pre-render data into React SPA with .NET Core.
Is there an example on how to accomplish this?
Thanks
I'm using a bit of a different approach to accomplish this. I am using spa services in .net core https://learn.microsoft.com/en-us/aspnet/core/client-side/spa-services?view=aspnetcore-2.2#server-prerendering to do my pre rendering. I am also using razor pages to generate the html page (with just a single div for react to mount to). All I need to do is add a tag on my root div in my Index.cshtml page that looks something like this:
<div id="react-app" asp-prerender-module="ClientApp/dist/main-server">Loading...</div>
The entry point for my main-server bundle looks like:
export default createServerRenderer(params => {
//do stuff here
return new Promise<RenderResult>((resolve, reject) => {
params.domainTasks.then(() => {
resolve({
html: /* html string rendered by your app */,
globals: {
cachedVar1: data1,
cachedVar2: data2
}
});
}, reject); // Also propagate any errors back into the host application
});
});
This lets me pre-load data that was created by node during the pre-rendering by putting them in global variables in JavaScript.
If you want to pre-load data that comes from the .net core server and not from node, then what you can do is to pass that data as part of your model to the view.
public async Task<IActionResult> Index()
{
//get data here
return View(preloadedData);
}
Then in the Index.cshtml page, you can add something like this:
<script>
var PRELOADED_CACHE = #Html.Raw(Json.Serialize(#Model));
</script>
This will put a global variable called PRELOADED_CACHE which you can access from your application in the browser (but won't be available during pre-rendering).
I know this isn't precisely what you are looking for, but hopefully this at least gives you some helpful ideas.

How to use server side rendering in order to add og meta-tags in react?

What I need is to change the content of og:title in a dynamic way into index.blade.php by using express server. As you know, the only way to change the content of the tags is by using server side rendering because facebook cannot read og tags if they added by react helmet component. So, here what I did:
Into index.balde.php I added these lines:
<meta property="og:title" content="$OG_TITLE">
<meta property="og:description" content="$OG_DESCRIPTION">
Then I created server.js file in order to change the content of the tags dynamically through the server:
var express = require('express');
var app = express();
const path = require('path');
const fs = require('fs')
app.get('/profile', function(request, response) {
console.log("Entered the logic");
const filePath = path.resolve(__dirname, '../views', 'index.blade.php');
// read in the index.html file
fs.readFile(filePath, 'utf8', function (err,data) {
if (err) {
return console.log(err);
}
let result = null;
// replace the special strings with server generated strings
data = data.replace(/\$OG_TITLE/g, 'PROFILE TITLE');
result = data.replace(/\$OG_DESCRIPTION/g, "PROFILE DESCRIPTIONS");
//result = data.replace(/\$OG_IMAGE/g, 'https://i.imgur.com/V7irMl8.png');
response.send(result);
});
});
app.listen(5000, function(){
console.log('listening on *:' + 5000);
});
As a result, when I open www.testurl.com:5000/profile The content of the tags have been changed successfully, but my problem is how to make the content of the tags changed without need to add the port number in url, since the requested link should be without the port number. The user does not need to add port number into the URL.
Is there anyway in react/express to let the server know that when user call www.testurl.com/profile all event listener in the server on port 500 should be called (on other way when access the url without port number app.get('/profile',...) should be called)? Or there is a way to call the url with port number into the basic component to make the event each time user open any page inside the app?
I am really need a help, since i spent a lot of time in order to find a solution. Thanks.

How to get a tensor from an image

I have an image and I would like to get the tensor from it.
Some of the images are already on the frontend server be whereas others will be served by the server
To do that, one needs to use fromPixels
In case the image is already displayed in an html page
You can consider doing a querySelector to get the image first and then you can use fromPixels
html
<img id="my-image" src="mydata.jpg">
js
const image = document.querySelector("#my-image")
const t = tf.fromPixels(image)
If the image is not present in the html page, you can use the constructor Image to create it and then pass it as parameter to fromPixels
const im = new Image()
im.onload = () => {
const a = tf.fromPixels(im, 4)
a.print()
console.log(a.shape)
}
im.src = "url-of-the-image"
document.body.appendChild(im)
onload makes sure that the image has finished downloading before converting it to a tensor.
If the image url and the url on which the frontend page is served are different there will be a cross-origin issue when creating the tensor. If the server serves the image with an access control that allows the frontend to retrieve that image, then setting the crossOrigin attribute of the image will solve the issue, otherwise there will nothing that can be done to get the tensor from that image.
const im = new Image()
im.crossOrigin = "anonymous";
im.src = "https://i.imgur.com/lVlPvCB.gif"
document.body.appendChild(im)
im.onload = () => {
const a = tf.fromPixels(im, 4)
a.print()
console.log(a.shape)
}
<html>
<head>
<!-- Load TensorFlow.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/tensorflow/0.12.4/tf.js"> </script>
</head>
<body>
</body>
</html>

Plaid: how to create public token in the front end (Ionic/angular) and send to server

I am follow this tutorial in order to get a transactions/accounts detail from the plaid API. Plaid'd quickstart guide user ejs in order to send to the server with the onSuccess function. How do I create this token using ionic?
Plaid quick guide also suggests that we use code blow
var linkHandler = Plaid.create({
env: 'sandbox',
clientName: 'Client Name',
key: '<PUBLIC_KEY>',
product: ['auth', 'transactions'],
token: '<GENERATED_PUBLIC_TOKEN>',
onSuccess: function(public_token, metadata) {
// You do not need to repeat the /item/public_token/exchange
// process when a user uses Link in update mode.
// The Item's access_token has not changed.
},
and also suggest to use this code
// Create a public_token for use with Plaid Link's update mode
client.createPublicToken(ACCESS_TOKEN, (err, result) => {
// Handle err
// Use the generated public_token to initialize Plaid Link in update
// mode for a user's Item so that they can provide updated credentials
// or MFA information
const publicToken = result.public_token;
});
in order to create a public token and get the access token. I can't use this function because I'm getting an error 'Plaid and/or client is not defined
How do I create this public token using Ionic front end and node back end?
What's the workflow here?
Thanks in advance
On the server side, you'll need to initialize the Plaid node client library first. You will also want to make an exchange token call, to exchange the public_token from Link for an API access_token. You'll then save the access_token and use it to retrieve transaction and account data:
// Initialize the Plaid API client with your API keys (https://dashboard.plaid.com/account/keys)
// Use plaid.environments.production, plaid.environments.development, or plaid.environments.sandbox
const plaid = require('plaid');
const client = new plaid.Client(client_id, secret, public_key, plaid.environments.sandbox);
client.exchangePublicToken(PUBLIC_TOKEN, function(error, tokenResponse) {
if (error != null) {
var msg = 'Could not exchange public_token!';
console.log(msg + '\n' + error);
}
const ACCESS_TOKEN = tokenResponse.access_token;
const ITEM_ID = tokenResponse.item_id;
console.log('Access Token: ' + ACCESS_TOKEN);
console.log('Item ID: ' + ITEM_ID);
// Now retrieve transactions or account information with the access_token
});
For the client-side in your Ionic app, you'll need to include the link-initialize.js script before calling Plaid.create. Specifically:
<script src="https://cdn.plaid.com/link/v2/stable/link-initialize.js">
</script>
Here's a full client-side HTML example:
<button id="link-button">Link Account</button>
<script src="https://cdn.plaid.com/link/v2/stable/link-initialize.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.js"></script>
<script type="text/javascript">
var handler = Plaid.create({
clientName: 'Plaid Walkthrough Demo',
env: 'sandbox',
key: '[PUBLIC_KEY]', // public_key is at https://dashboard.plaid.com/account/keys
product: ['auth'],
onLoad: function() {
// Optional, called when Link loads
},
onSuccess: function(public_token, metadata) {
// Send the public_token to your app server.
// The metadata object contains info about the institution the
// user selected and the account ID, if `selectAccount` is enabled.
$.post('/get_access_token', {
public_token: public_token,
});
},
onExit: function(err, metadata) {
// The user exited the Link flow.
}
});
</script>
An Angular library was recently created: click here and here
I had some issues implementing Plaid successfully at first; these tips should help:
Implement the library as shown in the second link above. Make sure for step two you import in your app.module.ts file. Don't use the jQuery provided in the documentation.
Using this library, a button will be automatically created within the Angular element <mr-ngx-plaid-link-button>. This button will act as a submit button unless you use DOM or other methods to change it to type button on ngAfterViewInit()
All five events in step three are listeners for various events. The onSuccess() callback will return the public token - only after you have (a) successfully submitted bank credentials (user_good / pass_good on Sandbox) and (b) clicked the Continue button to exit the Plaid Link

Google Tag Manager Data layer events missing data

We've implemented a data layer connection between Google Tag Manager and Google Analytics. Through Custom dimension however, we see over 3.000 events and only 17 records showing the data layer's data. How come there's a lot of missing data and how do you retrieve all event data?
<script type="text/javascript">
dataLayer = [];
</script>
<!-- Google Tag Manager (...) /-->
if user logs in:
dataLayer.push({
'fb_id': response.id,
'fb_email': response.email,
'fb_name': response.name,
'fb_first_name': response.first_name,
'fb_last_name': response.last_name,
'fb_gender': response.gender,
'fb_link': response.link,
'fb_locale': response.locale,
'fb_timezone': response.timezone,
'event': 'fb_login',
});

Resources