From cc938698e8bf13fdb5fa99255a59a26d327d4f5a Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Sat, 25 Aug 2018 11:14:04 -0400 Subject: [PATCH] Add ability to select custom data --- css/65_data.css | 1 + css/80_app.css | 5 +- modules/behavior/select.js | 7 ++- modules/modes/browse.js | 8 +-- modules/modes/index.js | 1 + modules/modes/rotate.js | 8 +-- modules/modes/select.js | 9 +--- modules/modes/select_data.js | 97 ++++++++++++++++++++++++++++++++++++ modules/modes/select_note.js | 75 +++++++++++++--------------- modules/renderer/map.js | 2 +- modules/svg/data.js | 12 +++-- modules/ui/data_editor.js | 2 +- 12 files changed, 158 insertions(+), 69 deletions(-) create mode 100644 modules/modes/select_data.js diff --git a/css/65_data.css b/css/65_data.css index 1cf8de123..24af906c4 100644 --- a/css/65_data.css +++ b/css/65_data.css @@ -8,6 +8,7 @@ } .mode-browse .layer-notes .note .note-fill, .mode-select .layer-notes .note .note-fill, +.mode-select-data .layer-notes .note .note-fill, .mode-select-note .layer-notes .note .note-fill { pointer-events: visible; cursor: pointer; /* Opera */ diff --git a/css/80_app.css b/css/80_app.css index 958b0e24d..0f51f871b 100644 --- a/css/80_app.css +++ b/css/80_app.css @@ -2594,6 +2594,7 @@ input.key-trap { .data-editor.raw-tag-editor button { display: none; } +.data-editor.raw-tag-editor .tag-row .key-wrap, .data-editor.raw-tag-editor .tag-row .input-wrap-position { width: 50%; } @@ -4060,7 +4061,7 @@ svg.mouseclick use.right { /* Settings Modals ------------------------------------------------------- */ .settings-modal textarea { - height: 60px; + height: 70px; } .settings-modal .buttons .button.col3 { float: none; /* undo float left */ @@ -4071,7 +4072,7 @@ svg.mouseclick use.right { } -.settings-custom-data .instructions-file { +.settings-custom-data .instructions-url { margin-bottom: 10px; } .settings-custom-data .field-file, diff --git a/modules/behavior/select.js b/modules/behavior/select.js index 9e0b3fee9..1dd051e65 100644 --- a/modules/behavior/select.js +++ b/modules/behavior/select.js @@ -11,6 +11,7 @@ import { geoVecLength } from '../geo'; import { modeBrowse, modeSelect, + modeSelectData, modeSelectNote } from '../modes'; @@ -157,13 +158,17 @@ export function behaviorSelect(context) { } } + } else if (datum && datum.__featurehash__ && !isMultiselect) { // clicked Data.. + context + .selectedNoteID(null) + .enter(modeSelectData(context, datum)); + } else if (datum instanceof osmNote && !isMultiselect) { // clicked a Note.. context .selectedNoteID(datum.id) .enter(modeSelectNote(context, datum.id)); } else { // clicked nothing.. - context.selectedNoteID(null); if (!isMultiselect && mode.id !== 'browse') { context.enter(modeBrowse(context)); diff --git a/modules/modes/browse.js b/modules/modes/browse.js index 72484df62..acd9cc6f3 100644 --- a/modules/modes/browse.js +++ b/modules/modes/browse.js @@ -30,9 +30,7 @@ export function modeBrowse(context) { mode.enter = function() { - behaviors.forEach(function(behavior) { - context.install(behavior); - }); + behaviors.forEach(context.install); // Get focus on the body. if (document.activeElement && document.activeElement.blur) { @@ -49,9 +47,7 @@ export function modeBrowse(context) { mode.exit = function() { context.ui().sidebar.hover.cancel(); - behaviors.forEach(function(behavior) { - context.uninstall(behavior); - }); + behaviors.forEach(context.uninstall); if (sidebar) { context.ui().sidebar.hide(); diff --git a/modules/modes/index.js b/modules/modes/index.js index 83838c4e1..af440c4c2 100644 --- a/modules/modes/index.js +++ b/modules/modes/index.js @@ -11,4 +11,5 @@ export { modeMove } from './move'; export { modeRotate } from './rotate'; export { modeSave } from './save'; export { modeSelect } from './select'; +export { modeSelectData } from './select_data'; export { modeSelectNote } from './select_note'; diff --git a/modules/modes/rotate.js b/modules/modes/rotate.js index 4addaed88..12cac0fdd 100644 --- a/modules/modes/rotate.js +++ b/modules/modes/rotate.js @@ -120,9 +120,7 @@ export function modeRotate(context, entityIDs) { mode.enter = function() { - behaviors.forEach(function(behavior) { - context.install(behavior); - }); + behaviors.forEach(context.install); context.surface() .on('mousemove.rotate', doRotate) @@ -141,9 +139,7 @@ export function modeRotate(context, entityIDs) { mode.exit = function() { - behaviors.forEach(function(behavior) { - context.uninstall(behavior); - }); + behaviors.forEach(context.uninstall); context.surface() .on('mousemove.rotate', null) diff --git a/modules/modes/select.js b/modules/modes/select.js index 25e12400f..1d19eccc3 100644 --- a/modules/modes/select.js +++ b/modules/modes/select.js @@ -451,9 +451,7 @@ export function modeSelect(context, selectedIDs) { } }); - behaviors.forEach(function(behavior) { - context.install(behavior); - }); + behaviors.forEach(context.install); keybinding .on(['[', 'pgup'], previousVertex) @@ -522,10 +520,7 @@ export function modeSelect(context, selectedIDs) { if (timeout) window.clearTimeout(timeout); if (inspector) wrap.call(inspector.close); - behaviors.forEach(function(behavior) { - context.uninstall(behavior); - }); - + behaviors.forEach(context.uninstall); keybinding.off(); closeMenu(); editMenu = undefined; diff --git a/modules/modes/select_data.js b/modules/modes/select_data.js new file mode 100644 index 000000000..1e433660d --- /dev/null +++ b/modules/modes/select_data.js @@ -0,0 +1,97 @@ +import { + event as d3_event, + select as d3_select +} from 'd3-selection'; + +import { d3keybinding as d3_keybinding } from '../lib/d3.keybinding.js'; + +import { + behaviorBreathe, + behaviorHover, + behaviorLasso, + behaviorSelect +} from '../behavior'; + +import { + modeDragNode, + modeDragNote +} from '../modes'; + +import { modeBrowse } from './browse'; +import { uiDataEditor } from '../ui'; + + +export function modeSelectData(context, selectedDatum) { + var mode = { + id: 'select-data', + button: 'browse' + }; + + var keybinding = d3_keybinding('select-data'); + var dataEditor = uiDataEditor(context); + + var behaviors = [ + behaviorBreathe(context), + behaviorHover(context), + behaviorSelect(context), + behaviorLasso(context), + modeDragNode(context).behavior, + modeDragNote(context).behavior + ]; + + + // class the data as selected, or return to browse mode if the data is gone + function selectData(drawn) { + var selection = context.surface().selectAll('.layer-mapdata .data' + selectedDatum.__featurehash__); + + if (selection.empty()) { + // Return to browse mode if selected DOM elements have + // disappeared because the user moved them out of view.. + var source = d3_event && d3_event.type === 'zoom' && d3_event.sourceEvent; + if (drawn && source && (source.type === 'mousemove' || source.type === 'touchmove')) { + context.enter(modeBrowse(context)); + } + } else { + selection.classed('selected', true); + } + } + + + function esc() { + context.enter(modeBrowse(context)); + } + + + mode.enter = function() { + behaviors.forEach(context.install); + keybinding.on('⎋', esc, true); + d3_select(document).call(keybinding); + + selectData(); + + context.ui().sidebar + .show(dataEditor.datum(selectedDatum)); + + context.map() + .on('drawn.select-data', selectData); + }; + + + mode.exit = function() { + behaviors.forEach(context.uninstall); + keybinding.off(); + + context.surface() + .selectAll('.layer-mapdata .selected') + .classed('selected hover', false); + + context.map() + .on('drawn.select-data', null); + + context.ui().sidebar + .hide(); + }; + + + return mode; +} diff --git a/modules/modes/select_note.js b/modules/modes/select_note.js index c2eb8aba0..36246a207 100644 --- a/modules/modes/select_note.js +++ b/modules/modes/select_note.js @@ -60,52 +60,48 @@ export function modeSelectNote(context, selectedNoteID) { return note; } + + // class the note as selected, or return to browse mode if the note is gone + function selectNote(drawn) { + if (!checkSelectedID()) return; + + var selection = context.surface().selectAll('.layer-notes .note-' + selectedNoteID); + + if (selection.empty()) { + // Return to browse mode if selected DOM elements have + // disappeared because the user moved them out of view.. + var source = d3_event && d3_event.type === 'zoom' && d3_event.sourceEvent; + if (drawn && source && (source.type === 'mousemove' || source.type === 'touchmove')) { + context.enter(modeBrowse(context)); + } + + } else { + selection + .classed('selected', true); + context.selectedNoteID(selectedNoteID); + } + } + + + function esc() { + context.enter(modeBrowse(context)); + } + + mode.newFeature = function(_) { if (!arguments.length) return newFeature; newFeature = _; return mode; }; + mode.enter = function() { - - // class the note as selected, or return to browse mode if the note is gone - function selectNote(drawn) { - if (!checkSelectedID()) return; - - var selection = context.surface() - .selectAll('.note-' + selectedNoteID); - - if (selection.empty()) { - // Return to browse mode if selected DOM elements have - // disappeared because the user moved them out of view.. - var source = d3_event && d3_event.type === 'zoom' && d3_event.sourceEvent; - if (drawn && source && (source.type === 'mousemove' || source.type === 'touchmove')) { - context.enter(modeBrowse(context)); - } - - } else { - selection - .classed('selected', true); - context.selectedNoteID(selectedNoteID); - } - } - - function esc() { - context.enter(modeBrowse(context)); - } - var note = checkSelectedID(); if (!note) return; - behaviors.forEach(function(behavior) { - context.install(behavior); - }); - - keybinding - .on('⎋', esc, true); - - d3_select(document) - .call(keybinding); + behaviors.forEach(context.install); + keybinding.on('⎋', esc, true); + d3_select(document).call(keybinding); selectNote(); @@ -118,14 +114,11 @@ export function modeSelectNote(context, selectedNoteID) { mode.exit = function() { - behaviors.forEach(function(behavior) { - context.uninstall(behavior); - }); - + behaviors.forEach(context.uninstall); keybinding.off(); context.surface() - .selectAll('.note.selected') + .selectAll('.layer-notes .selected') .classed('selected hover', false); context.map() diff --git a/modules/renderer/map.js b/modules/renderer/map.js index 727ae3323..2878d8a48 100644 --- a/modules/renderer/map.js +++ b/modules/renderer/map.js @@ -348,7 +348,7 @@ export function rendererMap(context) { surface.selectAll('.layer-osm *').remove(); var mode = context.mode(); - if (mode && mode.id !== 'save' && mode.id !== 'select-note') { + if (mode && mode.id !== 'save' && mode.id !== 'select-note' && mode.id !== 'select-data') { context.enter(modeBrowse(context)); } diff --git a/modules/svg/data.js b/modules/svg/data.js index b902a7648..8be1a551c 100644 --- a/modules/svg/data.js +++ b/modules/svg/data.js @@ -179,6 +179,7 @@ export function svgData(projection, context, dispatch) { function drawData(selection) { var vtService = getService(); var getPath = svgPath(projection).geojson; + var getAreaPath = svgPath(projection, null, true).geojson; var hasData = drawData.hasData(); layer = selection.selectAll('.layer-mapdata') @@ -226,7 +227,7 @@ export function svgData(projection, context, dispatch) { clipPaths.merge(clipPathsEnter) .selectAll('path') - .attr('d', getPath); + .attr('d', getAreaPath); // Draw fill, shadow, stroke layers @@ -242,9 +243,9 @@ export function svgData(projection, context, dispatch) { // Draw paths var pathData = { + fill: polygonData, shadow: geoData, - stroke: geoData, - fill: polygonData + stroke: geoData }; var paths = datagroups @@ -267,7 +268,10 @@ export function svgData(projection, context, dispatch) { return datagroup === 'fill' ? ('url(#' + clipPathID(d) + ')') : null; }) .merge(paths) - .attr('d', getPath); + .attr('d', function(d) { + var datagroup = this.parentNode.__data__; + return datagroup === 'fill' ? getAreaPath(d) : getPath(d); + }); // Draw labels diff --git a/modules/ui/data_editor.js b/modules/ui/data_editor.js index 9adf0a528..593517de6 100644 --- a/modules/ui/data_editor.js +++ b/modules/ui/data_editor.js @@ -46,7 +46,7 @@ export function uiDataEditor(context) { var editor = body.selectAll('.data-editor') .data([0]); - editor = editor.enter() + editor.enter() .append('div') .attr('class', 'modal-section data-editor') .merge(editor)