Bing Maps - Can't set a custom map style - maps

I'm trying to use a custom style on my map, but no matter what I do, I can't them them working. My initialize function is:
this.init = (mapSelector, api, title = '', poi = false, prefix = '', cache = true) => {
return new Promise((r, j) => {
if (api.slice(-1) !== '/')
this.setPrefix(prefix);
this.setCache(cache);
this.setPOI(poi);
this.setTitle(title);
try {
getMapKey().then(key => {
if(mapSelector) {
_map = new Microsoft.Maps.Map(mapSelector, {
credentials: key,
center: new Microsoft.Maps.Location(_latitude, _longitude),
zoom: 13,
disableBirdseye: true,
disableStreetside: true,
showDashboard: false,
customMapStyle: JSON.parse(sampleStyle),
});
} else {
j('error');
}
});
} catch (error) {
console.log(error);
}
});
};
It currently renders the standard map just fine. but no matter what I pass into customMapStyle nothing works, JSON.parse was added to make sure the data was in JSON format, because I'm running out of ideas.. I've copied the JSON from the examples on:
https://bingmapsv8samples.azurewebsites.net/#Set%20Custom%20Map%20Style
Some of the styles I've tried to use are:
const darkMode = {
"version": "1.0",
"settings": {
"landColor": "#0B334D"
},
"elements": {
"mapElement": {
"labelColor": "#FFFFFF",
"labelOutlineColor": "#000000"
},
"political": {
"borderStrokeColor": "#144B53",
"borderOutlineColor": "#00000000"
},
"point": {
"iconColor": "#0C4152",
"fillColor": "#000000",
"strokeColor": "#0C4152"
},
"transportation": {
"strokeColor": "#000000",
"fillColor": "#000000"
},
"highway": {
"strokeColor": "#158399",
"fillColor": "#000000"
},
"controlledAccessHighway": {
"strokeColor": "#158399",
"fillColor": "#000000"
},
"arterialRoad": {
"strokeColor": "#157399",
"fillColor": "#000000"
},
"majorRoad": {
"strokeColor": "#157399",
"fillColor": "#000000"
},
"railway": {
"strokeColor": "#146474",
"fillColor": "#000000"
},
"structure": {
"fillColor": "#115166"
},
"water": {
"fillColor": "#021019"
},
"area": {
"fillColor": "#115166"
}
}
};
const sampleStyle = {
"elements": {
"park": { "fillColor": "#A9A9D4BE" },
"controlledAccessHighway": { "fillColor": "#e6c317", "strokeColor": "#D3B300", "labelColor": "#444444", "labelOutlineColor": "#60ffffff" },
"highway": { "fillColor": "#e6c317", "strokeColor": "#D3B300", "labelColor": "#444444", "labelOutlineColor": "#60ffffff" },
"water": { "fillColor": "#B7CDDE" },
"medicalBuilding": { "fillColor": "#fceced" },
"majorRoad": { "fillColor": "#f0d85a" },
"education": { "fillColor": "#f0e8f8" },
"arterialRoad": { "fillColor": "#ffed91" },
"structure": { "fillColor": "#faf8ed" },
"buildinglobal": { "fillColor": "#e5e0d8" },
"forest": { "fillColor": "#deebdd" },
"vegetation": { "fillColor": "#deebdd" },
"reserve": { "fillColor": "#deebdd" },
"street": { "fillColor": "#ffffff", "strokeColor": "#e6e3df" },
"roadShield": { "fillColor": "#ffffff" },
"medical": { "fillColor": "#ffddee" },
"educationBuildinglobal": { "fillColor": "#f6f0f1" },
"golfCourse": { "fillColor": "#c5dabb" }
},
"settings": { "landColor": "#F6F4E3" }
};
Does anyone know how to get a custom style activated? If that's not possible, is there a dark mode that I can activate, which is what I'm trying to do.
Thanks

