From 8ba62ec4f6ddd45c61f559a5811ed05a8dfbc9a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nikola=20Forr=C3=B3?= Date: Fri, 21 Jun 2019 16:22:39 +0200 Subject: [PATCH] Improve UX of horde-map --- horde-map/map.css | 34 +++++-- horde-map/map.js | 254 ++++++++++++++++++++++++++++++++++------------ 2 files changed, 214 insertions(+), 74 deletions(-) diff --git a/horde-map/map.css b/horde-map/map.css index f0ecfd5..ff5be47 100644 --- a/horde-map/map.css +++ b/horde-map/map.css @@ -6,16 +6,36 @@ } .discord-control { - top: 4em; + bottom: 0.5rem; + left: 0.5rem; +} + +.discord-control button { + width: auto; + padding: 0.5rem; + font-size: 90%; +} + +.edit-control { + bottom: 2rem; left: 0.5em; } -.ol-touch .discord-control { - top: 5em; +.edit-control button:before { + font-family: 'Font Awesome 5 Free'; + font-weight: 900; + font-size: 80%; + content: '\f044'; } -.discord-control button { - width: auto; - padding: 0.5em; - font-size: 11pt; +.remove-control { + bottom: 2rem; + left: 2.5rem; +} + +.remove-control button:before { + font-family: 'Font Awesome 5 Free'; + font-weight: 900; + font-size: 80%; + content: '\f1f8'; } diff --git a/horde-map/map.js b/horde-map/map.js index a37c0ca..f2568af 100644 --- a/horde-map/map.js +++ b/horde-map/map.js @@ -1,5 +1,5 @@ -const membersApiUrl = 'https://lilia.mraveniste.cc/horde-members/api/members'; -const featuresApiUrl = 'https://lilia.mraveniste.cc/horde-members/api/features'; +const membersApiUrl = '/horde-members/api/members'; +const featuresApiUrl = '/horde-members/api/features'; const apiKey = 'eyJhbGciOiJIUzUxMiIsImlhdCI6MTU1Mzg5MjYwNSwiZXhwIjoxODY5MjUyNjA1fQ.ImNsaWVudCI.iX2EEEsKbMYpbeU-HB_FcqeepwZn8rkq8XdyfUmr6RJk2-64I744xLdKfrikxskF6_IlJbjBH3jNNcVfWyvswQ'; const discordClientId = '562565397451374593'; @@ -30,6 +30,59 @@ function remove(id) { }); } +function removePin() { + if (!discordUser) + return; + + var feature = source.forEachFeature((feature) => { + if (feature.get('id') == discordUser.id) + return feature; + }); + + if (feature === undefined) + return; + + if (confirm('Are you sure you want to remove yourself from the map?')) + { + source.removeFeature(feature); + + remove(discordUser.id); + + var button = editControl.element.firstElementChild; + button.style.display = 'none'; + + var button = removeControl.element.firstElementChild; + button.style.display = 'none'; + } +} + +function editNick(feature) { + if (!discordUser) + return; + + if (!feature) + feature = source.forEachFeature((feature) => { + if (feature.get('id') == discordUser.id) + return feature; + }); + + if (feature === undefined) + return; + + var nick = prompt('Edit nickname:', feature.get('nick')); + + if (nick !== null && nick != feature.get('nick')) { + feature.set('nick', nick); + + store(feature); + } +} + +document.addEventListener('keydown', (evt) => { + if (evt.code == 'Delete') + removePin(); +}); + function getColor(nick, alpha) { var r = 0; var g = 0; @@ -78,14 +131,25 @@ discord.onlogin = async () => { var user = await discord.fetchUser(); var guilds = await discord.fetchGuilds(); - var horde = guilds.find((guild) => guild.id == cheeseHordeGuildId); + var guild = guilds.find((guild) => guild.id == cheeseHordeGuildId); - if (horde !== undefined) { + if (guild !== undefined) { discordUser = user; var button = discordControl.element.firstElementChild; button.innerHTML = `${discordUser.username}: Log out`; button.style.display = null; + + var feature = source.forEachFeature((feature) => { + if (feature.get('id') == discordUser.id) + return feature; + }); + + var button = editControl.element.firstElementChild; + button.style.display = feature === undefined ? 'none' : null; + + var button = removeControl.element.firstElementChild; + button.style.display = feature === undefined ? 'none' : null; } } @@ -95,15 +159,13 @@ discord.onlogout = async () => { var button = discordControl.element.firstElementChild; button.innerHTML = 'Log in with Discord'; button.style.display = null; -}; -async function discordLogin() { - await discord.login(); -} + var button = editControl.element.firstElementChild; + button.style.display = 'none'; -async function discordLogout() { - await discord.logout(); -} + var button = removeControl.element.firstElementChild; + button.style.display = 'none'; +}; var DiscordControl = (function(Control) { function DiscordControl(opt_options) { @@ -130,11 +192,11 @@ var DiscordControl = (function(Control) { DiscordControl.prototype = Object.create(Control && Control.prototype); DiscordControl.prototype.constructor = DiscordControl; - DiscordControl.prototype.handleClick = function() { + DiscordControl.prototype.handleClick = async function() { if (!discordUser) - discordLogin(); + await discord.login(); else - discordLogout(); + await discord.logout(); }; return DiscordControl; @@ -142,6 +204,74 @@ var DiscordControl = (function(Control) { var discordControl = new DiscordControl(); +var EditControl = (function(Control) { + function EditControl(opt_options) { + var options = opt_options || {}; + + var button = document.createElement('button'); + button.style.display = 'none'; + + var element = document.createElement('div'); + element.className = 'edit-control ol-unselectable ol-control'; + element.appendChild(button); + + Control.call(this, { + element: element, + target: options.target + }); + + button.addEventListener('click', this.handleClick.bind(this), false); + } + + if (Control) + EditControl.__proto__ = Control; + + EditControl.prototype = Object.create(Control && Control.prototype); + EditControl.prototype.constructor = EditControl; + + EditControl.prototype.handleClick = function() { + editNick(); + }; + + return EditControl; +}(ol.control.Control)); + +var editControl = new EditControl(); + +var RemoveControl = (function(Control) { + function RemoveControl(opt_options) { + var options = opt_options || {}; + + var button = document.createElement('button'); + button.style.display = 'none'; + + var element = document.createElement('div'); + element.className = 'remove-control ol-unselectable ol-control'; + element.appendChild(button); + + Control.call(this, { + element: element, + target: options.target + }); + + button.addEventListener('click', this.handleClick.bind(this), false); + } + + if (Control) + RemoveControl.__proto__ = Control; + + RemoveControl.prototype = Object.create(Control && Control.prototype); + RemoveControl.prototype.constructor = RemoveControl; + + RemoveControl.prototype.handleClick = function() { + removePin(); + }; + + return RemoveControl; +}(ol.control.Control)); + +var removeControl = new RemoveControl(); + var source = new ol.source.Vector({ url: featuresApiUrl, wrapX: false, @@ -193,39 +323,24 @@ var map = new ol.Map({ zoom: 2 }), controls: ol.control.defaults().extend([ - discordControl + discordControl, + editControl, + removeControl ]) }); -var snap = new ol.interaction.Snap({ - source: source -}); - -map.addInteraction(snap); - -var modify = new ol.interaction.Modify({ - source: source, - condition: (evt) => { - if (!discordUser) - return false; - - var feature = source.getClosestFeatureToCoordinate(evt.coordinate); - - if (!feature) - return false; - - return feature.get('id') == discordUser.id; - } -}); - -modify.on('modifyend', (evt) => { - var feature = evt.features.getArray().find((feature) => feature.getRevision() > 1); +map.on('dblclick', (evt) => { + if (!discordUser) + return; - store(feature); + map.forEachFeatureAtPixel(evt.pixel, (feature) => { + if (feature.get('id') == discordUser.id) { + editNick(feature); + return true; + } + }); }); -map.addInteraction(modify); - var draw = new ol.interaction.Draw({ source: source, type: 'Point', @@ -238,17 +353,7 @@ var draw = new ol.interaction.Draw({ return feature; }); - if (feature === undefined) - return true; - - var features = []; - - // FIXME: allows duplication - map.forEachFeatureAtPixel(evt.pixel, (feature) => { - features.push(feature); - }); - - return features.length > 1; + return feature === undefined; } }); @@ -257,29 +362,44 @@ draw.on('drawend', (evt) => { evt.feature.set('nick', discordUser.username); store(evt.feature); + + var button = editControl.element.firstElementChild; + button.style.display = null; + + var button = removeControl.element.firstElementChild; + button.style.display = null; + + // hack + draw.lastDragTime_ = undefined; }); map.addInteraction(draw); -document.addEventListener('keydown', (evt) => { - if (evt.code != 'Delete') - return; +var snap = new ol.interaction.Snap({ + source: source +}); - if (!discordUser) - return; +map.addInteraction(snap); - var feature = source.forEachFeature((feature) => { - if (feature.get('id') == discordUser.id) - return feature; - }); +var modify = new ol.interaction.Modify({ + source: source, + condition: (evt) => { + if (!discordUser) + return false; - if (feature === undefined) - return; + var feature = source.getClosestFeatureToCoordinate(evt.coordinate); - if (confirm('Are you sure you want to remove yourself?')) - { - source.removeFeature(feature); + if (!feature) + return false; - remove(discordUser.id); + return feature.get('id') == discordUser.id; } }); + +modify.on('modifyend', (evt) => { + var feature = evt.features.getArray().find((feature) => feature.getRevision() > 1); + + store(feature); +}); + +map.addInteraction(modify);