mirror of
https://github.com/FoggedLens/iD.git
synced 2026-02-13 17:23:02 +00:00
411 lines
12 KiB
JavaScript
411 lines
12 KiB
JavaScript
import _debounce from 'lodash-es/debounce';
|
|
|
|
import {
|
|
descending as d3_descending,
|
|
ascending as d3_ascending
|
|
} from 'd3-array';
|
|
|
|
import {
|
|
event as d3_event,
|
|
select as d3_select
|
|
} from 'd3-selection';
|
|
|
|
import { d3keybinding as d3_keybinding } from '../lib/d3.keybinding.js';
|
|
|
|
import { t, textDirection } from '../util/locale';
|
|
import { svgIcon } from '../svg';
|
|
import { uiBackgroundDisplayOptions } from './background_display_options';
|
|
import { uiBackgroundOffset } from './background_offset';
|
|
import { uiCmd } from './cmd';
|
|
import { uiDisclosure } from './disclosure';
|
|
import { uiHelp } from './help';
|
|
import { uiMapData } from './map_data';
|
|
import { uiMapInMap } from './map_in_map';
|
|
import { uiTooltipHtml } from './tooltipHtml';
|
|
import { utilCallWhenIdle } from '../util';
|
|
import { tooltip } from '../util/tooltip';
|
|
|
|
|
|
export function uiBackground(context) {
|
|
var key = t('background.key');
|
|
|
|
var _customSource = context.background().findSource('custom');
|
|
var _previousBackground = context.background().findSource(context.storage('background-last-used-toggle'));
|
|
var _shown = false;
|
|
|
|
var _backgroundList = d3_select(null);
|
|
var _overlayList = d3_select(null);
|
|
var _displayOptionsContainer = d3_select(null);
|
|
var _offsetContainer = d3_select(null);
|
|
|
|
var backgroundDisplayOptions = uiBackgroundDisplayOptions(context);
|
|
var backgroundOffset = uiBackgroundOffset(context);
|
|
|
|
|
|
function setTooltips(selection) {
|
|
selection.each(function(d, i, nodes) {
|
|
var item = d3_select(this).select('label');
|
|
var span = item.select('span');
|
|
var placement = (i < nodes.length / 2) ? 'bottom' : 'top';
|
|
var description = d.description();
|
|
var isOverflowing = (span.property('clientWidth') !== span.property('scrollWidth'));
|
|
|
|
if (d === _previousBackground) {
|
|
item.call(tooltip()
|
|
.placement(placement)
|
|
.html(true)
|
|
.title(function() {
|
|
var tip = '<div>' + t('background.switch') + '</div>';
|
|
return uiTooltipHtml(tip, uiCmd('⌘' + key));
|
|
})
|
|
);
|
|
} else if (description || isOverflowing) {
|
|
item.call(tooltip()
|
|
.placement(placement)
|
|
.title(description || d.name())
|
|
);
|
|
} else {
|
|
item.call(tooltip().destroy);
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
function updateLayerSelections(selection) {
|
|
function active(d) {
|
|
return context.background().showsLayer(d);
|
|
}
|
|
|
|
selection.selectAll('.layer')
|
|
.classed('active', active)
|
|
.classed('switch', function(d) { return d === _previousBackground; })
|
|
.call(setTooltips)
|
|
.selectAll('input')
|
|
.property('checked', active);
|
|
}
|
|
|
|
|
|
function chooseBackground(d) {
|
|
if (d.id === 'custom' && !d.template()) {
|
|
return editCustom();
|
|
}
|
|
|
|
d3_event.preventDefault();
|
|
_previousBackground = context.background().baseLayerSource();
|
|
context.storage('background-last-used-toggle', _previousBackground.id);
|
|
context.storage('background-last-used', d.id);
|
|
context.background().baseLayerSource(d);
|
|
_backgroundList.call(updateLayerSelections);
|
|
document.activeElement.blur();
|
|
}
|
|
|
|
|
|
function editCustom() {
|
|
d3_event.preventDefault();
|
|
var example = 'https://{switch:a,b,c}.tile.openstreetmap.org/{zoom}/{x}/{y}.png';
|
|
var template = window.prompt(
|
|
t('background.custom_prompt', { example: example }),
|
|
_customSource.template() || example
|
|
);
|
|
|
|
if (template) {
|
|
context.storage('background-custom-template', template);
|
|
_customSource.template(template);
|
|
chooseBackground(_customSource);
|
|
} else {
|
|
_backgroundList.call(updateLayerSelections);
|
|
}
|
|
}
|
|
|
|
|
|
function chooseOverlay(d) {
|
|
d3_event.preventDefault();
|
|
context.background().toggleOverlayLayer(d);
|
|
_overlayList.call(updateLayerSelections);
|
|
document.activeElement.blur();
|
|
}
|
|
|
|
|
|
function drawListItems(layerList, type, change, filter) {
|
|
var sources = context.background()
|
|
.sources(context.map().extent())
|
|
.filter(filter);
|
|
|
|
var layerLinks = layerList.selectAll('li.layer')
|
|
.data(sources, function(d) { return d.name(); });
|
|
|
|
layerLinks.exit()
|
|
.remove();
|
|
|
|
var enter = layerLinks.enter()
|
|
.append('li')
|
|
.attr('class', 'layer')
|
|
.classed('layer-custom', function(d) { return d.id === 'custom'; })
|
|
.classed('best', function(d) { return d.best(); });
|
|
|
|
enter.filter(function(d) { return d.id === 'custom'; })
|
|
.append('button')
|
|
.attr('class', 'layer-browse')
|
|
.call(tooltip()
|
|
.title(t('background.custom_button'))
|
|
.placement((textDirection === 'rtl') ? 'right' : 'left')
|
|
)
|
|
.on('click', editCustom)
|
|
.call(svgIcon('#icon-search'));
|
|
|
|
enter.filter(function(d) { return d.best(); })
|
|
.append('div')
|
|
.attr('class', 'best')
|
|
.call(tooltip()
|
|
.title(t('background.best_imagery'))
|
|
.placement((textDirection === 'rtl') ? 'right' : 'left')
|
|
)
|
|
.append('span')
|
|
.html('★');
|
|
|
|
var label = enter
|
|
.append('label');
|
|
|
|
label
|
|
.append('input')
|
|
.attr('type', type)
|
|
.attr('name', 'layers')
|
|
.on('change', change);
|
|
|
|
label
|
|
.append('span')
|
|
.text(function(d) { return d.name(); });
|
|
|
|
|
|
layerList.selectAll('li.layer')
|
|
.sort(sortSources)
|
|
.style('display', layerList.selectAll('li.layer').data().length > 0 ? 'block' : 'none');
|
|
|
|
layerList
|
|
.call(updateLayerSelections);
|
|
|
|
|
|
function sortSources(a, b) {
|
|
return a.best() && !b.best() ? -1
|
|
: b.best() && !a.best() ? 1
|
|
: d3_descending(a.area(), b.area()) || d3_ascending(a.name(), b.name()) || 0;
|
|
}
|
|
}
|
|
|
|
|
|
function renderBackgroundList(selection) {
|
|
|
|
// the background list
|
|
var container = selection.selectAll('.layer-background-list')
|
|
.data([0]);
|
|
|
|
_backgroundList = container.enter()
|
|
.append('ul')
|
|
.attr('class', 'layer-list layer-background-list')
|
|
.attr('dir', 'auto')
|
|
.merge(container);
|
|
|
|
|
|
// add minimap toggle below list
|
|
var minimapEnter = selection.selectAll('.minimap-toggle-list')
|
|
.data([0])
|
|
.enter()
|
|
.append('ul')
|
|
.attr('class', 'layer-list minimap-toggle-list')
|
|
.append('li')
|
|
.attr('class', 'layer minimap-toggle-item');
|
|
|
|
var minimapLabelEnter = minimapEnter
|
|
.append('label')
|
|
.call(tooltip()
|
|
.html(true)
|
|
.title(uiTooltipHtml(t('background.minimap.tooltip'), t('background.minimap.key')))
|
|
.placement('top')
|
|
);
|
|
|
|
minimapLabelEnter
|
|
.append('input')
|
|
.attr('type', 'checkbox')
|
|
.on('change', function() {
|
|
d3_event.preventDefault();
|
|
uiMapInMap.toggle();
|
|
});
|
|
|
|
minimapLabelEnter
|
|
.append('span')
|
|
.text(t('background.minimap.description'));
|
|
|
|
|
|
// "Info / Report a Problem" link
|
|
selection.selectAll('.imagery-faq')
|
|
.data([0])
|
|
.enter()
|
|
.append('div')
|
|
.attr('class', 'imagery-faq')
|
|
.append('a')
|
|
.attr('target', '_blank')
|
|
.attr('tabindex', -1)
|
|
.call(svgIcon('#icon-out-link', 'inline'))
|
|
.attr('href', 'https://github.com/openstreetmap/iD/blob/master/FAQ.md#how-can-i-report-an-issue-with-background-imagery')
|
|
.append('span')
|
|
.text(t('background.imagery_source_faq'));
|
|
}
|
|
|
|
|
|
function renderOverlayList(selection) {
|
|
var container = selection.selectAll('.layer-overlay-list')
|
|
.data([0]);
|
|
|
|
_overlayList = container.enter()
|
|
.append('ul')
|
|
.attr('class', 'layer-list layer-overlay-list')
|
|
.attr('dir', 'auto')
|
|
.merge(container);
|
|
}
|
|
|
|
|
|
function update() {
|
|
_backgroundList
|
|
.call(drawListItems, 'radio', chooseBackground, function(d) { return !d.isHidden() && !d.overlay; });
|
|
|
|
_overlayList
|
|
.call(drawListItems, 'checkbox', chooseOverlay, function(d) { return !d.isHidden() && d.overlay; });
|
|
|
|
_displayOptionsContainer
|
|
.call(backgroundDisplayOptions);
|
|
|
|
_offsetContainer
|
|
.call(backgroundOffset);
|
|
}
|
|
|
|
|
|
function quickSwitch() {
|
|
if (d3_event) {
|
|
d3_event.stopImmediatePropagation();
|
|
d3_event.preventDefault();
|
|
}
|
|
if (_previousBackground) {
|
|
chooseBackground(_previousBackground);
|
|
}
|
|
}
|
|
|
|
|
|
function background(selection) {
|
|
|
|
function hidePane() {
|
|
setVisible(false);
|
|
}
|
|
|
|
function togglePane() {
|
|
if (d3_event) d3_event.preventDefault();
|
|
paneTooltip.hide(button);
|
|
setVisible(!button.classed('active'));
|
|
}
|
|
|
|
function setVisible(show) {
|
|
if (show !== _shown) {
|
|
button.classed('active', show);
|
|
_shown = show;
|
|
|
|
if (show) {
|
|
uiMapData.hidePane();
|
|
uiHelp.hidePane();
|
|
update();
|
|
|
|
pane
|
|
.style('display', 'block')
|
|
.style('right', '-300px')
|
|
.transition()
|
|
.duration(200)
|
|
.style('right', '0px');
|
|
|
|
} else {
|
|
pane
|
|
.style('display', 'block')
|
|
.style('right', '0px')
|
|
.transition()
|
|
.duration(200)
|
|
.style('right', '-300px')
|
|
.on('end', function() {
|
|
d3_select(this).style('display', 'none');
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
var pane = selection
|
|
.append('div')
|
|
.attr('class', 'fillL map-overlay col3 content hide');
|
|
|
|
var paneTooltip = tooltip()
|
|
.placement((textDirection === 'rtl') ? 'right' : 'left')
|
|
.html(true)
|
|
.title(uiTooltipHtml(t('background.description'), key));
|
|
|
|
var button = selection
|
|
.append('button')
|
|
.attr('tabindex', -1)
|
|
.on('click', togglePane)
|
|
.call(svgIcon('#icon-layers', 'light'))
|
|
.call(paneTooltip);
|
|
|
|
pane
|
|
.append('h2')
|
|
.text(t('background.title'));
|
|
|
|
// background list
|
|
pane
|
|
.append('div')
|
|
.attr('class', 'background-background-list-container')
|
|
.call(uiDisclosure(context, 'background_list', true)
|
|
.title(t('background.backgrounds'))
|
|
.content(renderBackgroundList)
|
|
);
|
|
|
|
// overlay list
|
|
pane
|
|
.append('div')
|
|
.attr('class', 'background-overlay-list-container')
|
|
.call(uiDisclosure(context, 'overlay_list', true)
|
|
.title(t('background.overlays'))
|
|
.content(renderOverlayList)
|
|
);
|
|
|
|
// display options
|
|
_displayOptionsContainer = pane
|
|
.append('div')
|
|
.attr('class', 'background-display-options');
|
|
|
|
// offset controls
|
|
_offsetContainer = pane
|
|
.append('div')
|
|
.attr('class', 'background-offset');
|
|
|
|
|
|
// add listeners
|
|
context.map()
|
|
.on('move.background-update', _debounce(utilCallWhenIdle(update), 1000));
|
|
|
|
context.background()
|
|
.on('change.background-update', update);
|
|
|
|
|
|
update();
|
|
|
|
var keybinding = d3_keybinding('background')
|
|
.on(key, togglePane)
|
|
.on(uiCmd('⌘' + key), quickSwitch)
|
|
.on([t('map_data.key'), t('help.key')], hidePane);
|
|
|
|
d3_select(document)
|
|
.call(keybinding);
|
|
|
|
uiBackground.hidePane = hidePane;
|
|
uiBackground.togglePane = togglePane;
|
|
uiBackground.setVisible = setVisible;
|
|
}
|
|
|
|
return background;
|
|
}
|