I would suggest taking a look at the map style sheet editor app - it will allow you to interactively adjust the style and shows sample code for how to initialize that style in all of the Bing maps controls (HTML, UWP and Static maps).
https://www.microsoft.com/en-us/p/map-style-sheet-editor/9nbhtcjt72ft

I had to set setOption, it had nothing to do with the map style I was trying to apply.

Related

How to groupby a sub property inside a property?

I've got an object with multiple key holding an array of values. Inside that array, there is a nested value on which I want to group on, while maintaining the main key.
So in my data I've got:
{
"foo1": [
{
"name": "foo1",
"subpart": {
"part": "bar1"
}
},
{
"name": "foo1",
"subpart": {
"part": "bar1"
}
},
{
"name": "foo1",
"subpart": {
"part": "bar2"
}
},
{
"name": "foo1",
"subpart": {
"part": "bar2"
}
},
{
"name": "foo1",
"subpart": {
"part": "bar3"
}
},
{
"name": "foo1",
"subpart": {
"part": "bar3"
}
}
],
"foo2": [
{
"name": "foo2",
"subpart": {
"part": "bar1"
}
},
{
"name": "foo2",
"subpart": {
"part": "bar1"
}
},
{
"name": "foo2",
"subpart": {
"part": "bar2"
}
},
{
"name": "foo2",
"subpart": {
"part": "bar3"
}
},
{
"name": "foo2",
"subpart": {
"part": "bar3"
}
}
]
}
and I want it to become:
{
"foo1": {
"bar1": [
{
"name": "foo1",
"subpart": {
"part": "bar1"
}
},
{
"name": "foo1",
"subpart": {
"part": "bar1"
}
}
],
"bar2": [
{
"name": "foo1",
"subpart": {
"part": "bar2"
}
},
{
"name": "foo1",
"subpart": {
"part": "bar2"
}
}
],
"bar3": [
{
"name": "foo1",
"subpart": {
"part": "bar3"
}
},
{
"name": "foo1",
"subpart": {
"part": "bar3"
}
}
]
},
"foo2": {
"bar1": [
{
"name": "foo2",
"subpart": {
"part": "bar1"
}
},
{
"name": "foo2",
"subpart": {
"part": "bar1"
}
}
],
"bar2": [
{
"name": "foo2",
"subpart": {
"part": "bar2"
}
}
],
"bar3": [
{
"name": "foo2",
"subpart": {
"part": "bar3"
}
},
{
"name": "foo2",
"subpart": {
"part": "bar3"
}
}
]
}
}
Right now I've found some examples, but that only does grouping on just one level, where they 'key' is the first group, but I've got a second property in some subvalue to be the second level of grouping (if that makes any sense).
Best I've got so far is:
function groupBy<T>(arr: T[], fn: (item: T) => any) {
return arr.reduce<Record<string, T[]>>((prev, curr) => {
const groupKey = fn(curr);
const group = prev[groupKey] || [];
group.push(curr);
return { ...prev, [groupKey]: group };
}, {});
}
and then:
const grouped = groupBy(data, (x) => x.subpart.part)
But that groups it into a main key which I don't want.
Essentially you need to map groupBy over each value in data.
Mapping over objects is somewhat difficult/not straight-forward in TypeScript. What you can do is using Object.entries and Object.fromEntries to convert the object to an array first, map it and convert it back to an object. doing this, however, breaks type inference and makes the result of type any. So be careful when you need to do this while maintaining type-safety.
You might also want to consider refactoring your code such that an array-based structure is used as input and/or output for this transformation, as its easier to work with, and easier to maintain type-safety with.
const data = { "foo1": [...], ...}
const dataArr = Object.entries(data);
const mappedArr = dataArr.map(([k,v]) => [k, groupBy(v, (x) => x.subpart.part)]);
const result = Object.fromEntries(mappedArr);
TS Playground

Convert React class component to React Hook

