Skip to content

Instantly share code, notes, and snippets.

@deldersveld
Last active May 9, 2017 19:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save deldersveld/4b9d8f50af8fdf9651175c6200544a57 to your computer and use it in GitHub Desktop.
Save deldersveld/4b9d8f50af8fdf9651175c6200544a57 to your computer and use it in GitHub Desktop.
/*
double #map required for map to appear in FF,Edge,IE (and I have no idea why)
final map should appear as fixed 60% width
fixed for scrolling story pane
top 55px because it covers up the Export button in DevTools...
*/
#map {
position:absolute;
top:20px;
bottom:0;
width:100%;
}
/*BlueGranite Logo*/
div.blue-granite-logo {
position:fixed;
bottom:0;
width:25px;
height:25px;
z-index:1;
background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAYAAADE6YVjAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAEnQAABJ0Ad5mH3gAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuOWwzfk4AAAUBSURBVEhLnVbrTxRXFN8P7szOa5fHAiK7CLjaVAJIeYiPRq22NHatom3sQ1YtCYkxtWgFyc4OUxW/tE18lDZFgWqbFGUB15Ui9KsmpkkfISaNG6IfRP6JCv567swsO6OG2J7kZO6eOff3u+d3z9y7rpexjWduVBadiO9bGk3o3o6knh8d1ZdGhyJrz/xcaaX8PwvrvWIglmz3qeMp5Wgc0gdfQmw8CnHrIQjsSb+VtjiyYxMPC7VEZw3lW1NfzkqiVxtztIlZZd/XkFdtAOeRwXMi3JxA7sES3gOOxhzvhXfleng/+grZ6vhsSI+HLYjFLaiOdiqfJyBXvGUCkjNABszGy4qCqKyqhJvnKMYZOW5egFK+Bd624blSffyUBfViC8SutXs/HYSnIGRMZuAGiM3/+PMvPHnyBFVV1Zk4kXAcD6GgFL7DV1DyRUK3IJ1WfvJmo3IsMScuXekAfdYvXurDvXv3UBQIPveOI5fyQ/AdG0ZZ7Op2C9q0TfoPnuzo+EOpcjutyjkxPXlNdTVycvNoH8xVZ97xFLOPeSgV2+BTx2bCejLTDEF1+JB04DwRiKT78xLVr23AzMwMduzY6Yi/9/5ePHr0CLuamgzydJynsbzvPILRoTaLwuXK1San5PJtlPACgvp6gyASiRgV2d+dPHUa8/PzUGOaI85cfHUTcqKTKYOgXh8JeDsS8Ai5jiQGWFe/Fo8fP0Zzc/MzEnkgy16IkoL1GzbSU16ILyxE8EE5nkCD/mPItTI2uFuKfAvBnSFgXltXlyEgne3vdF3H5ctXHBLJig+nu7uxZ88eI84TnvzxWQTU0Q9dhdr1NmFnjBJ52g8TrLa2LiORrRFYNYzg/v37KC1dsRBnvmXLVsw/fYoHDx4YJJxbgBjuQFC7GXUFupI6/85xs9cJsGHdeqOCSGQ//WbdwuKmmwQplJWVGbnpONtoieSLaRo1x7tmnIilN4/A3zmku4o7bx3x7I5RUMS6dQ2YnZ11VGCCeNDV1WVUwAjsFeTl5eHChW/gy8oxctNx9iHL4RMIqslOIomHpU96oNBKpqamsH//gQUCM5mHZhGUljGJ0vvDw08Ed+7cQV9fP3gPO9ts80guqfksStTBvS46rgt8HWPgpFz4c/3O1dCYVZBKmRLZQRjB7du30d/fT535fOu7xSx4qbuq1Z7lRhtnxX65q1S+bVRg6GmTaHp6GqGQedQY7+jp9/ttBNLCHOZsb5lLqzcjJzYxZRAwC3UNtvhaLlIS63dzVcfb220EpkQGQV7+4hVQ7hKPBPlAD/KjQ60WhcvV2vu7O1ubSHlr6HiwkmtqaonAPI3T7vfbJXLuwYKTAnJ1GFnq5HRNa6/bojBteXSkwdd+fU4oroDbk5Yt82RdxAgGBgYMArtEaWcSi8vKwXBWnx55w4J2Wol2o9Xbdg1CoMK6rMzVZSoYgCA6K2B56QrEIBF8dhXLukYOW5AvtuV0IsvtiX+Uut0Q6NplK6xaU41z584RgeQgMElov6h9pdeaQGfgXLGaWJwgbatODm/Iio7/7W25BLmqEbycbUjB0VVg3O30DbCPl5f9dE1vhdzyPSg/9Yoe32xBvJyxZgioiYPZ6q27vhNjkA9+B6lJo6+4A9IuDeLBHtL+Jv1b+fW3YnW4pab3mU3+r9bYPVJYGhsNF0UTR0KnknqBmjy8QovvfL37p0IrZRFzuf4FEuABqE86e1MAAAAASUVORK5CYII=');
}
/*mapbox-gl.css (v0.20.1)*/
.mapboxgl-map {
font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;
overflow: hidden;
position: relative;
-webkit-tap-highlight-color: rgba(0,0,0,0);
}
.mapboxgl-canvas-container.mapboxgl-interactive,
.mapboxgl-ctrl-nav-compass {
cursor: -webkit-grab;
cursor: -moz-grab;
cursor: grab;
}
.mapboxgl-canvas-container.mapboxgl-interactive:active,
.mapboxgl-ctrl-nav-compass:active {
cursor: -webkit-grabbing;
cursor: -moz-grabbing;
cursor: grabbing;
}
.mapboxgl-ctrl-top-left,
.mapboxgl-ctrl-top-right,
.mapboxgl-ctrl-bottom-left,
.mapboxgl-ctrl-bottom-right { position:absolute; }
.mapboxgl-ctrl-top-left { top:0; left:0; }
.mapboxgl-ctrl-top-right { top:0; right:0; }
.mapboxgl-ctrl-bottom-left { bottom:0; left:0; }
.mapboxgl-ctrl-bottom-right { right:0; bottom:0; }
.mapboxgl-ctrl { clear:both; }
.mapboxgl-ctrl-top-left .mapboxgl-ctrl { margin:10px 0 0 10px; float:left; }
.mapboxgl-ctrl-top-right .mapboxgl-ctrl{ margin:10px 10px 0 0; float:right; }
.mapboxgl-ctrl-bottom-left .mapboxgl-ctrl { margin:0 0 10px 10px; float:left; }
.mapboxgl-ctrl-bottom-right .mapboxgl-ctrl { margin:0 10px 10px 0; float:right; }
.mapboxgl-ctrl-group {
border-radius: 4px;
-moz-box-shadow: 0px 0px 2px rgba(0,0,0,0.1);
-webkit-box-shadow: 0px 0px 2px rgba(0,0,0,0.1);
box-shadow: 0px 0px 0px 2px rgba(0,0,0,0.1);
overflow: hidden;
background: #fff;
}
.mapboxgl-ctrl-group > button {
width: 30px;
height: 30px;
display: block;
padding: 0;
outline: none;
border: none;
border-bottom: 1px solid #ddd;
box-sizing: border-box;
background-color: rgba(0,0,0,0);
cursor: pointer;
}
/* https://bugzilla.mozilla.org/show_bug.cgi?id=140562 */
.mapboxgl-ctrl > button::-moz-focus-inner {
border: 0;
padding: 0;
}
.mapboxgl-ctrl > button:last-child {
border-bottom: 0;
}
.mapboxgl-ctrl > button:hover {
background-color: rgba(0,0,0,0.05);
}
.mapboxgl-ctrl-icon,
.mapboxgl-ctrl-icon > div.arrow {
speak: none;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.mapboxgl-ctrl-icon.mapboxgl-ctrl-zoom-out {
padding: 5px;
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg%20viewBox%3D%270%200%2020%2020%27%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%3E%0A%20%20%3Cpath%20style%3D%27fill%3A%23333333%3B%27%20d%3D%27m%207%2C9%20c%20-0.554%2C0%20-1%2C0.446%20-1%2C1%200%2C0.554%200.446%2C1%201%2C1%20l%206%2C0%20c%200.554%2C0%201%2C-0.446%201%2C-1%200%2C-0.554%20-0.446%2C-1%20-1%2C-1%20z%27%20%2F%3E%0A%3C%2Fsvg%3E%0A");
}
.mapboxgl-ctrl-icon.mapboxgl-ctrl-zoom-in {
padding: 5px;
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg%20viewBox%3D%270%200%2020%2020%27%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%3E%0A%20%20%3Cpath%20style%3D%27fill%3A%23333333%3B%27%20d%3D%27M%2010%206%20C%209.446%206%209%206.4459904%209%207%20L%209%209%20L%207%209%20C%206.446%209%206%209.446%206%2010%20C%206%2010.554%206.446%2011%207%2011%20L%209%2011%20L%209%2013%20C%209%2013.55401%209.446%2014%2010%2014%20C%2010.554%2014%2011%2013.55401%2011%2013%20L%2011%2011%20L%2013%2011%20C%2013.554%2011%2014%2010.554%2014%2010%20C%2014%209.446%2013.554%209%2013%209%20L%2011%209%20L%2011%207%20C%2011%206.4459904%2010.554%206%2010%206%20z%27%20%2F%3E%0A%3C%2Fsvg%3E%0A");
}
.mapboxgl-ctrl-icon.mapboxgl-ctrl-geolocate {
padding: 5px;
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg%20viewBox%3D%270%200%2020%2020%27%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%3E%3Cpath%20style%3D%27fill%3A%23333333%3B%27%20d%3D%27M13%2C7%20L10.5%2C11.75%20L10.25%2C10%20z%20M13.888%2C6.112%20C13.615%2C5.84%2013.382%2C6.076%2012.5%2C6.5%20C10.14%2C7.634%206%2C10%206%2C10%20L9.5%2C10.5%20L10%2C14%20C10%2C14%2012.366%2C9.86%2013.5%2C7.5%20C13.924%2C6.617%2014.16%2C6.385%2013.888%2C6.112%27%2F%3E%3C%2Fsvg%3E");
}
.mapboxgl-ctrl-icon.mapboxgl-ctrl-compass > div.arrow {
width: 20px;
height: 20px;
margin: 5px;
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2020%2020%27%3E%0A%09%3Cpolygon%20fill%3D%27%23333333%27%20points%3D%276%2C9%2010%2C1%2014%2C9%27%2F%3E%0A%09%3Cpolygon%20fill%3D%27%23CCCCCC%27%20points%3D%276%2C11%2010%2C19%2014%2C11%20%27%2F%3E%0A%3C%2Fsvg%3E");
background-repeat: no-repeat;
}
.mapboxgl-ctrl.mapboxgl-ctrl-attrib {
padding: 0 5px;
background-color: rgba(255,255,255,0.5);
margin: 0;
}
.mapboxgl-ctrl-attrib a {
color: rgba(0,0,0,0.75);
text-decoration: none;
}
.mapboxgl-ctrl-attrib a:hover {
color: inherit;
text-decoration: underline;
}
.mapboxgl-ctrl-attrib .mapbox-improve-map {
font-weight: bold;
margin-left: 2px;
}
.mapboxgl-popup {
position: absolute;
top: 0;
left: 0;
display: -webkit-flex;
display: flex;
will-change: transform;
pointer-events: none;
}
.mapboxgl-popup-anchor-top,
.mapboxgl-popup-anchor-top-left,
.mapboxgl-popup-anchor-top-right {
-webkit-flex-direction: column;
flex-direction: column;
}
.mapboxgl-popup-anchor-bottom,
.mapboxgl-popup-anchor-bottom-left,
.mapboxgl-popup-anchor-bottom-right {
-webkit-flex-direction: column-reverse;
flex-direction: column-reverse;
}
.mapboxgl-popup-anchor-left {
-webkit-flex-direction: row;
flex-direction: row;
}
.mapboxgl-popup-anchor-right {
-webkit-flex-direction: row-reverse;
flex-direction: row-reverse;
}
.mapboxgl-popup-tip {
width: 0;
height: 0;
border: 10px solid transparent;
z-index: 1;
}
.mapboxgl-popup-anchor-top .mapboxgl-popup-tip {
-webkit-align-self: center;
align-self: center;
border-top: none;
border-bottom-color: #fff;
}
.mapboxgl-popup-anchor-top-left .mapboxgl-popup-tip {
-webkit-align-self: flex-start;
align-self: flex-start;
border-top: none;
border-left: none;
border-bottom-color: #fff;
}
.mapboxgl-popup-anchor-top-right .mapboxgl-popup-tip {
-webkit-align-self: flex-end;
align-self: flex-end;
border-top: none;
border-right: none;
border-bottom-color: #fff;
}
.mapboxgl-popup-anchor-bottom .mapboxgl-popup-tip {
-webkit-align-self: center;
align-self: center;
border-bottom: none;
border-top-color: #fff;
}
.mapboxgl-popup-anchor-bottom-left .mapboxgl-popup-tip {
-webkit-align-self: flex-start;
align-self: flex-start;
border-bottom: none;
border-left: none;
border-top-color: #fff;
}
.mapboxgl-popup-anchor-bottom-right .mapboxgl-popup-tip {
-webkit-align-self: flex-end;
align-self: flex-end;
border-bottom: none;
border-right: none;
border-top-color: #fff;
}
.mapboxgl-popup-anchor-left .mapboxgl-popup-tip {
-webkit-align-self: center;
align-self: center;
border-left: none;
border-right-color: #fff;
}
.mapboxgl-popup-anchor-right .mapboxgl-popup-tip {
-webkit-align-self: center;
align-self: center;
border-right: none;
border-left-color: #fff;
}
.mapboxgl-popup-close-button {
position: absolute;
right: 0;
top: 0;
border: none;
border-radius: 0 3px 0 0;
cursor: pointer;
background-color: rgba(0,0,0,0);
}
.mapboxgl-popup-close-button:hover {
background-color: rgba(0,0,0,0.05);
}
.mapboxgl-popup-content {
position: relative;
background: #fff;
border-radius: 3px;
box-shadow: 0 1px 2px rgba(0,0,0,0.10);
padding: 10px 10px 15px;
pointer-events: auto;
}
.mapboxgl-popup-anchor-top-left .mapboxgl-popup-content {
border-top-left-radius: 0;
}
.mapboxgl-popup-anchor-top-right .mapboxgl-popup-content {
border-top-right-radius: 0;
}
.mapboxgl-popup-anchor-bottom-left .mapboxgl-popup-content {
border-bottom-left-radius: 0;
}
.mapboxgl-popup-anchor-bottom-right .mapboxgl-popup-content {
border-bottom-right-radius: 0;
}
.mapboxgl-crosshair,
.mapboxgl-crosshair .mapboxgl-interactive,
.mapboxgl-crosshair .mapboxgl-interactive:active {
cursor: crosshair;
}
.mapboxgl-boxzoom {
position: absolute;
top: 0;
left: 0;
width: 0;
height: 0;
background: #fff;
border: 2px dotted #202020;
opacity: 0.5;
}
@media print {
.mapbox-improve-map {
display:none;
}
}
module powerbi.visuals {
import DataRoleHelper = powerbi.data.DataRoleHelper;
export class ScriptDependency {
private _timeoutHandle : number;
public addScript(alias: string, uri: string, callback?:()=>boolean) {
var deferred = $.Deferred();
$.getScript(uri, (d, status, jqxhr)=>{
if (jqxhr.status == 200)
{
if (!callback){
deferred.resolve();
}
else {
this._timeoutHandle = setTimeout(()=>{this.doLoadedCallback(deferred, callback);}, 500);
}
}
else {
deferred.reject();
}
});
return deferred;
}
private doLoadedCallback(deferred : JQueryDeferred<any>, callback: ()=>boolean) : void
{
if (callback())
{
clearTimeout(this._timeoutHandle);
deferred.resolve();
}
else
{
console.log("all kinds of having to retry");
this._timeoutHandle = setTimeout(()=>{this.doLoadedCallback(deferred, callback);}, 500);
}
}
}
export interface CategoryViewModel {
value: string;
identity: string;
location: string;
}
export interface ValueViewModel {
values: any[];
}
export interface RoleViewModel {
longitude: number;
latitude: number;
size: number;
icon: number;
}
export interface ViewModel {
categories: CategoryViewModel[];
values: ValueViewModel[];
}
export class BlueGraniteMapboxGLClusterMap implements IVisual {
public static capabilities: VisualCapabilities = {
dataRoles: [
{
name: 'Category',
kind: VisualDataRoleKind.Grouping,
displayName: 'Entity'
},
{
name: 'Latitude',
kind: powerbi.VisualDataRoleKind.Measure,
displayName: 'Latitude',
preferredTypes: [
{ geography: { latitude: true } }
]
},
{
name: 'Longitude',
kind: powerbi.VisualDataRoleKind.Measure,
displayName: 'Longitude',
preferredTypes: [
{ geography: { longitude: true } }
]
},
{
name: 'Size',
kind: powerbi.VisualDataRoleKind.Measure,
displayName: 'Heading (should be unique)'
},
{
name: 'Icon',
kind: powerbi.VisualDataRoleKind.Measure,
displayName: 'Body'
},
],
dataViewMappings: [{
conditions: [
{ 'Category': { min: 1, max: 1 }, 'Latitude': { max: 1, kind: VisualDataRoleKind.Measure }, 'Longitude': { max: 1, kind: VisualDataRoleKind.Measure }, 'Size': { max: 1 }, 'Icon': { max: 0 } },
{ 'Category': { min: 1, max: 1 }, 'Latitude': { max: 1, kind: VisualDataRoleKind.Measure }, 'Longitude': { max: 1, kind: VisualDataRoleKind.Measure }, 'Size': { max: 1 }, 'Icon': { max: 1 } },
],
categorical: {
categories: {
for: { in: 'Category' },
dataReductionAlgorithm: { top: {} }
},
values: {
select: [
{ bind: { to: 'Latitude' } },
{ bind: { to: 'Longitude' } },
{ bind: { to: 'Size' } },
{ bind: { to: 'Icon' } },
],
dataReductionAlgorithm: { top: {} }
},
rowCount: { preferred: { min: 2 } },
dataVolume: 4,
}
}, {
conditions: [
{ 'Category': { max: 0 }, 'Latitude': { max: 1, kind: VisualDataRoleKind.Grouping }, 'Longitude': { max: 1, kind: VisualDataRoleKind.Grouping }, 'Size': { max: 1 }, 'Icon': { max: 0 } },
{ 'Category': { max: 0 }, 'Latitude': { max: 1, kind: VisualDataRoleKind.Grouping }, 'Longitude': { max: 1, kind: VisualDataRoleKind.Grouping }, 'Size': { max: 1 }, 'Icon': { max: 1 } }
],
categorical: {
categories: {
select: [
{ bind: { to: 'Latitude' } },
{ bind: { to: 'Longitude' } },
],
dataReductionAlgorithm: { top: {} }
},
values: {
select: [
{ bind: { to: 'Size' } },
{ bind: { to: 'Icon' } },
],
dataReductionAlgorithm: { top: {} }
},
rowCount: { preferred: { min: 2 } },
dataVolume: 4,
},
}],
objects: {
general: {
displayName: data.createDisplayNameGetter('Visual_General'),
properties: {
formatString: {
type: { formatting: { formatString: true } },
},
},
},
}
};
public static converter(dataView: DataView, colors: IDataColorPalette): ViewModel {
var viewModel: ViewModel = {
categories: [],
values: []
}
//console.log("converter");
//console.log(dataView);
var categorical = dataView.categorical;
if (categorical) {
var categories = categorical.categories;
var series = categorical.values;
var formatString = dataView.metadata.columns[0].format;
if (categories && categories.length > 0 && series.length > 0) {
for (var i = 0, catLength = categories[0].values.length; i < catLength; i++) {
viewModel.categories.push({
location: categories[0].values[i],
value: categories[0].values[i],
identity: ''
})
for (var k = 0, seriesLength = series.length; k < seriesLength; k++) {
var value = series[k].values[i];
if (k == 0) {
viewModel.values.push({ values: [] });
}
viewModel.values[i].values.push(value);
}
}
}
}
//console.log(viewModel);
return viewModel;
}
private hostContainer: JQuery;
private colorPalette: IDataColorPalette;
private dataView: DataView;
private map: D3.Selection;
private notification: D3.Selection;
private logo: D3.Selection;
public init(options: VisualInitOptions): void {
var deps = new ScriptDependency();
deps.addScript("mapboxgl", "https://api.mapbox.com/mapbox-gl-js/v0.20.1/mapbox-gl.js",
():boolean=>{ return (typeof mapboxgl)!=undefined; })
.done(()=>{
console.log("done loading");
})
.fail(()=>{
console.log("error loading dependency");
});
this.colorPalette = options.style.colorPalette.dataColors;
this.hostContainer = options.element.css('overflow-x', 'hidden');
//add BlueGranite logo
var logo = this.logo = d3.select(options.element.get(0))
.append("div")
.attr("class", "blue-granite-logo")
.on("click", function() { window.open("http://www.blue-granite.com"); });
//add map div
var map = this.map = d3.select(options.element.get(0))
.append("div")
.attr("id", "map")
.attr("height", options.viewport.height)
.attr("width", options.viewport.width);
//add story pane div
var notification = this.notification = d3.select(options.element.get(0))
.append("div")
.attr("id", "notification")
.attr("height", options.viewport.height)
.attr("width", options.viewport.width);
}
public update(options: VisualUpdateOptions) {
var dataViews = this.dataView = options.dataViews;
if (!dataViews) return;
this.updateContainerViewports(options.viewport);
var viewModel = BlueGraniteMapboxGLClusterMap.converter(dataViews[0], this.colorPalette);
//get index values for roles
//console.log("data role helper");
var lngIndex = -1;
var latIndex = -1;
var sizeIndex = -1;
var iconIndex = -1;
lngIndex = DataRoleHelper.getMeasureIndexOfRole(dataViews[0].categorical.values.grouped(), "Longitude");
latIndex = DataRoleHelper.getMeasureIndexOfRole(dataViews[0].categorical.values.grouped(), "Latitude");
sizeIndex = DataRoleHelper.getMeasureIndexOfRole(dataViews[0].categorical.values.grouped(), "Size");
iconIndex = DataRoleHelper.getMeasureIndexOfRole(dataViews[0].categorical.values.grouped(), "Icon");
//console.log("longitude: " + lngIndex);
//console.log("latitude: " + latIndex);
//console.log("size: " + sizeIndex);
//console.log("icon: " + iconIndex);
var roleModel = {
longitude: lngIndex,
latitude: latIndex,
size: sizeIndex,
icon: iconIndex
}
//console.log(roleModel);
//console.log(dataViews);
//console.log(viewModel);
//console.log(dataViews[0].metadata.columns);
//if exists, empty map and story to avoid duplicates on update
//$("#map").empty(); //disables flyto
$('#notification').children().remove();
//field check prior to rendering map
if(viewModel.categories[0].value == null || roleModel.longitude == -1 || roleModel.latitude == -1 || roleModel.size == -1 || roleModel.icon == -1){
var noteDiv = d3.select("#notification")
noteDiv.append("p")
.text("Map will load when Longitude, Latitude, Heading and Body have been added");
return;
}
//create map
mapboxgl.accessToken = 'pk.eyJ1IjoiZGVsZGVyc3ZlbGQiLCJhIjoiY2lxZ2w2ZmE0MDN3amZvbnA1Z2E5a2IwMyJ9.v60RBnYtK9ajw88xFrZLJg';
var map = new mapboxgl.Map({
container: 'map',
//style: 'mapbox://styles/mapbox/streets-v9',
//style: 'mapbox://styles/mapbox/satellite-v9',
//style: 'mapbox://styles/mapbox/light-v9',
//style: 'mapbox://styles/mapbox/dark-v9',
style: 'mapbox://styles/mapbox/bright-v9',
//style: 'mapbox://styles/mapbox/outdoors-v9',
//style: 'mapbox://styles/mapbox/emerald-v8',
//style: 'mapbox://styles/mapbox/satellite-hybrid-v8',
//style: 'mapbox://styles/mapbox/empty-v9',
//style: 'mapbox://styles/deldersveld/ciqeooas3000bc9nnzkg2iivg',
//center: [-84.50, 42],
zoom: 7,
pitch: 0, // pitch in degrees (3d angle)
bearing: 0, // bearing in degrees (rotation)
attributionControl: {
position: 'top-right'
}
});
//zoom and rotation controls
map.addControl(new mapboxgl.Navigation());
//urban area polygons
/*map.on('load', function () {
map.addSource('urban-areas', {
'type': 'geojson',
'data': 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_50m_urban_areas.geojson'
});
map.addLayer({
'id': 'urban-areas-fill',
'type': 'fill',
'source': 'urban-areas',
'layout': {},
'paint': {
'fill-color': '#587abc',
'fill-opacity': 0.4
}
}, 'urban');
});*/
AddPoints(viewModel, roleModel);
function AddPoints(data, roles){
//structure PBI data as GeoJSON
var collection = {};
var features = [];
for(var i in data.categories){
//console.log(data.categories[i].value);
//console.log(data.values[i].values[0]);
//console.log(data.values[i].values[1]);
var feature = {};
var geometry = {"type":"Point", "coordinates":[data.values[i].values[roles.longitude], data.values[i].values[roles.latitude]]};
var properties = {"title":data.categories[i].value, "size": data.values[i].values[roles.size], "icon":data.values[i].values[roles.icon]}
feature["type"] = "Feature";
feature["geometry"] = geometry;
feature["properties"] = properties;
features.push(feature);
}
collection["type"] = "FeatureCollection";
collection["features"] = features;
map.on('load', function () {
//point clusters
if(1==1){
map.addSource("points", {
"type": "geojson",
"data": collection,
cluster: true,
clusterMaxZoom: 14,
clusterRadius: 50
});
}
//dense points
else{
map.addSource("points", {
"type": "geojson",
"data": collection
});
}
//circles
map.addLayer({
"id": "points",
"type": "circle",
"source": "points",
"paint": {
"circle-radius": 10,
"circle-color": "#007cbf"
}
});
//begin clusters
var layers = [
[150, '#fd625e', 30, 0, 0.9],
[50, '#f2c80f', 24, 0, 0.9],
[0, '#01b8aa', 18, 0, 0.9]
];
layers.forEach(function (layer, i) {
map.addLayer({
"id": "cluster-" + i,
"type": "circle",
"source": "points",
"paint": {
"circle-color": layer[1],
"circle-radius": layer[2], //100 for heat map //18
"circle-blur": layer[3], //1 for heat map //.5
"circle-opacity": layer[4]
},
"filter": i === 0 ?
[">=", "point_count", layer[0]] :
["all",
[">=", "point_count", layer[0]],
["<", "point_count", layers[i - 1][0]]]
});
});
// Add a layer for the clusters' count labels
map.addLayer({
"id": "cluster-count",
"type": "symbol",
"source": "points",
"layout": {
"text-field": "{point_count}",
"text-font": [
"DIN Offc Pro Medium",
"Arial Unicode MS Bold"
],
"text-size": 14,
},
"paint": {
"text-color": "#111111",
"text-halo-color": "#eeeeee",
"text-halo-width": 1
},
});
//end clusters
});
//fit bounds to data
var bounds = new mapboxgl.LngLatBounds();
collection["features"].forEach(function(feature) {
bounds.extend(feature.geometry.coordinates);
});
console.log(bounds);
map.fitBounds(bounds);
}
}
private updateContainerViewports(viewport: IViewport) {
var width = viewport.width;
var height = viewport.height;
var sandboxPadding = 10;
this.hostContainer.css({
'height': height,
'width': width
});
}
public destroy(): void {
this.logo = null;
this.map = null;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment