Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add Mapbox wordmark as LogoControl #3933

Merged
merged 5 commits into from
Jan 27, 2017
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions dist/mapbox-gl.css
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,15 @@
display: inline-block;
}

a.mapboxgl-ctrl-logo {
width: 60px;
height: 20px;
display: block;
background-repeat: no-repeat;
cursor: pointer;
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgeD0iMCIgeT0iMCIgd2lkdGg9IjU5LjEiIGhlaWdodD0iMTgiIHZpZXdCb3g9IjAgMCA1OS4xIDE4IiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCA1OS4xMTkgMTgiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxwYXRoIGQ9Ik0xLjQgMEMwLjYgMC4xIDAgMC44IDAgMS41TDAgMTMuNEMwIDE0LjIgMC43IDE0LjggMS41IDE0LjhMMy4zIDE0LjhDNCAxNC44IDQuNyAxNC4yIDQuOCAxMy40TDQuOCA5LjEgNS41IDEwLjNDNiAxMS4yIDcuNSAxMS4yIDggMTAuM0w4LjggOS4xIDguOCAxMy40QzguOCAxNC4xIDkuNSAxNC44IDEwLjIgMTQuOEwxMiAxNC44QzEyLjggMTQuOCAxMy41IDE0LjIgMTMuNSAxMy40TDEzLjUgMTMuMkMxNC41IDE0LjMgMTUuOSAxNSAxNy42IDE1TDIxLjcgMTUgMjEuNyAxNi41QzIxLjcgMTcuMyAyMi4zIDE4IDIzLjEgMThMMjQuOSAxOEMyNS43IDE4IDI2LjQgMTcuMyAyNi40IDE2LjVMMjYuNCAxNUMyOC4xIDE1IDI5LjUgMTQuNCAzMC41IDEzLjNMMzAuNSAxMy41QzMwLjUgMTMuOSAzMC43IDE0LjMgMzEgMTQuNiAzMS4zIDE0LjkgMzEuNiAxNSAzMiAxNUwzNS4zIDE1QzM3LjQgMTUgMzkuMiAxNCA0MC4zIDEyLjMgNDEuMyAxMy45IDQzLjEgMTUgNDUuMSAxNSA0Ni4yIDE1IDQ3LjEgMTQuOCA0Ny45IDE0LjMgNDguMiAxNC42IDQ4LjcgMTQuOCA0OS4xIDE0LjhMNTEuMyAxNC44QzUxLjcgMTQuOCA1Mi4yIDE0LjYgNTIuNSAxNC4yTDUzLjQgMTIuOSA1NC4zIDE0LjJDNTQuNiAxNC42IDU1LjEgMTQuOCA1NS41IDE0LjhMNTcuNyAxNC44QzU4LjggMTQuOCA1OS41IDEzLjQgNTguOSAxMi41TDU2LjMgOC45IDU4LjcgNS41QzU5LjQgNC42IDU4LjYgMy4xIDU3LjUgMy4xTDU1LjMgMy4xQzU0LjkgMy4xIDU0LjQgMy40IDU0LjEgMy44TDUzLjQgNC44IDUyLjcgMy44QzUyLjQgMy40IDUxLjkgMy4xIDUxLjQgMy4xTDQ5LjMgMy4xQzQ4LjggMy4xIDQ4LjMgMy40IDQ4IDMuOCA0Ny4yIDMuMyA0Ni4yIDMgNDUuMSAzIDQzLjEgMyA0MS4zIDQuMSA0MC4yIDUuNyAzOS4yIDQgMzcuNCAzIDM1LjMgM0wzNS4zIDEuNUMzNS4zIDEuMSAzNS4xIDAuNyAzNC44IDAuNCAzNC42IDAuMiAzNC4yIDAgMzMuOCAwTDMyIDBDMzEuMyAwIDMwLjUgMC44IDMwLjUgMS41TDMwLjUgNC43QzI5LjUgMy42IDI4LjEgMyAyNi41IDNMMjMuMSAzQzIyLjQgMyAyMS43IDMuNyAyMS43IDQuNUwyMS43IDQuOEMyMC42IDMuNyAxOS4yIDMgMTcuNiAzIDE1LjkgMyAxNC41IDMuNyAxMy41IDQuOEwxMy41IDEuNUMxMy41IDAuNyAxMi44IDAgMTIgMEwxMC42IDBDOS42IDAgOC40IDAuNCA3LjggMS40TDYuOCAzLjEgNS44IDEuNEM1LjEgMC40IDMuOSAwIDIuOSAwTDEuNSAwIDEuNCAwek0xLjUgMS41TDIuOSAxLjVDMy42IDEuNSA0LjIgMS43IDQuNSAyLjJMNi44IDYuMSA5IDIuMkM5LjMgMS43IDkuOSAxLjUgMTAuNiAxLjVMMTIgMS41IDEyIDEzLjUgMTAuMiAxMy41IDEwLjIgMy42IDYuOCA5LjUgMy4zIDMuNiAzLjMgMTMuNSAxLjUgMTMuNSAxLjUgMS41ek0zMi4xIDEuNUwzMy44IDEuNSAzMy44IDQuNUMzNC40IDQuNSAzNC44IDQuNSAzNS4zIDQuNSAzNy44IDQuNSAzOS43IDYuNCAzOS43IDkgMzkuNyAxMS42IDM3LjggMTMuNSAzNS4zIDEzLjVMMzIuMSAxMy41IDMyLjEgMS41ek0xNy42IDQuNUMyMCA0LjUgMjEuOCA2LjQgMjEuOCA5TDIxLjggMTMuNSAxNy42IDEzLjVDMTUuMSAxMy41IDEzLjQgMTEuNiAxMy40IDkgMTMuNCA2LjQgMTUuMSA0LjUgMTcuNiA0LjV6TTQ1LjEgNC41QzQ3LjUgNC41IDQ5LjUgNi41IDQ5LjUgOSA0OS41IDExLjUgNDcuNSAxMy41IDQ1LjEgMTMuNSA0Mi43IDEzLjUgNDAuNyAxMS41IDQwLjcgOSA0MC43IDYuNSA0Mi43IDQuNSA0NS4xIDQuNXpNMjMuMSA0LjVMMjYuNSA0LjVDMjguOSA0LjUgMzAuOCA2LjQgMzAuOCA5IDMwLjggMTEuNiAyOC45IDEzLjUgMjYuNSAxMy41TDI0LjkgMTMuNSAyNC45IDE2LjUgMjMuMSAxNi41IDIzLjEgNC41ek00OS4zIDQuNUw1MS40IDQuNSA1My40IDcuMyA1NS4zIDQuNSA1Ny41IDQuNSA1NC41IDguOSA1Ny43IDEzLjUgNTUuNSAxMy41IDUzLjQgMTAuNCA1MS4yIDEzLjUgNDkuMSAxMy41IDUyLjMgOC45IDQ5LjMgNC41ek0xNy42IDYuMkMxNi4yIDYuMiAxNS4xIDcuNCAxNS4xIDkgMTUuMSAxMC42IDE2LjIgMTEuOCAxNy42IDExLjhMMjAgMTEuOCAyMCA5QzIwIDcuNCAxOSA2LjIgMTcuNiA2LjJ6TTQ1LjEgNi4yQzQzLjcgNi4yIDQyLjUgNy41IDQyLjUgOSA0Mi41IDEwLjUgNDMuNyAxMS44IDQ1LjEgMTEuOCA0Ni42IDExLjggNDcuNyAxMC41IDQ3LjcgOSA0Ny43IDcuNSA0Ni42IDYuMiA0NS4xIDYuMnpNMjQuOSA2LjNMMjQuOSAxMS44IDI2LjUgMTEuOEMyNy45IDExLjggMjkuMSAxMC41IDI5LjEgOSAyOS4xIDcuNSAyOC4xIDYuMyAyNi41IDYuM0wyNC45IDYuM3pNMzMuOCA2LjNMMzMuOCAxMS44IDM1LjMgMTEuOEMzNi45IDExLjggMzggMTAuNSAzOCA5IDM4IDcuNSAzNi44IDYuMyAzNS4zIDYuM0wzMy44IDYuM3pNMTcuNiA3LjdDMTguMSA3LjcgMTguNSA4LjEgMTguNSA5TDE4LjUgMTAuMyAxNy42IDEwLjNDMTcgMTAuMyAxNi42IDkuOSAxNi42IDkgMTYuNiA4LjEgMTcgNy43IDE3LjYgNy43ek0yNi40IDcuN0MyNy4yIDcuNyAyNy42IDguNCAyNy42IDkgMjcuNiA5LjkgMjYuOSAxMC4zIDI2LjQgMTAuM0wyNi40IDcuN3pNMzUuMSA3LjdDMzUuOCA3LjcgMzYuNSA4LjMgMzYuNSA5IDM2LjUgOS44IDM1LjkgMTAuMyAzNS4xIDEwLjNMMzUuMSA3Ljd6TTQ1LjEgNy43QzQ1LjcgNy43IDQ2LjIgOC4yIDQ2LjIgOSA0Ni4yIDkuOCA0NS43IDEwLjMgNDUuMSAxMC4zIDQ0LjUgMTAuMyA0NCA5LjggNDQgOSA0NCA4LjIgNDQuNSA3LjcgNDUuMSA3Ljd6IiBvcGFjaXR5PSIwLjMiLz48cGF0aCBkPSJtMS41IDEuNSAwIDEyIDEuOCAwIDAtOS45IDMuNSA1LjkgMy41LTUuOSAwIDkuOSAxLjggMCAwLTEyLTEuNCAwQzkuOSAxLjUgOS4zIDEuNyA5IDIuMkw2LjggNi4xIDQuNSAyLjJDNC4yIDEuNyAzLjYgMS41IDIuOSAxLjVMMS41IDEuNVptMzAuNiAwIDAgMTIgMy4zIDBjMi40IDAgNC40LTEuOSA0LjQtNC41IDAtMi42LTEuOS00LjUtNC40LTQuNS0wLjUgMC0wLjkgMC0xLjUgMGwwLTMtMS43IDB6TTE3LjYgNC41Yy0yLjQgMC00LjIgMS45LTQuMiA0LjUgMCAyLjYgMS44IDQuNSA0LjIgNC41bDQuMiAwTDIxLjggOWMwLTIuNi0xLjctNC41LTQuMi00LjV6bTI3LjYgMGMtMi40IDAtNC40IDItNC40IDQuNSAwIDIuNSAyIDQuNSA0LjQgNC41IDIuNCAwIDQuMy0yIDQuMy00LjUgMC0yLjUtMS45LTQuNS00LjMtNC41em0tMjIgMCAwIDEyIDEuOCAwIDAtMyAxLjYgMGMyLjQgMCA0LjMtMS45IDQuMy00LjUgMC0yLjYtMS45LTQuNS00LjMtNC41bC0zLjMgMHptMjYuMiAwIDMgNC40LTMuMiA0LjYgMi4xIDAgMi4yLTMuMSAyLjEgMy4xIDIuMiAwTDU0LjUgOC45IDU3LjUgNC41IDU1LjMgNC41IDUzLjQgNy4zIDUxLjQgNC41IDQ5LjMgNC41Wk0xNy42IDYuMkMxOSA2LjIgMjAgNy40IDIwIDlsMCAyLjgtMi40IDBjLTEuNCAwLTIuNC0xLjItMi40LTIuOCAwLTEuNiAxLTIuOCAyLjQtMi44em0yNy42IDBjMS40IDAgMi42IDEuMiAyLjYgMi44IDAgMS41LTEuMiAyLjgtMi42IDIuOEM0My43IDExLjggNDIuNSAxMC41IDQyLjUgOWMwLTEuNSAxLjItMi44IDIuNi0yLjh6bS0yMC4yIDAgMS42IDBjMS42IDAgMi42IDEuMyAyLjYgMi44IDAgMS41LTEuMSAyLjgtMi42IDIuOGwtMS42IDAgMC01LjV6bTkgMCAxLjUgMGMxLjUgMCAyLjYgMS4zIDIuNiAyLjggMCAxLjUtMSAyLjgtMi42IDIuOGwtMS41IDAgMC01LjV6IiBmaWxsPSIjZmZmIi8+PC9zdmc+");
}