Im trying to convert the following code to react hook component, but I don't understand how to convert the onOrderChange and the consts in the render parts to react hooks, how do I go about this? My goal is to have a drag and drop-able react checkbox tree component but I'm unable to convert the drag and drop part to react hooks, the other parts are in react hooks.
import React from 'react';
import CheckboxTree from 'react-checkbox-tree-reorderable';
const nodesData = './data.json'
class BasicExample extends React.Component {
state = {
nodes: nodesData,
checked:[],
expanded: [],
};
constructor(props) {
super(props);
this.onCheck = this.onCheck.bind(this);
this.onExpand = this.onExpand.bind(this);
}
onCheck(checked) {
this.setState({ checked });
}
onExpand(expanded) {
this.setState({ expanded });
}
onOrderChange = (orderedNodes) => {
this.setState({
nodes: orderedNodes,
});
}
render() {
const { onOrderChange, state } = this;
const { checked, expanded, nodes } = state;
return (
<CheckboxTree
checked={checked}
expanded={expanded}
iconsClass="fa5"
nodes={nodes}
onCheck={this.onCheck}
onExpand={this.onExpand}
orderable
onOrderChange={onOrderChange}
/>
);
}
}
export default BasicExample;
This is my data.json file
[
{
"value": "polygon",
"label": "Polygon",
"type": "parent",
"children": [
{
"value": "ward",
"label": "Ward",
"type": "fill",
"source": {
"type": "geojson",
"data": "/Ward.json"
},
"id": "ward",
"paint": {
"fill-color": "red",
"fill-opacity": 0.2
},
"layout": {
"visibility": "none"
},
"filter": [
"all"
]
},
{
"value": "zone",
"label": "Zone",
"type": "fill",
"source": {
"type": "geojson",
"data": "/Zone.json"
},
"id": "zone",
"paint": {
"fill-color": "blue",
"fill-opacity": 0.2
},
"layout": {
"visibility": "none"
},
"filter": [
"all"
]
}
]
},
{
"value": "line",
"label": "Line",
"type": "parent",
"children": [
{
"value": "path",
"label": "Path",
"type": "parent",
"children": [
{
"value": "roads",
"label": "Roads",
"type": "line",
"source": {
"type": "geojson",
"data": "/Roads.json"
},
"id": "roads",
"paint": {
"line-color": "orange"
},
"layout": {
"visibility": "none"
},
"filter": [
"all"
]
},
{
"value": "footpaths",
"label": "Footpaths",
"type": "line",
"source": {
"type": "geojson",
"data": "/Footpaths.json"
},
"id": "footpaths",
"paint": {
"line-color": "pink"
},
"layout": {
"visibility": "none"
},
"filter": [
"all"
]
}
]
},
{
"value": "drainage",
"label": "Drainage",
"type": "parent",
"children": [
{
"value": "waste",
"label": "Waste",
"type": "line",
"source": {
"type": "geojson",
"data": "/Waste.json"
},
"id": "waste",
"paint": {
"line-color": "brown"
},
"layout": {
"visibility": "none"
},
"filter": [
"all"
]
},
{
"value": "storm",
"label": "Storm",
"type": "line",
"source": {
"type": "geojson",
"data": "/Storm.json"
},
"id": "storm",
"paint": {
"line-color": "green"
},
"layout": {
"visibility": "none"
},
"filter": [
"all"
]
}
]
}
]
}
]
Refer this and go through the code below..
https://olinations.medium.com/10-steps-to-convert-a-react-class-component-to-a-functional-component-with-hooks-ab198e0fa139
import React, { useState } from "react";
import CheckboxTree from "react-checkbox-tree-reorderable";
const nodesData = "./data.json";
const BasicExample = () => {
const [checked, setChecked] = useState("");
const [expanded, setExpand] = useState("");
const [nodes, setOrderNodes] = useState(nodesData);
const onCheck = (checked) => setChecked(checked);
const onExpand = (expanded) => setExpand(expanded);
const onOrderChange = (orderedNodes) => setOrderNodes(orderedNodes);
return (
<CheckboxTree
checked={checked}
expanded={expanded}
iconsClass="fa5"
nodes={nodes}
onCheck={onCheck}
onExpand={onExpand}
orderable
onOrderChange={onOrderChange}
/>
);
};
export default BasicExample;

