"use strict"; function editMarker() { if (customization) return; closeDialogs("#markerEditor, .stable"); $("#markerEditor").dialog(); elSelected = d3.select(d3.event.target).call(d3.drag().on("start", dragMarker)).classed("draggable", true); updateInputs(); if (modules.editMarker) return; modules.editMarker = true; $("#markerEditor").dialog({ title: "Edit Marker", resizable: false, position: {my: "center top+30", at: "bottom", of: d3.event, collision: "fit"}, close: closeMarkerEditor }); // add listeners document.getElementById("markerGroup").addEventListener("click", toggleGroupSection); document.getElementById("markerAddGroup").addEventListener("click", toggleGroupInput); document.getElementById("markerSelectGroup").addEventListener("change", changeGroup); document.getElementById("markerInputGroup").addEventListener("change", createGroup); document.getElementById("markerRemoveGroup").addEventListener("click", removeGroup); document.getElementById("markerIcon").addEventListener("click", toggleIconSection); document.getElementById("markerIconSize").addEventListener("input", changeIconSize); document.getElementById("markerIconShiftX").addEventListener("input", changeIconShiftX); document.getElementById("markerIconShiftY").addEventListener("input", changeIconShiftY); document.getElementById("markerIconCustom").addEventListener("input", applyCustomUnicodeIcon); document.getElementById("markerStyle").addEventListener("click", toggleStyleSection); document.getElementById("markerSize").addEventListener("input", changeMarkerSize); document.getElementById("markerBaseStroke").addEventListener("input", changePinStroke); document.getElementById("markerBaseFill").addEventListener("input", changePinFill); document.getElementById("markerIconStrokeWidth").addEventListener("input", changeIconStrokeWidth); document.getElementById("markerIconStroke").addEventListener("input", changeIconStroke); document.getElementById("markerIconFill").addEventListener("input", changeIconFill); document.getElementById("markerToggleBubble").addEventListener("click", togglePinVisibility); document.getElementById("markerLegendButton").addEventListener("click", editMarkerLegend); document.getElementById("markerAdd").addEventListener("click", toggleAddMarker); document.getElementById("markerRemove").addEventListener("click", removeMarker); updateGroupOptions(); function dragMarker() { const tr = parseTransform(this.getAttribute("transform")); const x = +tr[0] - d3.event.x, y = +tr[1] - d3.event.y; d3.event.on("drag", function() { const transform = `translate(${(x + d3.event.x)},${(y + d3.event.y)})`; this.setAttribute("transform", transform); }); } function updateInputs() { const id = elSelected.attr("data-id"); const symbol = d3.select("#defs-markers").select(id); const icon = symbol.select("text"); markerSelectGroup.value = id.slice(1); markerIconSize.value = parseFloat(icon.attr("font-size")); markerIconShiftX.value = parseFloat(icon.attr("x")); markerIconShiftY.value = parseFloat(icon.attr("y")); markerSize.value = elSelected.attr("data-size"); markerBaseStroke.value = symbol.select("path").attr("fill"); markerBaseFill.value = symbol.select("circle").attr("fill"); markerIconStrokeWidth.value = icon.attr("stroke-width"); markerIconStroke.value = icon.attr("stroke"); markerIconFill.value = icon.attr("fill"); markerToggleBubble.className = symbol.select("circle").attr("opacity") === "0" ? "icon-info" : "icon-info-circled"; const table = document.getElementById("markerIconTable"); let selected = table.getElementsByClassName("selected"); if (selected.length) selected[0].removeAttribute("class"); selected = document.querySelectorAll("#markerIcon" + icon.text().codePointAt()); if (selected.length) selected[0].className = "selected"; markerIconCustom.value = selected.length ? "" : icon.text(); } function toggleGroupSection() { if (markerGroupSection.style.display === "inline-block") { markerEditor.querySelectorAll("button:not(#markerGroup)").forEach(b => b.style.display = "inline-block"); markerGroupSection.style.display = "none"; } else { markerEditor.querySelectorAll("button:not(#markerGroup)").forEach(b => b.style.display = "none"); markerGroupSection.style.display = "inline-block"; } } function updateGroupOptions() { markerSelectGroup.innerHTML = ""; d3.select("#defs-markers").selectAll("symbol").each(function() { markerSelectGroup.options.add(new Option(this.id, this.id)); }); markerSelectGroup.value = elSelected.attr("data-id").slice(1); } function toggleGroupInput() { if (markerInputGroup.style.display === "inline-block") { markerSelectGroup.style.display = "inline-block"; markerInputGroup.style.display = "none"; } else { markerSelectGroup.style.display = "none"; markerInputGroup.style.display = "inline-block"; markerInputGroup.focus(); } } function changeGroup() { elSelected.attr("xlink:href", "#"+this.value); elSelected.attr("data-id", "#"+this.value); } function createGroup() { let newGroup = this.value.toLowerCase().replace(/ /g, "_").replace(/[^\w\s]/gi, ""); if (Number.isFinite(+newGroup.charAt(0))) newGroup = "m" + newGroup; if (document.getElementById(newGroup)) { tip("Element with this id already exists. Please provide a unique name", false, "error"); return; } markerInputGroup.value = ""; // clone old group assigning new id const id = elSelected.attr("data-id"); const clone = d3.select("#defs-markers").select(id).node().cloneNode(true); clone.id = newGroup; document.getElementById("defs-markers").insertBefore(clone, null); elSelected.attr("xlink:href", "#"+newGroup).attr("data-id", "#"+newGroup); // select new group markerSelectGroup.options.add(new Option(newGroup, newGroup, false, true)); toggleGroupInput(); } function removeGroup() { const id = elSelected.attr("data-id"); const used = document.querySelectorAll("use[data-id='"+id+"']"); const count = used.length === 1 ? "1 element" : used.length + " elements"; alertMessage.innerHTML = "Are you sure you want to remove the marker (" + count + ")?"; $("#alert").dialog({resizable: false, title: "Remove marker", buttons: { Remove: function() { $(this).dialog("close"); if (id !== "#marker0") d3.select("#defs-markers").select(id).remove(); used.forEach(e => e.remove()); updateGroupOptions(); updateGroupOptions(); $("#markerEditor").dialog("close"); }, Cancel: function() {$(this).dialog("close");} } }); } function toggleIconSection() { if (markerIconSection.style.display === "inline-block") { markerEditor.querySelectorAll("button:not(#markerIcon)").forEach(b => b.style.display = "inline-block"); markerIconSection.style.display = "none"; } else { markerEditor.querySelectorAll("button:not(#markerIcon)").forEach(b => b.style.display = "none"); markerIconSection.style.display = "inline-block"; if (!markerIconTable.innerHTML) drawIconsList(); } } function drawIconsList() { let icons = [ // emoticons in FF: ["2693", "โš“", "Anchor"], ["26EA", "โ›ช", "Church"], ["1F3EF", "๐Ÿฏ", "Japanese Castle"], ["1F3F0", "๐Ÿฐ", "Castle"], ["1F5FC", "๐Ÿ—ผ", "Tower"], ["1F3E0", "๐Ÿ ", "House"], ["1F3AA", "๐ŸŽช", "Tent"], ["1F3E8", "๐Ÿจ", "Hotel"], ["1F4B0", "๐Ÿ’ฐ", "Money bag"], ["1F6A8", "๐Ÿšจ", "Revolving Light"], ["1F309", "๐ŸŒ‰", "Bridge at Night"], ["1F5FB", "๐Ÿ—ป", "Mountain"], ["1F30B", "๐ŸŒ‹", "Volcano"], ["270A", "โœŠ", "Raised Fist"], ["1F44A", "๐Ÿ‘Š", "Oncoming Fist"], ["1F4AA", "๐Ÿ’ช", "Flexed Biceps"], ["1F47C", "๐Ÿ‘ผ", "Baby Angel"], ["1F40E", "๐ŸŽ", "Horse"], ["1F434", "๐Ÿด", "Horse Face"], ["1F42E", "๐Ÿฎ", "Cow"], ["1F43A", "๐Ÿบ", "Wolf Face"], ["1F435", "๐Ÿต", "Monkey face"], ["1F437", "๐Ÿท", "Pig face"], ["1F414", "๐Ÿ”", "Chicken"], ["1F411", "๐Ÿ‘", "Ewe"], ["1F42B", "๐Ÿซ", "Camel"], ["1F418", "๐Ÿ˜", "Elephant"], ["1F422", "๐Ÿข", "Turtle"], ["1F40C", "๐ŸŒ", "Snail"], ["1F40D", "๐Ÿ", "Snake"], ["1F41D", "๐Ÿ", "Honeybee"], ["1F41C", "๐Ÿœ", "Ant"], ["1F41B", "๐Ÿ›", "Bug"], ["1F426", "๐Ÿฆ", "Bird"], ["1F438", "๐Ÿธ", "Frog Face"], ["1F433", "๐Ÿณ", "Whale"], ["1F42C", "๐Ÿฌ", "Dolphin"], ["1F420", "๐ŸŸ", "Fish"], ["1F480", "๐Ÿ’€", "Skull"], ["1F432", "๐Ÿฒ", "Dragon Head"], ["1F479", "๐Ÿ‘น", "Ogre"], ["1F47A", "๐Ÿ‘บ", "Goblin"], ["1F47B", "๐Ÿ‘ป", "Ghost"], ["1F47E", "๐Ÿ‘พ", "Alien"], ["1F383", "๐ŸŽƒ", "Jack-O-Lantern"], ["1F384", "๐ŸŽ„", "Christmas Tree"], ["1F334", "๐ŸŒด", "Palm"], ["1F335", "๐ŸŒต", "Cactus"], ["2618", "โ˜˜๏ธ", "Shamrock"], ["1F340", "๐Ÿ€", "Four Leaf Clover"], ["1F341", "๐Ÿ", "Maple Leaf"], ["1F33F", "๐ŸŒฟ", "Herb"], ["1F33E", "๐ŸŒพ", "Sheaf"], ["1F344", "๐Ÿ„", "Mushroom"], ["1F374", "๐Ÿด", "Fork and knife"], ["1F372", "๐Ÿฒ", "Food"], ["1F35E", "๐Ÿž", "Bread"], ["1F357", "๐Ÿ—", "Poultry leg"], ["1F347", "๐Ÿ‡", "Grapes"], ["1F34F", "๐Ÿ", "Apple"], ["1F352", "๐Ÿ’", "Cherries"], ["1F36F", "๐Ÿฏ", "Honey pot"], ["1F37A", "๐Ÿบ", "Beer"], ["1F37B", "๐Ÿป", "Beers"], ["1F377", "๐Ÿท", "Wine glass"], ["1F3BB", "๐ŸŽป", "Violin"], ["1F3B8", "๐ŸŽธ", "Guitar"], ["1F52A", "๐Ÿ”ช", "Knife"], ["1F52B", "๐Ÿ”ซ", "Pistol"], ["1F4A3", "๐Ÿ’ฃ", "Bomb"], ["1F4A5", "๐Ÿ’ฅ", "Collision"], ["1F4A8", "๐Ÿ’จ", "Dashing away"], ["1F301", "๐ŸŒ", "Foggy"], ["2744", "โ„๏ธ", "Snowflake"], ["26A1", "โšก", "Electricity"], ["1F320", "๐ŸŒ ", "Shooting star"], ["1F319", "๐ŸŒ™", "Crescent moon"], ["1F525", "๐Ÿ”ฅ", "Fire"], ["1F4A7", "๐Ÿ’ง", "Droplet"], ["1F30A", "๐ŸŒŠ", "Wave"], ["23F0", "โฐ", "Alarm Clock"], ["231B", "โŒ›", "Hourglass"], ["1F3C6", "๐Ÿ†", "Goblet"], ["26F2", "โ›ฒ", "Fountain"], ["26F5", "โ›ต", "Sailboat"], ["26FA", "โ›บ", "Campfire"], ["2764", "โค", "Red Heart"], ["1F498", "๐Ÿ’˜", "Heart With Arrow"], ["1F489", "๐Ÿ’‰", "Syringe"], ["1F4D5", "๐Ÿ“•", "Closed Book"], ["1F4D6", "๐Ÿ“š", "Books"], ["1F381", "๐ŸŽ", "Wrapped Gift"], ["1F3AF", "๐ŸŽฏ", "Archery"], ["1F52E", "๐Ÿ”ฎ", "Magic ball"], ["1F3AD", "๐ŸŽญ", "Performing arts"], ["1F3A8", "๐ŸŽจ", "Artist palette"], ["1F457", "๐Ÿ‘—", "Dress"], ["1F392", "๐ŸŽ’", "Backpack"], ["1F451", "๐Ÿ‘‘", "Crown"], ["1F48D", "๐Ÿ’", "Ring"], ["1F48E", "๐Ÿ’Ž", "Gem"], ["1F514", "๐Ÿ””", "Bell"], ["1F3B2", "๐ŸŽฒ", "Die"], // black and white icons in FF: ["26A0", "โš ", "Alert"], ["2317", "โŒ—", "Hash"], ["2318", "โŒ˜", "POI"], ["2307", "โŒ‡", "Wavy"], ["27F1", "โŸฑ", "Downwards Quadruple"], ["21E6", "โ‡ฆ", "Left arrow"], ["21E7", "โ‡ง", "Top arrow"], ["21E8", "โ‡จ", "Right arrow"], ["21E9", "โ‡ฉ", "Left arrow"], ["21F6", "โ‡ถ", "Three arrows"], ["2699", "โš™", "Gear"], ["269B", "โš›", "Atom"], ["2680", "โš€", "Die1"], ["2681", "โš", "Die2"], ["2682", "โš‚", "Die3"], ["2683", "โšƒ", "Die4"], ["2684", "โš„", "Die5"], ["2685", "โš…", "Die6"], ["26B4", "โšด", "Pallas"], ["26B5", "โšต", "Juno"], ["26B6", "โšถ", "Vesta"], ["26B7", "โšท", "Chiron"], ["26B8", "โšธ", "Lilith"], ["263F", "โ˜ฟ", "Mercury"], ["2640", "โ™€", "Venus"], ["2641", "โ™", "Earth"], ["2642", "โ™‚", "Mars"], ["2643", "โ™ƒ", "Jupiter"], ["2644", "โ™„", "Saturn"], ["2645", "โ™…", "Uranus"], ["2646", "โ™†", "Neptune"], ["2647", "โ™‡", "Pluto"], ["26B3", "โšณ", "Ceres"], ["2654", "โ™”", "Chess king"], ["2655", "โ™•", "Chess queen"], ["2656", "โ™–", "Chess rook"], ["2657", "โ™—", "Chess bishop"], ["2658", "โ™˜", "Chess knight"], ["2659", "โ™™", "Chess pawn"], ["2660", "โ™ ", "Spade"], ["2663", "โ™ฃ", "Club"], ["2665", "โ™ฅ", "Heart"], ["2666", "โ™ฆ", "Diamond"], ["2698", "โš˜", "Flower"], ["2625", "โ˜ฅ", "Ankh"], ["2626", "โ˜ฆ", "Orthodox"], ["2627", "โ˜ง", "Chi Rho"], ["2628", "โ˜จ", "Lorraine"], ["2629", "โ˜ฉ", "Jerusalem"], ["2670", "โ™ฐ", "Syriacย cross"], ["2020", "โ€ ", "Dagger"], ["262A", "โ˜ช", "Muslim"], ["262D", "โ˜ญ", "Soviet"], ["262E", "โ˜ฎ", "Peace"], ["262F", "โ˜ฏ", "Yin yang"], ["26A4", "โšค", "Heterosexuality"], ["26A2", "โšข", "Female homosexuality"], ["26A3", "โšฃ", "Male homosexuality"], ["26A5", "โšฅ", "Male and female"], ["26AD", "โšญ", "Rings"], ["2690", "โš", "White flag"], ["2691", "โš‘", "Black flag"], ["263C", "โ˜ผ", "Sun"], ["263E", "โ˜พ", "Moon"], ["2668", "โ™จ", "Hot springs"], ["2600", "โ˜€", "Black sun"], ["2601", "โ˜", "Cloud"], ["2602", "โ˜‚", "Umbrella"], ["2603", "โ˜ƒ", "Snowman"], ["2604", "โ˜„", "Comet"], ["2605", "โ˜…", "Black star"], ["2606", "โ˜†", "White star"], ["269D", "โš", "Outlined star"], ["2618", "โ˜˜", "Shamrock"], ["21AF", "โ†ฏ", "Lightning"], ["269C", "โšœ", "FleurDeLis"], ["2622", "โ˜ข", "Radiation"], ["2623", "โ˜ฃ", "Biohazard"], ["2620", "โ˜ ", "Skull"], ["2638", "โ˜ธ", "Dharma"], ["2624", "โ˜ค", "Caduceus"], ["2695", "โš•", "Aeculapius staff"], ["269A", "โšš", "Hermes staff"], ["2697", "โš—", "Alembic"], ["266B", "โ™ซ", "Music"], ["2702", "โœ‚", "Scissors"], ["2696", "โš–", "Scales"], ["2692", "โš’", "Hammer and pick"], ["2694", "โš”", "Swords"] ]; const table = document.getElementById("markerIconTable"); table.addEventListener("click", selectIcon, false); table.addEventListener("mouseover", hoverIcon, false); let row = ""; for (let i=0; i < icons.length; i++) { if (i%16 === 0) row = table.insertRow(0); const cell = row.insertCell(0); const icon = String.fromCodePoint(parseInt(icons[i][0], 16)); cell.innerHTML = icon; cell.id = "markerIcon" + icon.codePointAt(); cell.dataset.desc = icons[i][2]; } } function selectIcon(e) { if (e.target !== e.currentTarget) { const table = document.getElementById("markerIconTable"); const selected = table.getElementsByClassName("selected"); if (selected.length) selected[0].removeAttribute("class"); e.target.className = "selected"; const id = elSelected.attr("data-id"); const icon = e.target.innerHTML; d3.select("#defs-markers").select(id).select("text").text(icon); } e.stopPropagation(); } function hoverIcon(e) { if (e.target !== e.currentTarget) tip(e.target.innerHTML + " " + e.target.dataset.desc); e.stopPropagation(); } function changeIconSize() { const id = elSelected.attr("data-id"); d3.select("#defs-markers").select(id).select("text").attr("font-size", this.value + "px"); } function changeIconShiftX() { const id = elSelected.attr("data-id"); d3.select("#defs-markers").select(id).select("text").attr("x", this.value + "%"); } function changeIconShiftY() { const id = elSelected.attr("data-id"); d3.select("#defs-markers").select(id).select("text").attr("y", this.value + "%"); } function applyCustomUnicodeIcon() { if (!this.value) return; const id = elSelected.attr("data-id"); d3.select("#defs-markers").select(id).select("text").text(this.value); } function toggleStyleSection() { if (markerStyleSection.style.display === "inline-block") { markerEditor.querySelectorAll("button:not(#markerStyle)").forEach(b => b.style.display = "inline-block"); markerStyleSection.style.display = "none"; } else { markerEditor.querySelectorAll("button:not(#markerStyle)").forEach(b => b.style.display = "none"); markerStyleSection.style.display = "inline-block"; } } function changeMarkerSize() { const id = elSelected.attr("data-id"); document.querySelectorAll("use[data-id='"+id+"']").forEach(e => e.dataset.size = markerSize.value); invokeActiveZooming(); } function changePinStroke() { const id = elSelected.attr("data-id"); d3.select(id).select("path").attr("fill", this.value); d3.select(id).select("circle").attr("stroke", this.value); } function changePinFill() { const id = elSelected.attr("data-id"); d3.select(id).select("circle").attr("fill", this.value); } function changeIconStrokeWidth() { const id = elSelected.attr("data-id"); d3.select("#defs-markers").select(id).select("text").attr("stroke-width", this.value); } function changeIconStroke() { const id = elSelected.attr("data-id"); d3.select("#defs-markers").select(id).select("text").attr("stroke", this.value); } function changeIconFill() { const id = elSelected.attr("data-id"); d3.select("#defs-markers").select(id).select("text").attr("fill", this.value); } function togglePinVisibility() { const id = elSelected.attr("data-id"); let show = 1; if (this.className === "icon-info-circled") {this.className = "icon-info"; show = 0; } else this.className = "icon-info-circled"; d3.select(id).select("circle").attr("opacity", show); d3.select(id).select("path").attr("opacity", show); } function editMarkerLegend() { const id = elSelected.attr("id"); editNotes(id, id); } function toggleAddMarker() { document.getElementById("addMarker").click(); } function removeMarker() { alertMessage.innerHTML = "Are you sure you want to remove the marker?"; $("#alert").dialog({resizable: false, title: "Remove marker", buttons: { Remove: function() { $(this).dialog("close"); const index = notes.findIndex(n => n.id === elSelected.attr("id")); if (index != -1) notes.splice(index, 1); elSelected.remove(); $("#markerEditor").dialog("close"); }, Cancel: function() {$(this).dialog("close");} } }); } function closeMarkerEditor() { unselect(); if (addMarker.classList.contains("pressed")) addMarker.classList.remove("pressed"); if (markerAdd.classList.contains("pressed")) markerAdd.classList.remove("pressed"); restoreDefaultEvents(); clearMainTip(); } }