.mapboxgl-ctrl.mapboxgl-ctrl-attrib {
padding: 0 5px;
background-color: rgba(255, 255, 255, .5);
Expand Down
1 change: 1 addition & 0 deletions documentation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ toc:
- GeolocateControl
- AttributionControl
- ScaleControl
- LogoControl
- name: Handlers
description: |
Handlers add different kinds of interactivity to the map -
Expand Down
1 change: 1 addition & 0 deletions js/mapbox-gl.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ mapboxgl.workerCount = Math.max(Math.floor(browser.hardwareConcurrency / 2), 1);

mapboxgl.Map = require('./ui/map');
mapboxgl.NavigationControl = require('./ui/control/navigation_control');
mapboxgl.LogoControl = require('./ui/control/logo_control');
mapboxgl.GeolocateControl = require('./ui/control/geolocate_control');
mapboxgl.AttributionControl = require('./ui/control/attribution_control');
mapboxgl.ScaleControl = require('./ui/control/scale_control');
Expand Down
2 changes: 1 addition & 1 deletion js/source/load_tilejson.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ module.exports = function(options, callback) {
return callback(err);
}

const result = util.pick(tileJSON, ['tiles', 'minzoom', 'maxzoom', 'attribution']);
const result = util.pick(tileJSON, ['tiles', 'minzoom', 'maxzoom', 'attribution', 'mapbox_logo']);

if (tileJSON.vector_layers) {
result.vectorLayers = tileJSON.vector_layers;
Expand Down
65 changes: 65 additions & 0 deletions js/ui/control/logo_control.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
'use strict';

const DOM = require('../../util/dom');
const util = require('../../util/util');

/**
* A `LogoControl` is a control that adds the Mapbox watermark
* to the map as required by the [terms of service](https://www.mapbox.com/tos/) for Mapbox
* vector tiles and core styles.
*
* @implements {IControl}
**/

class LogoControl {

constructor() {
util.bindAll(['_logoRequired', '_updateLogo'], this);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: _logoRequired doesn't need to be bound (it's not used as an event handler).

}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can omit empty constructors


onAdd(map) {
this._map = map;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to save the map reference if it's not used by the control?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we don't! I was following the IControl docs, but you're right it isn't necessary in this case.

this._container = DOM.create('div', 'mapboxgl-ctrl');

this._map.on('data', this._updateLogo);
this._updateLogo();
return this._container;
}

onRemove() {
this._container.parentNode.removeChild(this._container);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also needs this._map.off('data', this._updateLogo).

}

getDefaultPosition() {
return 'bottom-left';
}

_updateLogo() {
if (this._logoRequired()) {
const anchor = DOM.create('a', 'mapboxgl-ctrl-logo');
anchor.target = "_blank";
anchor.href = "https://www.mapbox.com/";
anchor.setAttribute("aria-label", "Mapbox logo");
this._container.appendChild(anchor);
this._map.off('data', this._updateLogo);
}
}

_logoRequired() {
if (!this._map.style) return;

const sourceCaches = this._map.style.sourceCaches;
for (const id in sourceCaches) {
const source = sourceCaches[id].getSource();
if (source.mapbox_logo) {
return true;
}
}

return false;
}

}


module.exports = LogoControl;
3 changes: 3 additions & 0 deletions js/ui/map.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const LngLat = require('../geo/lng_lat');
const LngLatBounds = require('../geo/lng_lat_bounds');
const Point = require('point-geometry');
const AttributionControl = require('./control/attribution_control');
const LogoControl = require('./control/logo_control');
const isSupported = require('mapbox-gl-supported');

const defaultMinZoom = 0;
Expand Down Expand Up @@ -99,6 +100,7 @@ const defaultOptions = {
* in an HTML element's `class` attribute. To learn more about Mapbox style classes, read about
* [Layers](https://www.mapbox.com/mapbox-gl-style-spec/#layers) in the style specification.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you really mean to replace attributionControl with logoPosition, or did you mean to replace logoControl with logoPosition?

Given further down you've dropped out options.logoControl with options.logoPosition but retained options.attributionControl.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yipes good catch @andrewharvey -- this was not intentional!

* @param {boolean} [options.attributionControl=true] If `true`, an [AttributionControl](#AttributionControl) will be added to the map.
* @param {boolean} [options.logoPosition='bottom-left'] Position of the Mapbox wordmark on the map. Valid options are ['top-left','top-right', 'bottom-left', 'bottom-right'].
* @param {boolean} [options.failIfMajorPerformanceCaveat=false] If `true`, map creation will fail if the performance of Mapbox
* GL JS would be dramatically worse than expected (i.e. a software renderer would be used).
* @param {boolean} [options.preserveDrawingBuffer=false] If `true`, the map's canvas can be exported to a PNG using `map.getCanvas().toDataURL()`. This is `false` by default as a performance optimization.
Expand Down Expand Up @@ -200,6 +202,7 @@ class Map extends Camera {
if (options.style) this.setStyle(options.style);

if (options.attributionControl) this.addControl(new AttributionControl());
this.addControl(new LogoControl(), options.logoPosition);

this.on('style.load', function() {
if (this.transform.unmodified) {
Expand Down
67 changes: 67 additions & 0 deletions test/js/ui/control/logo.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
'use strict';
const test = require('mapbox-gl-js-test').test;
const VectorTileSource = require('../../../../js/source/vector_tile_source');
const window = require('../../../../js/util/window');
const Map = require('../../../../js/ui/map');

function createMap(logoPosition, logoRequired) {
const container = window.document.createElement('div');
return new Map({
container: container,
style: {
version: 8,
sources: {
'composite': createSource({
minzoom: 1,
maxzoom: 10,
attribution: "Mapbox",
tiles: [
"http://example.com/{z}/{x}/{y}.png"
]
}, logoRequired)
},
layers: []
},
logoPosition: logoPosition || undefined
});
}

function createSource(options, logoRequired) {
const source = new VectorTileSource('id', options, { send: function () {} });
source.onAdd({
transform: { angle: 0, pitch: 0, showCollisionBoxes: false }
});
source.on('error', (e) => {
throw e.error;
});
const logoFlag = "mapbox_logo";
source[logoFlag] = logoRequired === undefined ? true : logoRequired;
return source;
}
test('LogoControl appears in bottom-left by default', (t) => {
const map = createMap();
map.on('load', () => {
t.equal(map.getContainer().querySelectorAll(
'.mapboxgl-ctrl-bottom-left .mapboxgl-ctrl-logo'
).length, 1);
t.end();
});
});
test('LogoControl appears in the position specified by the position option', (t) => {
const map = createMap('top-left');
map.on('load', () => {
t.equal(map.getContainer().querySelectorAll(
'.mapboxgl-ctrl-top-left .mapboxgl-ctrl-logo'
).length, 1);
t.end();
});
});
test('LogoControl is not added when the mapbox_logo property is false', (t) => {
const map = createMap('top-left', false);
map.on('load', () => {
t.equal(map.getContainer().querySelectorAll(
'.mapboxgl-ctrl-top-left .mapboxgl-ctrl-logo').length,
0);
t.end();
});
});