react-portal loads data then doesn't re-render

I have been trying to render ParticleJS as a background to the root div of my create-react-app and I have had success of it loading initially, but when changing routes and then visiting the homepage again, the particlejs is gone. Below is my configuration, please let me know if there is something I am missing.
import React, { Component } from 'react';
import { Portal } from 'react-portal';
import Particles from 'react-particles-js';
class Particle extends Component {
render() {
return (
<Portal node={document && document.getElementById('root')}>
<div id="particles">
<Particles
params={{
particles: {
number: {
value: 20,
density: {
enable: true,
value_area: 800
}
},
color: {
value: "#ffffff"
},
shape: {
type: "circle",
stroke: {
width: 0,
color: "#000000"
},
},
"polygon": {
"nb_sides": 5
},
"image": {
"src": "",
"width": 100,
"height": 100
},
"opacity": {
"value": 0.6,
"random": false,
"anim": {
"enable": false,
"speed": 1,
"opacity_min": 0.5,
"sync": false
}
},
"size": {
"value": 3,
"random": true,
"anim": {
"enable": false,
"speed": 40,
"size_min": 0.1,
"sync": false
}
},
"line_linked": {
"enable": true,
"distance": 150,
"color": "#FFFFFF",
"opacity": 0.6,
"width": 1
},
"move": {
"enable": true,
"speed": 4,
"direction": "none",
"random": false,
"straight": false,
"out_mode": "out",
"bounce": false,
"attract": {
"enable": false,
"rotateX": 600,
"rotateY": 1200
}
},
"interactivity": {
"detect_on": "canvas",
"events": {
"onhover": {
"enable": true,
"mode": "repulse"
},
"onclick": {
"enable": true,
"mode": "push"
},
"resize": true
},
"modes": {
"grab": {
"distance": 400,
"line_linked": {
"opacity": .6
}
},
"bubble": {
"distance": 400,
"size": 40,
"duration": 2,
"opacity": 8,
"speed": 3
},
"repulse": {
"distance": 200,
"duration": 0.4
},
"push": {
"particles_nb": 4
},
"remove": {
"particles_nb": 2
}
}
},
"retina_detect": true
}
}} />
</div>
</Portal>
);
}
}
export default Particle;
And I have this for the following component to render this file
class HomePage extends Component {
componentWillMount() {
window.scrollTo(0,0);
}
render() {
return (
<ScrollAnimation animateIn='fadeIn'>
<Particles/>
</ScrollAnimation>
Is there something I should be doing to re-render this?
Ah.... It was CSS, did not realize the background of particles was being affected.

Angular states not showing amcharts after switching back to that state

I have two charts divs in html which I am able to display first time. but when my state changes and I come back to the state where I displayed charts. Then charts are not shown. I think I have to re-attach the dataProvider and render it again but i don't know how.
this is my controller
.controller('HomeCtrl', function ($location,$window) {
AmCharts.makeChart("chartdiv-pie", {
"type": "pie",
"theme": "light",
"dataProvider": [{
"title": "20%",
"value": 3852,
"color": "#18aa9f"
}, {
"title": "40%",
"value": 3899,
"color": "#e65548"
},
{
"title": "40%",
"value": 4899,
"color": "#e1e3e4"
}
],
"title": "AmCharts",
"color": "black",
"titleField": "title",
"valueField": "value",
"radius": "25%",
"outlineAlpha":0,
"innerRadius": "40%",
"balloonText": "[[value]]",
"labelText": "[[title]]",
"labelsEnabled": true,
"colorField": "color",
"labelText": "[[title]]",
"export": {
"enabled": true
},
});
var chart = AmCharts.makeChart( "chartdiv-male", {
"type": "serial",
"addClassNames": true,
"theme": "light",
"autoMargins": false,
"marginLeft": 30,
"marginRight": 8,
"marginTop": 10,
"marginBottom": 26,
"balloon": {
"adjustBorderColor": false,
"horizontalPadding": 10,
"verticalPadding": 8,
"color": "#ffffff"
},
"dataProvider": [ {
"year": "Pos",
"income": 30.1,
"color": "#FF0F00",
"expenses": 34.9,
}, {
"year": "Neg",
"income": 29.5,
"expenses": 31.1
}, {
"year": "Neu",
"income": 30.6,
"expenses": 28.2,
"dashLengthLine": 5,
"columnColor": 'green'
} ],
"valueAxes": [ {
"axisAlpha": 0,
"position": "left"
} ],
"startDuration": 1,
"graphs": [ {
"alphaField": "alpha",
"balloonText": "<span style='font-size:12px;'>[[title]] in [[category]]:<br><span style='font-size:20px;'>[[value]]</span> [[additional]]</span>",
"fillAlphas": 1,
"title": "Income",
"type": "column",
"valueField": "income",
"dashLengthField": "dashLengthColumn"
}, ],
"categoryField": "year",
"categoryAxis": {
"gridPosition": "start",
"axisAlpha": 0,
"tickLength": 0
},
"export": {
"enabled": true
}
} );
}
these are my states
.state('home.stats', {
url:'/stats',
templateUrl: 'views/stats.html',
controller: 'StatsCtrl',
controllerAs: 'stats'
})
.state('home.posts', {
url:'/posts',
templateUrl: 'views/posts.html',
controller: 'PostsCtrl',
controllerAs: 'posts'
});

Google map fitBounds not working

I am creating a trip view using google map with angularjs directive. All works fine except the google map fitbound to a latitude longitude collection.
I have tried all the way to use the fitbounds methods but failed.
Thanks,
Below is my code efforts.
Directive:
<div class="trip-google-map" trip-map="" mapid="2" latitude="22.998673" longitude="72.514346"></div>
Directive Code:
app.directive('tripMap', function ($compile) {
return {
controller: function ($scope, $location, mapService) {
this.registerMap = function (myMap) {
mapService.setTripMap(myMap);
};
},
link: function (scope, elem, attrs, ctrl) {
var mapOptions,
latitude,
longitude,
mapStyles,
map;
latitude = attrs.latitude;
longitude = attrs.longitude;
mapStyles =
[
{
"featureType": "water",
"elementType": "geometry",
"stylers": [
{
"color": "#a2daf2"
}
]
},
{
"featureType": "landscape.man_made",
"elementType": "geometry",
"stylers": [
{
"color": "#f7f1df"
}
]
},
{
"featureType": "landscape.natural",
"elementType": "geometry",
"stylers": [
{
"color": "#d0e3b4"
}
]
},
{
"featureType": "landscape.natural.terrain",
"elementType": "geometry",
"stylers": [
{
"visibility": "on"
}
]
},
{
"featureType": "poi.park",
"elementType": "geometry",
"stylers": [
{
"color": "#bde6ab"
}
]
},
{
"featureType": "poi",
"elementType": "labels",
"stylers": [
{
"visibility": "on"
}
]
},
{
"featureType": "poi.medical",
"elementType": "geometry",
"stylers": [
{
"color": "#fbd3da"
}
]
},
{
"featureType": "poi.business",
"elementType": "all",
"stylers": [
{
"visibility": "on"
}
]
},
{
"featureType": "road",
"elementType": "geometry.stroke",
"stylers": [
{
"visibility": "on"
}
]
},
{
"featureType": "road",
"elementType": "labels",
"stylers": [
{
"visibility": "on"
}
]
},
{
"featureType": "road.highway",
"elementType": "geometry.fill",
"stylers": [
{
"color": "#ffe15f"
}
]
},
{
"featureType": "road.highway",
"elementType": "geometry.stroke",
"stylers": [
{
"color": "#efd151"
}
]
},
{
"featureType": "road.arterial",
"elementType": "geometry.fill",
"stylers": [
{
"color": "#ffffff"
}
]
},
{
"featureType": "road.local",
"elementType": "geometry.fill",
"stylers": [
{
"color": "black"
}
]
},
{
"featureType": "transit.station.airport",
"elementType": "geometry.fill",
"stylers": [
{
"color": "#cfb2db"
}
]
}
];
mapOptions = {
zoom: 12,
disableDefaultUI: true,
center: new google.maps.LatLng(latitude, longitude),
mapTypeId: google.maps.MapTypeId.ROADMAP,
styles: mapStyles,
mapTypeControl: true,
mapTypeControlOptions: {
style: google.maps.MapTypeControlStyle.HORIZONTAL_BAR,
position: google.maps.ControlPosition.BOTTOM_CENTER
},
panControl: true,
panControlOptions: {
position: google.maps.ControlPosition.LEFT_CENTER
},
zoomControl: true,
zoomControlOptions: {
style: google.maps.ZoomControlStyle.LARGE,
position: google.maps.ControlPosition.LEFT_CENTER
},
scaleControl: true,
streetViewControl: true,
streetViewControlOptions: {
position: google.maps.ControlPosition.LEFT_CENTER
},
};
/*
var mapOptions = {
mapTypeId: google.maps.MapTypeId.ROADMAP,
mapTypeControl: false
};
*/
//google.maps.visualRefresh = true;
var map = new google.maps.Map(elem[0], mapOptions);
ctrl.registerMap(map);
scope.InitializeTripdetailController();
scope.$apply(function () {
window.setTimeout(function () {
google.maps.event.trigger(map, 'resize');
}, 100);
});
}
};
});
Controller Code:
app.controller('tripdetailController', ['$scope', '$rootScope', '$timeout', 'mapService', 'ngDialog', function ($scope, $rootScope, $timeout, mapService, ngDialog) {
$scope.tripPathPolylines = [];
var trips = [];
var insertTripLatlng = function (trip) {
var isExists = false;
for (var v in trips) {
if (trips[v].hash == trip.hash) {
isExists = true
break;
}
}
if (isExists == false) {
trips.push(trip);
}
}
function settrip() {
var marker;
var tripmap = mapService.getTripMap();
var bounds = new google.maps.LatLngBounds();
for (var j = 0; j < trips.length; j++) {
var ltlng = new google.maps.LatLng(trips[j].lat, trips[j].lng);
bounds.extend(ltlng);
marker = new google.maps.Marker({
position: ltlng,
map: tripmap
});
}
tripmap.fitBounds(bounds);
}
$scope.InitializeTripdetailController = function () {
var tripData = $scope.$parent.ngDialogData;
for (var p = 0; p < tripData.messages.length; p++) {
insertTripLatlng({ lat: tripData.messages[p].trackPoint.pos.lat, lng: tripData.messages[p].trackPoint.pos.lng, hash: tripData.messages[p].trackPoint.pos.lat + "-" + tripData.messages[p].trackPoint.pos.lng })
}
settrip();
}
}]);
FitBounds Code:
var tripmap = mapService.getTripMap();
var bounds = new google.maps.LatLngBounds();
for (var j = 0; j < trips.length; j++) {
var ltlng = new google.maps.LatLng(trips[j].lat, trips[j].lng);
bounds.extend(ltlng);
marker = new google.maps.Marker({position: ltlng,map: tripmap});
}
tripmap.fitBounds(bounds);
The map looks like:
It should be after fitbounds as:
Update: css for map:
Update: The map is loaded in ngDialog popup.
.trip-google-map {
width: 100%;
height: 450px;
}
It was due to map is resized by ngDialog popup directive.
Solved by call fitbounds in map resize callback with as
$scope.$apply(function () {
window.setTimeout(function () {
google.maps.event.trigger(tripmap, 'resize');
tripmap.fitBounds(bounds);
}, 100);
});
Thanks all for help.

Resources