mirror of
https://github.com/FoggedLens/iD.git
synced 2026-03-31 01:09:22 +02:00
Merge pull request #4575 from openstreetmap/background_pane
Enhancements to Background, Map Data, Help panes
This commit is contained in:
315
css/80_app.css
315
css/80_app.css
@@ -130,7 +130,6 @@ a, button, input, textarea {
|
||||
a,
|
||||
button,
|
||||
.checkselect label:hover,
|
||||
.opacity-options li,
|
||||
.radial-menu-item {
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -268,7 +267,7 @@ table th {
|
||||
}
|
||||
|
||||
table.tags, table.tags td, table.tags th {
|
||||
border: 1px solid #CCC;
|
||||
border: 1px solid #ccc;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
@@ -304,7 +303,7 @@ ul li { list-style: none;}
|
||||
display: block;
|
||||
height: 30px;
|
||||
background-color: white;
|
||||
color: #7092FF;
|
||||
color: #7092ff;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@@ -740,6 +739,30 @@ button.save.has-count .count::before {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
|
||||
/* Hide-Toggle
|
||||
------------------------------------------------------- */
|
||||
|
||||
.hide-toggle .icon.pre-text {
|
||||
vertical-align: text-top;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-left: -3px;
|
||||
}
|
||||
[dir='rtl'] .hide-toggle .icon.pre-text {
|
||||
margin-left: 0;
|
||||
margin-right: -3px;
|
||||
}
|
||||
|
||||
a:visited.hide-toggle,
|
||||
a.hide-toggle {
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
|
||||
/* Inspector
|
||||
------------------------------------------------------- */
|
||||
|
||||
@@ -782,7 +805,6 @@ button.save.has-count .count::before {
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
|
||||
.feature-list-pane .inspector-body {
|
||||
top: 120px;
|
||||
}
|
||||
@@ -1071,7 +1093,7 @@ button.save.has-count .count::before {
|
||||
|
||||
.preset-list-item button.tag-reference-button {
|
||||
height: 100%;
|
||||
border: 1px solid #CCC;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 0 3px 3px 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
@@ -1143,7 +1165,7 @@ button.save.has-count .count::before {
|
||||
}
|
||||
|
||||
.preset-editor a.hide-toggle {
|
||||
margin: 0 20px 10px 20px;
|
||||
margin: 0 20px 5px 20px;
|
||||
}
|
||||
|
||||
.preset-editor .form-fields-container {
|
||||
@@ -1218,7 +1240,7 @@ button.save.has-count .count::before {
|
||||
}
|
||||
[dir='rtl'] .form-label button {
|
||||
border-left: none;
|
||||
border-right: 1px solid #CCC;
|
||||
border-right: 1px solid #ccc;
|
||||
border-radius: 4px 0 0 0;
|
||||
width: 31px;
|
||||
}
|
||||
@@ -1574,13 +1596,13 @@ input[type=number] {
|
||||
float: left;
|
||||
height: 100%;
|
||||
width: 32px;
|
||||
border-left: 1px solid #CCC;
|
||||
border-left: 1px solid #ccc;
|
||||
border-radius: 0;
|
||||
background: rgba(0, 0, 0, 0);
|
||||
}
|
||||
[dir='rtl'] .spin-control button{
|
||||
border-left: 0;
|
||||
border-right: 1px solid #CCC;
|
||||
border-right: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.spin-control button.decrement {
|
||||
@@ -1604,13 +1626,13 @@ input[type=number] {
|
||||
}
|
||||
|
||||
.spin-control button.decrement::after {
|
||||
border-top: 5px solid #CCC;
|
||||
border-top: 5px solid #ccc;
|
||||
border-left: 5px solid transparent;
|
||||
border-right: 5px solid transparent;
|
||||
}
|
||||
|
||||
.spin-control button.increment::after {
|
||||
border-bottom: 5px solid #CCC;
|
||||
border-bottom: 5px solid #ccc;
|
||||
border-left: 5px solid transparent;
|
||||
border-right: 5px solid transparent;
|
||||
}
|
||||
@@ -1622,7 +1644,7 @@ input[type=number] {
|
||||
display: block;
|
||||
background: white;
|
||||
padding: 5px 10px;
|
||||
color: #7092FF;
|
||||
color: #7092ff;
|
||||
}
|
||||
|
||||
.checkselect label:hover {
|
||||
@@ -1720,7 +1742,7 @@ input[type=number] {
|
||||
right: 1px;
|
||||
width: 32px;
|
||||
margin-left: -32px;
|
||||
border: 1px solid #CCC;
|
||||
border: 1px solid #ccc;
|
||||
border-top-width: 0;
|
||||
border-right-width: 0;
|
||||
border-radius: 0 0 4px 0;
|
||||
@@ -1938,12 +1960,12 @@ div.combobox {
|
||||
height: 31px;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
border-bottom: 1px solid #CCC;
|
||||
border-left: 1px solid #CCC;
|
||||
border-bottom: 1px solid #ccc;
|
||||
border-left: 1px solid #ccc;
|
||||
}
|
||||
[dir='rtl'] .tag-row input {
|
||||
border-left: none;
|
||||
border-right: 1px solid #CCC;
|
||||
border-right: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.tag-row .key-wrap,
|
||||
@@ -1963,14 +1985,14 @@ div.combobox {
|
||||
}
|
||||
|
||||
.tag-row input.value {
|
||||
border-right: 1px solid #CCC;
|
||||
border-right: 1px solid #ccc;
|
||||
}
|
||||
[dir='rtl'] .tag-row input.value {
|
||||
border-left: 1px solid #CCC;
|
||||
border-left: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.tag-row:first-child input.key {
|
||||
border-top: 1px solid #CCC;
|
||||
border-top: 1px solid #ccc;
|
||||
border-top-left-radius: 4px;
|
||||
}
|
||||
[dir='rtl'] .tag-row:first-child input.key {
|
||||
@@ -1979,14 +2001,14 @@ div.combobox {
|
||||
}
|
||||
|
||||
.tag-row:first-child input.value {
|
||||
border-top: 1px solid #CCC;
|
||||
border-top: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.tag-row button {
|
||||
position: absolute;
|
||||
height: 31px;
|
||||
right: 10%;
|
||||
border: 1px solid #CCC;
|
||||
border: 1px solid #ccc;
|
||||
border-top-width: 0;
|
||||
border-left-width: 0;
|
||||
}
|
||||
@@ -2246,16 +2268,12 @@ div.full-screen > button:hover {
|
||||
|
||||
.imagery-faq {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.map-data-control .hide-toggle,
|
||||
.background-control .hide-toggle {
|
||||
padding-bottom: 10px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.layer-list, .controls-list {
|
||||
margin-bottom: 10px;
|
||||
border: 1px solid #CCC;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
@@ -2263,7 +2281,7 @@ div.full-screen > button:hover {
|
||||
position: relative;
|
||||
height: 30px;
|
||||
background-color: white;
|
||||
color: #7092FF;
|
||||
color: #7092ff;
|
||||
}
|
||||
|
||||
.layer-list:empty {
|
||||
@@ -2292,7 +2310,7 @@ div.full-screen > button:hover {
|
||||
|
||||
.layer-list li.active,
|
||||
.layer-list li.switch {
|
||||
background: #E8EBFF;
|
||||
background: #e8ebff;
|
||||
}
|
||||
|
||||
.layer-list li.best > div.best {
|
||||
@@ -2324,60 +2342,38 @@ div.full-screen > button:hover {
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.minimap-toggle {
|
||||
display: block;
|
||||
padding: 5px 10px;
|
||||
cursor: pointer;
|
||||
color: #7092FF;
|
||||
border-radius: 3px;
|
||||
|
||||
/* Background Display Options */
|
||||
|
||||
.display-options-container {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.minimap-toggle.active {
|
||||
background: #E8EBFF;
|
||||
.display-control h5 {
|
||||
padding-bottom: 0;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.minimap-toggle:hover {
|
||||
background-color: #ececec;
|
||||
.display-control h5 span {
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.hide-toggle {
|
||||
display: block;
|
||||
padding-left: 12px;
|
||||
position: relative;
|
||||
}
|
||||
[dir='rtl'] .hide-toggle {
|
||||
padding-left: 0;
|
||||
padding-right: 12px;
|
||||
.display-control .display-option-input {
|
||||
height: 20px;
|
||||
width: 160px;
|
||||
}
|
||||
|
||||
.hide-toggle:before {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
height: 0;
|
||||
width: 0;
|
||||
left: 0;
|
||||
top: 5px;
|
||||
border-top: 4px solid transparent;
|
||||
border-bottom: 4px solid transparent;
|
||||
border-left: 8px solid #7092ff;
|
||||
.display-control button {
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
margin-left: 5px;
|
||||
margin-right: 0px;
|
||||
vertical-align: text-bottom;
|
||||
border-radius: 4px;
|
||||
}
|
||||
[dir='rtl'] .hide-toggle:before {
|
||||
left: auto;
|
||||
right: 0;
|
||||
border-left: none;
|
||||
border-right: 8px solid #7092ff;
|
||||
}
|
||||
|
||||
.hide-toggle.expanded:before {
|
||||
border-top: 8px solid #7092ff;
|
||||
border-bottom: 0;
|
||||
border-right: 4px solid transparent;
|
||||
border-left: 4px solid transparent;
|
||||
}
|
||||
[dir='rtl'] .hide-toggle.expanded:before {
|
||||
border-left: 4px solid transparent;
|
||||
border-right: 4px solid transparent;
|
||||
[dir='rtl'] .display-control button {
|
||||
margin-left: 0px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
|
||||
@@ -2433,7 +2429,7 @@ div.full-screen > button:hover {
|
||||
}
|
||||
|
||||
.nudge-container input.error {
|
||||
border: 1px solid #FF7878;
|
||||
border: 1px solid #ff7878;
|
||||
border-radius: 2px;
|
||||
background: #ffb;
|
||||
}
|
||||
@@ -2485,92 +2481,43 @@ div.full-screen > button:hover {
|
||||
}
|
||||
|
||||
.background-control .nudge.right::after {
|
||||
border-top: 5px solid transparent;
|
||||
border-bottom: 5px solid transparent;
|
||||
border-left: 5px solid #222;
|
||||
border-top: 5px solid transparent;
|
||||
border-bottom: 5px solid transparent;
|
||||
border-left: 5px solid #222;
|
||||
}
|
||||
|
||||
.background-control .nudge.left::after {
|
||||
border-top: 5px solid transparent;
|
||||
border-bottom: 5px solid transparent;
|
||||
border-right: 5px solid #222;
|
||||
border-top: 5px solid transparent;
|
||||
border-bottom: 5px solid transparent;
|
||||
border-right: 5px solid #222;
|
||||
}
|
||||
|
||||
.background-control .nudge.top::after {
|
||||
border-right: 5px solid transparent;
|
||||
border-left: 5px solid transparent;
|
||||
border-bottom: 5px solid #222;
|
||||
border-right: 5px solid transparent;
|
||||
border-left: 5px solid transparent;
|
||||
border-bottom: 5px solid #222;
|
||||
}
|
||||
|
||||
.background-control .nudge.bottom::after {
|
||||
border-right: 5px solid transparent;
|
||||
border-left: 5px solid transparent;
|
||||
border-top: 5px solid #222;
|
||||
border-right: 5px solid transparent;
|
||||
border-left: 5px solid transparent;
|
||||
border-top: 5px solid #222;
|
||||
}
|
||||
|
||||
.opacity-options {
|
||||
background: url(img/background-pattern-opacity.png) 0 0 repeat;
|
||||
height: 20px;
|
||||
width: 82px;
|
||||
position: absolute;
|
||||
right: 50px;
|
||||
top: 20px;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
[dir='rtl'] .opacity-options {
|
||||
left: 50px;
|
||||
right: auto;
|
||||
}
|
||||
|
||||
.opacity-options li {
|
||||
height: 100%;
|
||||
display: block;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.opacity-options li .select-box{
|
||||
position: absolute;
|
||||
width: 20px;
|
||||
height: 18px;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.map-data-control li:hover .select-box,
|
||||
.map-data-control li.selected .select-box,
|
||||
.background-control li:hover .select-box,
|
||||
.background-control li.selected .select-box {
|
||||
border: 2px solid #7092ff;
|
||||
background: rgba(89, 123, 231, .5);
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
.map-data-control li.selected:hover .select-box,
|
||||
.map-data-control li.selected .select-box,
|
||||
.background-control li.selected:hover .select-box,
|
||||
.background-control li.selected .select-box {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.background-control .opacity {
|
||||
background:#222;
|
||||
display:inline-block;
|
||||
width:20px;
|
||||
height:18px;
|
||||
}
|
||||
|
||||
.map-data-control .layer-list button,
|
||||
.background-control .layer-list button {
|
||||
float: right;
|
||||
height: 100%;
|
||||
width: 10%;
|
||||
border-left: 1px solid #CCC;
|
||||
border-left: 1px solid #ccc;
|
||||
border-radius: 0;
|
||||
}
|
||||
[dir='rtl'] .map-data-control .layer-list button,
|
||||
[dir='rtl'] .background-control .layer-list button {
|
||||
float: left;
|
||||
border-left: none;
|
||||
border-right: 1px solid #CCC;
|
||||
border-right: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.map-data-control .layer-list button .icon,
|
||||
@@ -2603,12 +2550,12 @@ div.full-screen > button:hover {
|
||||
border-radius: 0 0 0 4px;
|
||||
}
|
||||
[dir='rtl'] .geolocate-control button {
|
||||
border-radius: 0 0 4px 0;
|
||||
border-radius: 0 0 4px 0;
|
||||
}
|
||||
|
||||
.map-overlay.content {
|
||||
position: fixed;
|
||||
top:60px;
|
||||
top: 60px;
|
||||
bottom: 30px;
|
||||
padding: 20px 50px 20px 20px;
|
||||
right: 0;
|
||||
@@ -2620,13 +2567,17 @@ div.full-screen > button:hover {
|
||||
right: auto !important;
|
||||
}
|
||||
|
||||
.map-overlay.content > div {
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
||||
/* Help */
|
||||
|
||||
.help-control button {
|
||||
border-radius: 0 0 0 4px;
|
||||
}
|
||||
[dir='rtl'] .help-control button {
|
||||
border-radius: 0 0 4px 0;
|
||||
border-radius: 0 0 4px 0;
|
||||
}
|
||||
|
||||
.help-wrap p {
|
||||
@@ -2655,7 +2606,7 @@ div.full-screen > button:hover {
|
||||
}
|
||||
|
||||
.help-wrap .toc {
|
||||
width:40%;
|
||||
width: 40%;
|
||||
float:right;
|
||||
margin-left: 20px;
|
||||
margin-bottom: 20px;
|
||||
@@ -2732,12 +2683,12 @@ div.full-screen > button:hover {
|
||||
------------------------------------------------------- */
|
||||
|
||||
img.tile {
|
||||
position:absolute;
|
||||
transform-origin:0 0;
|
||||
-ms-transform-origin:0 0;
|
||||
-webkit-transform-origin:0 0;
|
||||
-moz-transform-origin:0 0;
|
||||
-o-transform-origin:0 0;
|
||||
position: absolute;
|
||||
transform-origin: 0 0;
|
||||
-ms-transform-origin: 0 0;
|
||||
-webkit-transform-origin: 0 0;
|
||||
-moz-transform-origin: 0 0;
|
||||
-o-transform-origin: 0 0;
|
||||
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
@@ -2747,8 +2698,16 @@ img.tile {
|
||||
opacity: 0;
|
||||
|
||||
-webkit-transition: opacity 200ms linear;
|
||||
transition: opacity 200ms linear;
|
||||
-moz-transition: opacity 200ms linear;
|
||||
transition: opacity 200ms linear;
|
||||
}
|
||||
|
||||
img.tile-loaded {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
img.tile-removing {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.tile-label-debug {
|
||||
@@ -2763,11 +2722,11 @@ img.tile {
|
||||
margin-left: -70px;
|
||||
margin-top: -20px;
|
||||
|
||||
transform-origin:0 0;
|
||||
-ms-transform-origin:0 0;
|
||||
-webkit-transform-origin:0 0;
|
||||
-moz-transform-origin:0 0;
|
||||
-o-transform-origin:0 0;
|
||||
transform-origin: 0 0;
|
||||
-ms-transform-origin: 0 0;
|
||||
-webkit-transform-origin: 0 0;
|
||||
-moz-transform-origin: 0 0;
|
||||
-o-transform-origin: 0 0;
|
||||
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
@@ -2779,23 +2738,15 @@ img.tile-debug {
|
||||
outline: 1px solid red;
|
||||
}
|
||||
|
||||
img.tile-loaded {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
img.tile-removing {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
|
||||
/* Map
|
||||
------------------------------------------------------- */
|
||||
|
||||
#map {
|
||||
position:relative;
|
||||
overflow:hidden;
|
||||
height:100%;
|
||||
background:#000;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
background: #000;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
@@ -2803,11 +2754,11 @@ img.tile-removing {
|
||||
}
|
||||
|
||||
#supersurface {
|
||||
transform-origin:0 0;
|
||||
-ms-transform-origin:0 0;
|
||||
-webkit-transform-origin:0 0;
|
||||
-moz-transform-origin:0 0;
|
||||
-o-transform-origin:0 0;
|
||||
transform-origin: 0 0;
|
||||
-ms-transform-origin: 0 0;
|
||||
-webkit-transform-origin: 0 0;
|
||||
-moz-transform-origin: 0 0;
|
||||
-o-transform-origin: 0 0;
|
||||
}
|
||||
|
||||
#supersurface, .layer {
|
||||
@@ -3368,7 +3319,7 @@ img.tile-removing {
|
||||
|
||||
.modal-section {
|
||||
padding: 20px;
|
||||
border-bottom: 1px solid #CCC;
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.modal-section.header h3 {
|
||||
@@ -3401,8 +3352,8 @@ img.tile-removing {
|
||||
.modal-actions button,
|
||||
.save-success a.button {
|
||||
font-weight: normal;
|
||||
color: #7092FF;
|
||||
border-bottom: 1px solid #CCC;
|
||||
color: #7092ff;
|
||||
border-bottom: 1px solid #ccc;
|
||||
border-radius: 0;
|
||||
height: 160px;
|
||||
text-align: center;
|
||||
@@ -3422,7 +3373,7 @@ img.tile-removing {
|
||||
}
|
||||
|
||||
.modal-actions > :first-child {
|
||||
border-right: 1px solid #CCC;
|
||||
border-right: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.modal-section:last-child {
|
||||
@@ -3432,7 +3383,7 @@ img.tile-removing {
|
||||
/* Restore Modal
|
||||
------------------------------------------------------- */
|
||||
.modal-actions .logo-restore {
|
||||
color: #7092FF;
|
||||
color: #7092ff;
|
||||
}
|
||||
.modal-actions .logo-reset {
|
||||
color: #E06C5E;
|
||||
@@ -3450,7 +3401,7 @@ img.tile-removing {
|
||||
padding-top: 15px;
|
||||
}
|
||||
.save-success .logo-osm {
|
||||
color: #7092FF;
|
||||
color: #7092ff;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.save-success a.button.social {
|
||||
@@ -3460,14 +3411,14 @@ img.tile-removing {
|
||||
.save-success .icon.social {
|
||||
height: 80px;
|
||||
width: 80px;
|
||||
color: #7092FF;
|
||||
color: #7092ff;
|
||||
}
|
||||
|
||||
/* Splash Modal
|
||||
------------------------------------------------------- */
|
||||
.modal-actions .logo-walkthrough,
|
||||
.modal-actions .logo-features {
|
||||
color: #7092FF;
|
||||
color: #7092ff;
|
||||
}
|
||||
|
||||
|
||||
@@ -3658,7 +3609,7 @@ svg.mouseclick use.right {
|
||||
}
|
||||
|
||||
.mode-save .commit-section .changeset-list button {
|
||||
border-left: 1px solid #CCC;
|
||||
border-left: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.changeset-list li span.count:before { content: '('; }
|
||||
@@ -4215,7 +4166,7 @@ li.hide + li.version .badge .tooltip .tooltip-arrow {
|
||||
.curtain-tooltip .tooltip-inner .instruction {
|
||||
font-weight: bold;
|
||||
display: block;
|
||||
border-top: 1px solid #CCC;
|
||||
border-top: 1px solid #ccc;
|
||||
margin-top: 10px;
|
||||
margin-left: -20px;
|
||||
margin-right: -20px;
|
||||
@@ -4293,5 +4244,5 @@ li.hide + li.version .badge .tooltip .tooltip-arrow {
|
||||
.huge-modal-button .illustration {
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
color: #7092FF;
|
||||
color: #7092ff;
|
||||
}
|
||||
|
||||
@@ -375,21 +375,27 @@ en:
|
||||
title: Background
|
||||
description: Background settings
|
||||
key: B
|
||||
percent_brightness: "{opacity}% brightness"
|
||||
backgrounds: Backgrounds
|
||||
none: None
|
||||
best_imagery: Best known imagery source for this location
|
||||
switch: Switch back to this background
|
||||
custom: Custom
|
||||
custom_button: Edit custom background
|
||||
custom_prompt: "Enter a tile URL template. Valid tokens are:\n - {zoom}/{z}, {x}, {y} for Z/X/Y tile scheme\n - {ty} for flipped TMS-style Y coordinates\n - {u} for quadtile scheme\n - {switch:a,b,c} for DNS server multiplexing\n\nExample:\n{example}"
|
||||
fix_misalignment: Adjust imagery offset
|
||||
imagery_source_faq: Where does this imagery come from?
|
||||
overlays: Overlays
|
||||
imagery_source_faq: Imagery Info / Report a Problem
|
||||
reset: reset
|
||||
offset: "Drag anywhere in the gray area below to adjust the imagery offset, or enter the offset values in meters."
|
||||
display_options: Display Options
|
||||
brightness: Brightness
|
||||
contrast: Contrast
|
||||
saturation: Saturation
|
||||
sharpness: Sharpness
|
||||
minimap:
|
||||
description: Minimap
|
||||
description: Show Minimap
|
||||
tooltip: Show a zoomed out map to help locate the area currently displayed.
|
||||
key: '/'
|
||||
fix_misalignment: Adjust imagery offset
|
||||
offset: "Drag anywhere in the gray area below to adjust the imagery offset, or enter the offset values in meters."
|
||||
map_data:
|
||||
title: Map Data
|
||||
description: Map Data
|
||||
|
||||
18
dist/locales/en.json
vendored
18
dist/locales/en.json
vendored
@@ -464,22 +464,28 @@
|
||||
"title": "Background",
|
||||
"description": "Background settings",
|
||||
"key": "B",
|
||||
"percent_brightness": "{opacity}% brightness",
|
||||
"backgrounds": "Backgrounds",
|
||||
"none": "None",
|
||||
"best_imagery": "Best known imagery source for this location",
|
||||
"switch": "Switch back to this background",
|
||||
"custom": "Custom",
|
||||
"custom_button": "Edit custom background",
|
||||
"custom_prompt": "Enter a tile URL template. Valid tokens are:\n - {zoom}/{z}, {x}, {y} for Z/X/Y tile scheme\n - {ty} for flipped TMS-style Y coordinates\n - {u} for quadtile scheme\n - {switch:a,b,c} for DNS server multiplexing\n\nExample:\n{example}",
|
||||
"fix_misalignment": "Adjust imagery offset",
|
||||
"imagery_source_faq": "Where does this imagery come from?",
|
||||
"overlays": "Overlays",
|
||||
"imagery_source_faq": "Imagery Info / Report a Problem",
|
||||
"reset": "reset",
|
||||
"offset": "Drag anywhere in the gray area below to adjust the imagery offset, or enter the offset values in meters.",
|
||||
"display_options": "Display Options",
|
||||
"brightness": "Brightness",
|
||||
"contrast": "Contrast",
|
||||
"saturation": "Saturation",
|
||||
"sharpness": "Sharpness",
|
||||
"minimap": {
|
||||
"description": "Minimap",
|
||||
"description": "Show Minimap",
|
||||
"tooltip": "Show a zoomed out map to help locate the area currently displayed.",
|
||||
"key": "/"
|
||||
}
|
||||
},
|
||||
"fix_misalignment": "Adjust imagery offset",
|
||||
"offset": "Drag anywhere in the gray area below to adjust the imagery offset, or enter the offset values in meters."
|
||||
},
|
||||
"map_data": {
|
||||
"title": "Map Data",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import _find from 'lodash-es/find';
|
||||
|
||||
import { dispatch as d3_dispatch } from 'd3-dispatch';
|
||||
import { interpolateNumber as d3_interpolateNumber } from 'd3-interpolate';
|
||||
import { select as d3_select } from 'd3-selection';
|
||||
|
||||
import { data } from '../../data';
|
||||
@@ -12,24 +13,83 @@ import { utilRebind } from '../util/rebind';
|
||||
|
||||
|
||||
export function rendererBackground(context) {
|
||||
var dispatch = d3_dispatch('change'),
|
||||
baseLayer = rendererTileLayer(context).projection(context.projection),
|
||||
overlayLayers = [],
|
||||
backgroundSources;
|
||||
var dispatch = d3_dispatch('change');
|
||||
var baseLayer = rendererTileLayer(context).projection(context.projection);
|
||||
var _overlayLayers = [];
|
||||
var _backgroundSources = [];
|
||||
var _brightness = 1;
|
||||
var _contrast = 1;
|
||||
var _saturation = 1;
|
||||
var _sharpness = 1;
|
||||
|
||||
|
||||
function background(selection) {
|
||||
var baseFilter = '';
|
||||
|
||||
if (_brightness !== 1) {
|
||||
baseFilter += 'brightness(' + _brightness + ')';
|
||||
}
|
||||
if (_contrast !== 1) {
|
||||
baseFilter += 'contrast(' + _contrast + ')';
|
||||
}
|
||||
if (_saturation !== 1) {
|
||||
baseFilter += 'saturate(' + _saturation + ')';
|
||||
}
|
||||
if (_sharpness < 1) { // gaussian blur
|
||||
var blur = d3_interpolateNumber(0.5, 5)(1 - _sharpness);
|
||||
baseFilter += 'blur(' + blur + 'px)';
|
||||
}
|
||||
|
||||
var base = selection.selectAll('.layer-background')
|
||||
.data([0]);
|
||||
|
||||
base.enter()
|
||||
base = base.enter()
|
||||
.insert('div', '.layer-data')
|
||||
.attr('class', 'layer layer-background')
|
||||
.merge(base)
|
||||
.style('filter', baseFilter || null);
|
||||
|
||||
|
||||
var imagery = base.selectAll('.layer-imagery')
|
||||
.data([0]);
|
||||
|
||||
imagery.enter()
|
||||
.append('div')
|
||||
.attr('class', 'layer layer-imagery')
|
||||
.merge(imagery)
|
||||
.call(baseLayer);
|
||||
|
||||
|
||||
var maskFilter = '';
|
||||
var mixBlendMode = '';
|
||||
if (_sharpness > 1) { // apply unsharp mask
|
||||
mixBlendMode = 'overlay';
|
||||
maskFilter = 'saturate(0) blur(3px) invert(1)';
|
||||
|
||||
var contrast = _sharpness - 1;
|
||||
maskFilter += ' contrast(' + contrast + ')';
|
||||
|
||||
var brightness = d3_interpolateNumber(1, 0.85)(_sharpness - 1);
|
||||
maskFilter += ' brightness(' + brightness + ')';
|
||||
}
|
||||
|
||||
var mask = base.selectAll('.layer-unsharp-mask')
|
||||
.data(_sharpness > 1 ? [0] : []);
|
||||
|
||||
mask.exit()
|
||||
.remove();
|
||||
|
||||
mask.enter()
|
||||
.append('div')
|
||||
.attr('class', 'layer layer-mask layer-unsharp-mask')
|
||||
.merge(mask)
|
||||
.call(baseLayer)
|
||||
.style('filter', maskFilter || null)
|
||||
.style('mix-blend-mode', mixBlendMode || null);
|
||||
|
||||
|
||||
var overlays = selection.selectAll('.layer-overlay')
|
||||
.data(overlayLayers, function(d) { return d.source().name(); });
|
||||
.data(_overlayLayers, function(d) { return d.source().name(); });
|
||||
|
||||
overlays.exit()
|
||||
.remove();
|
||||
@@ -46,7 +106,7 @@ export function rendererBackground(context) {
|
||||
if (context.inIntro()) return;
|
||||
|
||||
var b = background.baseLayerSource(),
|
||||
o = overlayLayers
|
||||
o = _overlayLayers
|
||||
.filter(function (d) { return !d.source().isLocatorOverlay() && !d.source().isHidden(); })
|
||||
.map(function (d) { return d.source().id; })
|
||||
.join(','),
|
||||
@@ -85,7 +145,7 @@ export function rendererBackground(context) {
|
||||
|
||||
var imageryUsed = [b.imageryUsed()];
|
||||
|
||||
overlayLayers
|
||||
_overlayLayers
|
||||
.filter(function (d) { return !d.source().isLocatorOverlay() && !d.source().isHidden(); })
|
||||
.forEach(function (d) { imageryUsed.push(d.source().imageryUsed()); });
|
||||
|
||||
@@ -117,7 +177,7 @@ export function rendererBackground(context) {
|
||||
|
||||
|
||||
background.sources = function(extent) {
|
||||
return backgroundSources.filter(function(source) {
|
||||
return _backgroundSources.filter(function(source) {
|
||||
return source.intersects(extent);
|
||||
});
|
||||
};
|
||||
@@ -127,7 +187,7 @@ export function rendererBackground(context) {
|
||||
if (!_) return;
|
||||
baseLayer.dimensions(_);
|
||||
|
||||
overlayLayers.forEach(function(layer) {
|
||||
_overlayLayers.forEach(function(layer) {
|
||||
layer.dimensions(_);
|
||||
});
|
||||
};
|
||||
@@ -172,7 +232,7 @@ export function rendererBackground(context) {
|
||||
|
||||
|
||||
background.findSource = function(id) {
|
||||
return _find(backgroundSources, function(d) {
|
||||
return _find(_backgroundSources, function(d) {
|
||||
return d.id && d.id === id;
|
||||
});
|
||||
};
|
||||
@@ -185,22 +245,22 @@ export function rendererBackground(context) {
|
||||
|
||||
background.showsLayer = function(d) {
|
||||
return d.id === baseLayer.source().id ||
|
||||
overlayLayers.some(function(layer) { return d.id === layer.source().id; });
|
||||
_overlayLayers.some(function(layer) { return d.id === layer.source().id; });
|
||||
};
|
||||
|
||||
|
||||
background.overlayLayerSources = function() {
|
||||
return overlayLayers.map(function (l) { return l.source(); });
|
||||
return _overlayLayers.map(function (l) { return l.source(); });
|
||||
};
|
||||
|
||||
|
||||
background.toggleOverlayLayer = function(d) {
|
||||
var layer;
|
||||
|
||||
for (var i = 0; i < overlayLayers.length; i++) {
|
||||
layer = overlayLayers[i];
|
||||
for (var i = 0; i < _overlayLayers.length; i++) {
|
||||
layer = _overlayLayers[i];
|
||||
if (layer.source() === d) {
|
||||
overlayLayers.splice(i, 1);
|
||||
_overlayLayers.splice(i, 1);
|
||||
dispatch.call('change');
|
||||
background.updateImagery();
|
||||
return;
|
||||
@@ -210,9 +270,10 @@ export function rendererBackground(context) {
|
||||
layer = rendererTileLayer(context)
|
||||
.source(d)
|
||||
.projection(context.projection)
|
||||
.dimensions(baseLayer.dimensions());
|
||||
.dimensions(baseLayer.dimensions()
|
||||
);
|
||||
|
||||
overlayLayers.push(layer);
|
||||
_overlayLayers.push(layer);
|
||||
dispatch.call('change');
|
||||
background.updateImagery();
|
||||
};
|
||||
@@ -235,6 +296,38 @@ export function rendererBackground(context) {
|
||||
};
|
||||
|
||||
|
||||
background.brightness = function(d) {
|
||||
if (!arguments.length) return _brightness;
|
||||
_brightness = d;
|
||||
if (context.mode()) dispatch.call('change');
|
||||
return background;
|
||||
};
|
||||
|
||||
|
||||
background.contrast = function(d) {
|
||||
if (!arguments.length) return _contrast;
|
||||
_contrast = d;
|
||||
if (context.mode()) dispatch.call('change');
|
||||
return background;
|
||||
};
|
||||
|
||||
|
||||
background.saturation = function(d) {
|
||||
if (!arguments.length) return _saturation;
|
||||
_saturation = d;
|
||||
if (context.mode()) dispatch.call('change');
|
||||
return background;
|
||||
};
|
||||
|
||||
|
||||
background.sharpness = function(d) {
|
||||
if (!arguments.length) return _sharpness;
|
||||
_sharpness = d;
|
||||
if (context.mode()) dispatch.call('change');
|
||||
return background;
|
||||
};
|
||||
|
||||
|
||||
background.init = function() {
|
||||
function parseMap(qmap) {
|
||||
if (!qmap) return false;
|
||||
@@ -251,7 +344,7 @@ export function rendererBackground(context) {
|
||||
best;
|
||||
|
||||
// Add all the available imagery sources
|
||||
backgroundSources = dataImagery.map(function(source) {
|
||||
_backgroundSources = dataImagery.map(function(source) {
|
||||
if (source.type === 'bing') {
|
||||
return rendererBackgroundSource.Bing(source, dispatch);
|
||||
} else if (source.id === 'EsriWorldImagery') {
|
||||
@@ -261,15 +354,15 @@ export function rendererBackground(context) {
|
||||
}
|
||||
});
|
||||
|
||||
first = backgroundSources.length && backgroundSources[0];
|
||||
first = _backgroundSources.length && _backgroundSources[0];
|
||||
|
||||
// Add 'None'
|
||||
backgroundSources.unshift(rendererBackgroundSource.None());
|
||||
_backgroundSources.unshift(rendererBackgroundSource.None());
|
||||
|
||||
// Add 'Custom'
|
||||
var template = context.storage('background-custom-template') || '';
|
||||
var custom = rendererBackgroundSource.Custom(template);
|
||||
backgroundSources.unshift(custom);
|
||||
_backgroundSources.unshift(custom);
|
||||
|
||||
|
||||
// Decide which background layer to display
|
||||
@@ -290,7 +383,7 @@ export function rendererBackground(context) {
|
||||
);
|
||||
}
|
||||
|
||||
var locator = _find(backgroundSources, function(d) {
|
||||
var locator = _find(_backgroundSources, function(d) {
|
||||
return d.overlay && d.default;
|
||||
});
|
||||
|
||||
|
||||
@@ -7,439 +7,237 @@ import {
|
||||
|
||||
import {
|
||||
event as d3_event,
|
||||
select as d3_select,
|
||||
selectAll as d3_selectAll
|
||||
select as d3_select
|
||||
} from 'd3-selection';
|
||||
|
||||
import { d3keybinding as d3_keybinding } from '../lib/d3.keybinding.js';
|
||||
|
||||
import { t, textDirection } from '../util/locale';
|
||||
import { geoMetersToOffset, geoOffsetToMeters } from '../geo';
|
||||
import { utilDetect } from '../util/detect';
|
||||
import { utilSetTransform, utilCallWhenIdle } from '../util';
|
||||
import { svgIcon } from '../svg';
|
||||
import { uiMapInMap } from './map_in_map';
|
||||
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'),
|
||||
detected = utilDetect(),
|
||||
opacities = [1, 0.75, 0.5, 0.25],
|
||||
directions = [
|
||||
['right', [0.5, 0]],
|
||||
['top', [0, -0.5]],
|
||||
['left', [-0.5, 0]],
|
||||
['bottom', [0, 0.5]]],
|
||||
opacityDefault = (context.storage('background-opacity') !== null) ?
|
||||
(+context.storage('background-opacity')) : 1.0,
|
||||
customSource = context.background().findSource('custom'),
|
||||
previous;
|
||||
var key = t('background.key');
|
||||
|
||||
// Can be 0 from <1.3.0 use or due to issue #1923.
|
||||
if (opacityDefault === 0) opacityDefault = 1.0;
|
||||
var _customSource = context.background().findSource('custom');
|
||||
var _previousBackground;
|
||||
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 background(selection) {
|
||||
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.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 setOpacity(d) {
|
||||
var bg = context.container().selectAll('.layer-background')
|
||||
.transition()
|
||||
.style('opacity', d)
|
||||
.attr('data-opacity', d);
|
||||
function renderBackgroundList(selection) {
|
||||
|
||||
if (!detected.opera) {
|
||||
utilSetTransform(bg, 0, 0);
|
||||
}
|
||||
// the background list
|
||||
var container = selection.selectAll('.layer-background-list')
|
||||
.data([0]);
|
||||
|
||||
opacityList.selectAll('li')
|
||||
.classed('active', function(_) { return _ === d; });
|
||||
|
||||
context.storage('background-opacity', d);
|
||||
}
|
||||
_backgroundList = container.enter()
|
||||
.append('ul')
|
||||
.attr('class', 'layer-list layer-background-list')
|
||||
.attr('dir', 'auto')
|
||||
.merge(container);
|
||||
|
||||
|
||||
function setTooltips(selection) {
|
||||
selection.each(function(d, i, nodes) {
|
||||
var item = d3_select(this).select('label'),
|
||||
span = item.select('span'),
|
||||
placement = (i < nodes.length / 2) ? 'bottom' : 'top',
|
||||
description = d.description(),
|
||||
isOverflowing = (span.property('clientWidth') !== span.property('scrollWidth'));
|
||||
// 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');
|
||||
|
||||
if (d === previous) {
|
||||
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 selectLayer() {
|
||||
function active(d) {
|
||||
return context.background().showsLayer(d);
|
||||
}
|
||||
|
||||
content.selectAll('.layer')
|
||||
.classed('active', active)
|
||||
.classed('switch', function(d) { return d === previous; })
|
||||
.call(setTooltips)
|
||||
.selectAll('input')
|
||||
.property('checked', active);
|
||||
}
|
||||
|
||||
|
||||
function clickSetSource(d) {
|
||||
if (d.id === 'custom' && !d.template()) {
|
||||
return editCustom();
|
||||
}
|
||||
|
||||
d3_event.preventDefault();
|
||||
previous = context.background().baseLayerSource();
|
||||
context.background().baseLayerSource(d);
|
||||
selectLayer();
|
||||
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
|
||||
var minimapLabelEnter = minimapEnter
|
||||
.append('label')
|
||||
.call(tooltip()
|
||||
.html(true)
|
||||
.title(uiTooltipHtml(t('background.minimap.tooltip'), t('background.minimap.key')))
|
||||
.placement('top')
|
||||
);
|
||||
|
||||
if (template) {
|
||||
context.storage('background-custom-template', template);
|
||||
customSource.template(template);
|
||||
clickSetSource(customSource);
|
||||
} else {
|
||||
selectLayer();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function clickSetOverlay(d) {
|
||||
d3_event.preventDefault();
|
||||
context.background().toggleOverlayLayer(d);
|
||||
selectLayer();
|
||||
document.activeElement.blur();
|
||||
}
|
||||
|
||||
|
||||
function drawList(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');
|
||||
}
|
||||
|
||||
|
||||
function update() {
|
||||
backgroundList.call(drawList, 'radio', clickSetSource, function(d) { return !d.isHidden() && !d.overlay; });
|
||||
overlayList.call(drawList, 'checkbox', clickSetOverlay, function(d) { return !d.isHidden() && d.overlay; });
|
||||
|
||||
selectLayer();
|
||||
updateOffsetVal();
|
||||
}
|
||||
|
||||
|
||||
function updateOffsetVal() {
|
||||
var meters = geoOffsetToMeters(context.background().offset()),
|
||||
x = +meters[0].toFixed(2),
|
||||
y = +meters[1].toFixed(2);
|
||||
|
||||
d3_selectAll('.nudge-inner-rect')
|
||||
.select('input')
|
||||
.classed('error', false)
|
||||
.property('value', x + ', ' + y);
|
||||
|
||||
d3_selectAll('.nudge-reset')
|
||||
.classed('disabled', function() {
|
||||
return (x === 0 && y === 0);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function resetOffset() {
|
||||
if (d3_event.button !== 0) return;
|
||||
context.background().offset([0, 0]);
|
||||
updateOffsetVal();
|
||||
}
|
||||
|
||||
|
||||
function nudge(d) {
|
||||
context.background().nudge(d, context.map().zoom());
|
||||
updateOffsetVal();
|
||||
}
|
||||
|
||||
|
||||
function buttonOffset(d) {
|
||||
if (d3_event.button !== 0) return;
|
||||
var timeout = window.setTimeout(function() {
|
||||
interval = window.setInterval(nudge.bind(null, d), 100);
|
||||
}, 500),
|
||||
interval;
|
||||
|
||||
function doneNudge() {
|
||||
window.clearTimeout(timeout);
|
||||
window.clearInterval(interval);
|
||||
d3_select(window)
|
||||
.on('mouseup.buttonoffset', null, true)
|
||||
.on('mousedown.buttonoffset', null, true);
|
||||
}
|
||||
|
||||
d3_select(window)
|
||||
.on('mouseup.buttonoffset', doneNudge, true)
|
||||
.on('mousedown.buttonoffset', doneNudge, true);
|
||||
|
||||
nudge(d);
|
||||
}
|
||||
|
||||
|
||||
function inputOffset() {
|
||||
if (d3_event.button !== 0) return;
|
||||
var input = d3_select(this);
|
||||
var d = input.node().value;
|
||||
|
||||
if (d === '') return resetOffset();
|
||||
|
||||
d = d.replace(/;/g, ',').split(',').map(function(n) {
|
||||
// if n is NaN, it will always get mapped to false.
|
||||
return !isNaN(n) && n;
|
||||
minimapLabelEnter
|
||||
.append('input')
|
||||
.attr('type', 'checkbox')
|
||||
.on('change', function() {
|
||||
d3_event.preventDefault();
|
||||
uiMapInMap.toggle();
|
||||
});
|
||||
|
||||
if (d.length !== 2 || !d[0] || !d[1]) {
|
||||
input.classed('error', true);
|
||||
return;
|
||||
}
|
||||
|
||||
context.background().offset(geoMetersToOffset(d));
|
||||
updateOffsetVal();
|
||||
}
|
||||
minimapLabelEnter
|
||||
.append('span')
|
||||
.text(t('background.minimap.description'));
|
||||
|
||||
|
||||
function dragOffset() {
|
||||
if (d3_event.button !== 0) return;
|
||||
var origin = [d3_event.clientX, d3_event.clientY];
|
||||
|
||||
context.container()
|
||||
.append('div')
|
||||
.attr('class', 'nudge-surface');
|
||||
|
||||
d3_select(window)
|
||||
.on('mousemove.offset', function() {
|
||||
var latest = [d3_event.clientX, d3_event.clientY];
|
||||
var d = [
|
||||
-(origin[0] - latest[0]) / 4,
|
||||
-(origin[1] - latest[1]) / 4
|
||||
];
|
||||
|
||||
origin = latest;
|
||||
nudge(d);
|
||||
})
|
||||
.on('mouseup.offset', function() {
|
||||
if (d3_event.button !== 0) return;
|
||||
d3_selectAll('.nudge-surface')
|
||||
.remove();
|
||||
|
||||
d3_select(window)
|
||||
.on('mousemove.offset', null)
|
||||
.on('mouseup.offset', null);
|
||||
});
|
||||
|
||||
d3_event.preventDefault();
|
||||
}
|
||||
|
||||
|
||||
function hide() {
|
||||
setVisible(false);
|
||||
}
|
||||
|
||||
|
||||
function toggle() {
|
||||
if (d3_event) {
|
||||
d3_event.preventDefault();
|
||||
}
|
||||
tooltipBehavior.hide(button);
|
||||
setVisible(!button.classed('active'));
|
||||
}
|
||||
|
||||
|
||||
function quickSwitch() {
|
||||
if (d3_event) {
|
||||
d3_event.stopImmediatePropagation();
|
||||
d3_event.preventDefault();
|
||||
}
|
||||
if (previous) {
|
||||
clickSetSource(previous);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function setVisible(show) {
|
||||
if (show !== shown) {
|
||||
button.classed('active', show);
|
||||
shown = show;
|
||||
|
||||
if (show) {
|
||||
selection
|
||||
.on('mousedown.background-inside', function() {
|
||||
d3_event.stopPropagation();
|
||||
});
|
||||
|
||||
content
|
||||
.style('display', 'block')
|
||||
.style('right', '-300px')
|
||||
.transition()
|
||||
.duration(200)
|
||||
.style('right', '0px');
|
||||
|
||||
content.selectAll('.layer')
|
||||
.call(setTooltips);
|
||||
|
||||
} else {
|
||||
content
|
||||
.style('display', 'block')
|
||||
.style('right', '0px')
|
||||
.transition()
|
||||
.duration(200)
|
||||
.style('right', '-300px')
|
||||
.on('end', function() {
|
||||
d3_select(this).style('display', 'none');
|
||||
});
|
||||
|
||||
selection
|
||||
.on('mousedown.background-inside', null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var content = selection
|
||||
.append('div')
|
||||
.attr('class', 'fillL map-overlay col3 content hide'),
|
||||
tooltipBehavior = tooltip()
|
||||
.placement((textDirection === 'rtl') ? 'right' : 'left')
|
||||
.html(true)
|
||||
.title(uiTooltipHtml(t('background.description'), key)),
|
||||
button = selection
|
||||
.append('button')
|
||||
.attr('tabindex', -1)
|
||||
.on('click', toggle)
|
||||
.call(svgIcon('#icon-layers', 'light'))
|
||||
.call(tooltipBehavior),
|
||||
shown = false;
|
||||
|
||||
|
||||
/* opacity switcher */
|
||||
|
||||
var opawrap = content
|
||||
.append('div')
|
||||
.attr('class', 'opacity-options-wrapper');
|
||||
|
||||
opawrap
|
||||
.append('h4')
|
||||
.text(t('background.title'));
|
||||
|
||||
var opacityList = opawrap
|
||||
.append('ul')
|
||||
.attr('class', 'opacity-options');
|
||||
|
||||
opacityList.selectAll('div.opacity')
|
||||
.data(opacities)
|
||||
// "Info / Report a Problem" link
|
||||
selection.selectAll('.imagery-faq')
|
||||
.data([0])
|
||||
.enter()
|
||||
.append('li')
|
||||
.attr('data-original-title', function(d) {
|
||||
return t('background.percent_brightness', { opacity: (d * 100) });
|
||||
})
|
||||
.on('click.set-opacity', setOpacity)
|
||||
.html('<div class="select-box"></div>')
|
||||
.call(tooltip()
|
||||
.placement((textDirection === 'rtl') ? 'right' : 'left'))
|
||||
.append('div')
|
||||
.attr('class', 'opacity')
|
||||
.style('opacity', function(d) { return 1.25 - d; });
|
||||
|
||||
|
||||
/* background list */
|
||||
|
||||
var backgroundList = content
|
||||
.append('ul')
|
||||
.attr('class', 'layer-list')
|
||||
.attr('dir', 'auto');
|
||||
|
||||
content
|
||||
.append('div')
|
||||
.attr('class', 'imagery-faq')
|
||||
.append('a')
|
||||
@@ -449,108 +247,141 @@ export function uiBackground(context) {
|
||||
.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'));
|
||||
}
|
||||
|
||||
|
||||
/* overlay list */
|
||||
function renderOverlayList(selection) {
|
||||
var container = selection.selectAll('.layer-overlay-list')
|
||||
.data([0]);
|
||||
|
||||
var overlayList = content
|
||||
_overlayList = container.enter()
|
||||
.append('ul')
|
||||
.attr('class', 'layer-list');
|
||||
.attr('class', 'layer-list layer-overlay-list')
|
||||
.attr('dir', 'auto')
|
||||
.merge(container);
|
||||
}
|
||||
|
||||
var controls = content
|
||||
|
||||
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', 'controls-list');
|
||||
.attr('class', 'fillL map-overlay col3 content hide');
|
||||
|
||||
var paneTooltip = tooltip()
|
||||
.placement((textDirection === 'rtl') ? 'right' : 'left')
|
||||
.html(true)
|
||||
.title(uiTooltipHtml(t('background.description'), key));
|
||||
|
||||
/* minimap toggle */
|
||||
var button = selection
|
||||
.append('button')
|
||||
.attr('tabindex', -1)
|
||||
.on('click', togglePane)
|
||||
.call(svgIcon('#icon-layers', 'light'))
|
||||
.call(paneTooltip);
|
||||
|
||||
var minimapLabel = controls
|
||||
.append('label')
|
||||
.call(tooltip()
|
||||
.html(true)
|
||||
.title(uiTooltipHtml(t('background.minimap.tooltip'), t('background.minimap.key')))
|
||||
.placement('top')
|
||||
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)
|
||||
);
|
||||
|
||||
minimapLabel
|
||||
.classed('minimap-toggle', true)
|
||||
.append('input')
|
||||
.attr('type', 'checkbox')
|
||||
.on('change', function() {
|
||||
uiMapInMap.toggle();
|
||||
d3_event.preventDefault();
|
||||
});
|
||||
|
||||
minimapLabel
|
||||
.append('span')
|
||||
.text(t('background.minimap.description'));
|
||||
|
||||
|
||||
/* imagery offset controls */
|
||||
|
||||
var adjustments = content
|
||||
// overlay list
|
||||
pane
|
||||
.append('div')
|
||||
.attr('class', 'adjustments');
|
||||
|
||||
adjustments
|
||||
.append('a')
|
||||
.text(t('background.fix_misalignment'))
|
||||
.attr('href', '#')
|
||||
.classed('hide-toggle', true)
|
||||
.classed('expanded', false)
|
||||
.on('click', function() {
|
||||
if (d3_event.button !== 0) return;
|
||||
var exp = d3_select(this).classed('expanded');
|
||||
nudgeContainer.style('display', exp ? 'none' : 'block');
|
||||
d3_select(this).classed('expanded', !exp);
|
||||
d3_event.preventDefault();
|
||||
});
|
||||
|
||||
var nudgeContainer = adjustments
|
||||
.append('div')
|
||||
.attr('class', 'nudge-container cf')
|
||||
.style('display', 'none');
|
||||
|
||||
nudgeContainer
|
||||
.append('div')
|
||||
.attr('class', 'nudge-instructions')
|
||||
.text(t('background.offset'));
|
||||
|
||||
var nudgeRect = nudgeContainer
|
||||
.append('div')
|
||||
.attr('class', 'nudge-outer-rect')
|
||||
.on('mousedown', dragOffset);
|
||||
|
||||
nudgeRect
|
||||
.append('div')
|
||||
.attr('class', 'nudge-inner-rect')
|
||||
.append('input')
|
||||
.on('change', inputOffset)
|
||||
.on('mousedown', function() {
|
||||
if (d3_event.button !== 0) return;
|
||||
d3_event.stopPropagation();
|
||||
});
|
||||
|
||||
nudgeContainer
|
||||
.append('div')
|
||||
.selectAll('button')
|
||||
.data(directions).enter()
|
||||
.append('button')
|
||||
.attr('class', function(d) { return d[0] + ' nudge'; })
|
||||
.on('mousedown', function(d) {
|
||||
if (d3_event.button !== 0) return;
|
||||
buttonOffset(d[1]);
|
||||
});
|
||||
|
||||
nudgeContainer
|
||||
.append('button')
|
||||
.attr('title', t('background.reset'))
|
||||
.attr('class', 'nudge-reset disabled')
|
||||
.on('click', resetOffset)
|
||||
.call(
|
||||
(textDirection === 'rtl') ? svgIcon('#icon-redo') : svgIcon('#icon-undo')
|
||||
.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));
|
||||
|
||||
@@ -559,15 +390,18 @@ export function uiBackground(context) {
|
||||
|
||||
|
||||
update();
|
||||
setOpacity(opacityDefault);
|
||||
|
||||
var keybinding = d3_keybinding('background')
|
||||
.on(key, toggle)
|
||||
.on(key, togglePane)
|
||||
.on(uiCmd('⌘' + key), quickSwitch)
|
||||
.on([t('map_data.key'), t('help.key')], hide);
|
||||
.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;
|
||||
|
||||
125
modules/ui/background_display_options.js
Normal file
125
modules/ui/background_display_options.js
Normal file
@@ -0,0 +1,125 @@
|
||||
import {
|
||||
event as d3_event,
|
||||
select as d3_select
|
||||
} from 'd3-selection';
|
||||
|
||||
|
||||
import { t, textDirection } from '../util/locale';
|
||||
import { svgIcon } from '../svg';
|
||||
import { uiDisclosure } from './disclosure';
|
||||
|
||||
|
||||
export function uiBackgroundDisplayOptions(context) {
|
||||
var _selection = d3_select(null);
|
||||
var sliders = ['brightness', 'contrast', 'saturation', 'sharpness'];
|
||||
var storedOpacity = context.storage('background-opacity');
|
||||
|
||||
var _options = {
|
||||
brightness: (storedOpacity !== null ? (+storedOpacity) : 1),
|
||||
contrast: 1,
|
||||
saturation: 1,
|
||||
sharpness: 1
|
||||
};
|
||||
|
||||
|
||||
function clamp(x, min, max) {
|
||||
return Math.max(min, Math.min(x, max));
|
||||
}
|
||||
|
||||
|
||||
function updateValue(d, val) {
|
||||
if (!val && d3_event && d3_event.target) {
|
||||
val = d3_event.target.value;
|
||||
}
|
||||
|
||||
val = clamp(val, 0.25, 2);
|
||||
|
||||
_options[d] = val;
|
||||
context.background()[d](val);
|
||||
|
||||
if (d === 'brightness') {
|
||||
context.storage('background-opacity', val);
|
||||
}
|
||||
|
||||
_selection
|
||||
.call(render);
|
||||
}
|
||||
|
||||
|
||||
function render(selection) {
|
||||
var container = selection.selectAll('.display-options-container')
|
||||
.data([0]);
|
||||
|
||||
var containerEnter = container.enter()
|
||||
.append('div')
|
||||
.attr('class', 'display-options-container controls-list');
|
||||
|
||||
// add slider controls
|
||||
var slidersEnter = containerEnter.selectAll('.display-control')
|
||||
.data(sliders)
|
||||
.enter()
|
||||
.append('div')
|
||||
.attr('class', function(d) { return 'display-control display-control-' + d; });
|
||||
|
||||
slidersEnter
|
||||
.append('h5')
|
||||
.text(function(d) { return t('background.' + d); })
|
||||
.append('span')
|
||||
.attr('class', function(d) { return 'display-option-value display-option-value-' + d; });
|
||||
|
||||
slidersEnter
|
||||
.append('input')
|
||||
.attr('class', function(d) { return 'display-option-input display-option-input-' + d; })
|
||||
.attr('type', 'range')
|
||||
.attr('min', '0.25')
|
||||
.attr('max', '2')
|
||||
.attr('step', '0.05')
|
||||
.on('input', function(d) {
|
||||
var val = d3_select(this).property('value');
|
||||
updateValue(d, val);
|
||||
});
|
||||
|
||||
slidersEnter
|
||||
.append('button')
|
||||
.attr('title', t('background.reset'))
|
||||
.attr('class', function(d) { return 'display-option-reset display-option-reset-' + d; })
|
||||
.on('click', function(d) {
|
||||
if (d3_event.button !== 0) return;
|
||||
updateValue(d, 1);
|
||||
})
|
||||
.call(svgIcon('#icon-' + (textDirection === 'rtl' ? 'redo' : 'undo')));
|
||||
|
||||
|
||||
// update
|
||||
container = containerEnter
|
||||
.merge(container);
|
||||
|
||||
container.selectAll('.display-option-input')
|
||||
.property('value', function(d) { return _options[d]; });
|
||||
|
||||
container.selectAll('.display-option-value')
|
||||
.text(function(d) { return Math.floor(_options[d] * 100) + '%'; });
|
||||
|
||||
container.selectAll('.display-option-reset')
|
||||
.classed('disabled', function(d) { return _options[d] === 1; });
|
||||
|
||||
// first time only, set brightness if needed
|
||||
if (containerEnter.size() && _options.brightness !== 1) {
|
||||
context.background().brightness(_options.brightness);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function backgroundDisplayOptions(selection) {
|
||||
_selection = selection;
|
||||
|
||||
selection
|
||||
.call(uiDisclosure(context, 'background_display_options', true)
|
||||
.title(t('background.display_options'))
|
||||
.content(render)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
return backgroundDisplayOptions;
|
||||
}
|
||||
197
modules/ui/background_offset.js
Normal file
197
modules/ui/background_offset.js
Normal file
@@ -0,0 +1,197 @@
|
||||
import {
|
||||
event as d3_event,
|
||||
select as d3_select,
|
||||
selectAll as d3_selectAll
|
||||
} from 'd3-selection';
|
||||
|
||||
import { t, textDirection } from '../util/locale';
|
||||
import { geoMetersToOffset, geoOffsetToMeters } from '../geo';
|
||||
import { svgIcon } from '../svg';
|
||||
import { uiDisclosure } from './disclosure';
|
||||
|
||||
|
||||
export function uiBackgroundOffset(context) {
|
||||
var directions = [
|
||||
['right', [0.5, 0]],
|
||||
['top', [0, -0.5]],
|
||||
['left', [-0.5, 0]],
|
||||
['bottom', [0, 0.5]]
|
||||
];
|
||||
|
||||
|
||||
function d3_eventCancel() {
|
||||
d3_event.stopPropagation();
|
||||
d3_event.preventDefault();
|
||||
}
|
||||
|
||||
|
||||
function updateValue() {
|
||||
var meters = geoOffsetToMeters(context.background().offset());
|
||||
var x = +meters[0].toFixed(2);
|
||||
var y = +meters[1].toFixed(2);
|
||||
|
||||
d3_selectAll('.nudge-inner-rect')
|
||||
.select('input')
|
||||
.classed('error', false)
|
||||
.property('value', x + ', ' + y);
|
||||
|
||||
d3_selectAll('.nudge-reset')
|
||||
.classed('disabled', function() {
|
||||
return (x === 0 && y === 0);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function resetOffset() {
|
||||
context.background().offset([0, 0]);
|
||||
updateValue();
|
||||
}
|
||||
|
||||
|
||||
function nudge(d) {
|
||||
context.background().nudge(d, context.map().zoom());
|
||||
updateValue();
|
||||
}
|
||||
|
||||
|
||||
function clickNudgeButton(d) {
|
||||
var interval;
|
||||
var timeout = window.setTimeout(function() {
|
||||
interval = window.setInterval(nudge.bind(null, d), 100);
|
||||
}, 500);
|
||||
|
||||
function doneNudge() {
|
||||
window.clearTimeout(timeout);
|
||||
window.clearInterval(interval);
|
||||
d3_select(window)
|
||||
.on('mouseup.buttonoffset', null, true)
|
||||
.on('mousedown.buttonoffset', null, true);
|
||||
}
|
||||
|
||||
d3_select(window)
|
||||
.on('mouseup.buttonoffset', doneNudge, true)
|
||||
.on('mousedown.buttonoffset', doneNudge, true);
|
||||
|
||||
nudge(d);
|
||||
}
|
||||
|
||||
|
||||
function inputOffset() {
|
||||
var input = d3_select(this);
|
||||
var d = input.node().value;
|
||||
|
||||
if (d === '') return resetOffset();
|
||||
|
||||
d = d.replace(/;/g, ',').split(',').map(function(n) {
|
||||
// if n is NaN, it will always get mapped to false.
|
||||
return !isNaN(n) && n;
|
||||
});
|
||||
|
||||
if (d.length !== 2 || !d[0] || !d[1]) {
|
||||
input.classed('error', true);
|
||||
return;
|
||||
}
|
||||
|
||||
context.background().offset(geoMetersToOffset(d));
|
||||
updateValue();
|
||||
}
|
||||
|
||||
|
||||
function dragOffset() {
|
||||
d3_event.preventDefault();
|
||||
if (d3_event.button !== 0) return;
|
||||
|
||||
var origin = [d3_event.clientX, d3_event.clientY];
|
||||
|
||||
context.container()
|
||||
.append('div')
|
||||
.attr('class', 'nudge-surface');
|
||||
|
||||
d3_select(window)
|
||||
.on('mousemove.offset', function() {
|
||||
var latest = [d3_event.clientX, d3_event.clientY];
|
||||
var d = [
|
||||
-(origin[0] - latest[0]) / 4,
|
||||
-(origin[1] - latest[1]) / 4
|
||||
];
|
||||
|
||||
origin = latest;
|
||||
nudge(d);
|
||||
})
|
||||
.on('mouseup.offset', function() {
|
||||
if (d3_event.button !== 0) return;
|
||||
d3_selectAll('.nudge-surface')
|
||||
.remove();
|
||||
|
||||
d3_select(window)
|
||||
.on('mousemove.offset', null)
|
||||
.on('mouseup.offset', null);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function render(selection) {
|
||||
var container = selection.selectAll('.nudge-container')
|
||||
.data([0]);
|
||||
|
||||
var containerEnter = container.enter()
|
||||
.append('div')
|
||||
.attr('class', 'nudge-container cf');
|
||||
|
||||
containerEnter
|
||||
.append('div')
|
||||
.attr('class', 'nudge-instructions')
|
||||
.text(t('background.offset'));
|
||||
|
||||
var nudgeEnter = containerEnter
|
||||
.append('div')
|
||||
.attr('class', 'nudge-outer-rect')
|
||||
.on('mousedown', dragOffset);
|
||||
|
||||
nudgeEnter
|
||||
.append('div')
|
||||
.attr('class', 'nudge-inner-rect')
|
||||
.append('input')
|
||||
.on('change', inputOffset);
|
||||
|
||||
containerEnter
|
||||
.append('div')
|
||||
.selectAll('button')
|
||||
.data(directions).enter()
|
||||
.append('button')
|
||||
.attr('class', function(d) { return d[0] + ' nudge'; })
|
||||
.on('contextmenu', d3_eventCancel)
|
||||
.on('mousedown', function(d) {
|
||||
if (d3_event.button !== 0) return;
|
||||
clickNudgeButton(d[1]);
|
||||
});
|
||||
|
||||
containerEnter
|
||||
.append('button')
|
||||
.attr('title', t('background.reset'))
|
||||
.attr('class', 'nudge-reset disabled')
|
||||
.on('contextmenu', d3_eventCancel)
|
||||
.on('click', function() {
|
||||
if (d3_event.button !== 0) return;
|
||||
resetOffset();
|
||||
})
|
||||
.call(svgIcon('#icon-' + (textDirection === 'rtl' ? 'redo' : 'undo')));
|
||||
|
||||
updateValue();
|
||||
}
|
||||
|
||||
|
||||
function backgroundOffset(selection) {
|
||||
selection
|
||||
.call(uiDisclosure(context, 'background_offset', false)
|
||||
.title(t('background.fix_misalignment'))
|
||||
.content(render)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
context.background()
|
||||
.on('change.backgroundOffset-update', updateValue);
|
||||
|
||||
return backgroundOffset;
|
||||
}
|
||||
@@ -269,7 +269,6 @@ export function uiCommit(context) {
|
||||
updateChangeset({ review_requested: (rr ? 'yes' : undefined) });
|
||||
|
||||
var expanded = !tagSection.selectAll('a.hide-toggle.expanded').empty();
|
||||
|
||||
tagSection
|
||||
.call(rawTagEditor
|
||||
.expanded(expanded)
|
||||
|
||||
@@ -1,70 +1,115 @@
|
||||
import { dispatch as d3_dispatch } from 'd3-dispatch';
|
||||
import { event as d3_event } from 'd3-selection';
|
||||
|
||||
import { svgIcon } from '../svg';
|
||||
import { utilRebind } from '../util/rebind';
|
||||
import { uiToggle } from './toggle';
|
||||
import { textDirection } from '../util/locale';
|
||||
|
||||
|
||||
export function uiDisclosure() {
|
||||
export function uiDisclosure(context, key, expandedDefault) {
|
||||
var dispatch = d3_dispatch('toggled'),
|
||||
title,
|
||||
expanded = false,
|
||||
content = function () {};
|
||||
_preference = (context.storage('disclosure.' + key + '.expanded')),
|
||||
_expanded = (_preference === null ? !!expandedDefault : (_preference === 'true')),
|
||||
_title,
|
||||
_updatePreference = true,
|
||||
_content = function () {};
|
||||
|
||||
|
||||
var disclosure = function(selection) {
|
||||
var hideToggle = selection.selectAll('.hide-toggle')
|
||||
var hideToggle = selection.selectAll('.hide-toggle-' + key)
|
||||
.data([0]);
|
||||
|
||||
hideToggle = hideToggle.enter()
|
||||
// enter
|
||||
var hideToggleEnter = hideToggle.enter()
|
||||
.append('a')
|
||||
.attr('href', '#')
|
||||
.attr('class', 'hide-toggle')
|
||||
.attr('class', 'hide-toggle hide-toggle-' + key)
|
||||
.call(svgIcon('', 'pre-text', 'hide-toggle-icon'));
|
||||
|
||||
hideToggleEnter
|
||||
.append('span')
|
||||
.attr('class', 'hide-toggle-text');
|
||||
|
||||
// update
|
||||
hideToggle = hideToggleEnter
|
||||
.merge(hideToggle);
|
||||
|
||||
hideToggle
|
||||
.text(title)
|
||||
.on('click', toggle)
|
||||
.classed('expanded', expanded);
|
||||
.classed('expanded', _expanded);
|
||||
|
||||
hideToggle.selectAll('.hide-toggle-text')
|
||||
.text(_title);
|
||||
|
||||
hideToggle.selectAll('.hide-toggle-icon')
|
||||
.attr('xlink:href', _expanded ? '#icon-down'
|
||||
: (textDirection === 'rtl') ? '#icon-backward' : '#icon-forward'
|
||||
);
|
||||
|
||||
|
||||
var wrap = selection.selectAll('div')
|
||||
var wrap = selection.selectAll('.disclosure-wrap')
|
||||
.data([0]);
|
||||
|
||||
wrap = wrap.enter()
|
||||
.append('div')
|
||||
.attr('class', 'disclosure-wrap disclosure-wrap-' + key)
|
||||
.merge(wrap);
|
||||
|
||||
wrap
|
||||
.classed('hide', !expanded)
|
||||
.call(content);
|
||||
.classed('hide', !_expanded)
|
||||
.call(_content);
|
||||
|
||||
|
||||
function toggle() {
|
||||
expanded = !expanded;
|
||||
hideToggle.classed('expanded', expanded);
|
||||
wrap.call(uiToggle(expanded));
|
||||
dispatch.call('toggled', this, expanded);
|
||||
d3_event.preventDefault();
|
||||
|
||||
_expanded = !_expanded;
|
||||
|
||||
if (_updatePreference) {
|
||||
context.storage('disclosure.' + key + '.expanded', _expanded);
|
||||
}
|
||||
|
||||
hideToggle
|
||||
.classed('expanded', _expanded);
|
||||
|
||||
hideToggle.selectAll('.hide-toggle-icon')
|
||||
.attr('xlink:href', _expanded ? '#icon-down'
|
||||
: (textDirection === 'rtl') ? '#icon-backward' : '#icon-forward'
|
||||
);
|
||||
|
||||
wrap
|
||||
.call(uiToggle(_expanded));
|
||||
|
||||
dispatch.call('toggled', this, _expanded);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
disclosure.title = function(_) {
|
||||
if (!arguments.length) return title;
|
||||
title = _;
|
||||
if (!arguments.length) return _title;
|
||||
_title = _;
|
||||
return disclosure;
|
||||
};
|
||||
|
||||
|
||||
disclosure.expanded = function(_) {
|
||||
if (!arguments.length) return expanded;
|
||||
expanded = _;
|
||||
if (!arguments.length) return _expanded;
|
||||
_expanded = _;
|
||||
return disclosure;
|
||||
};
|
||||
|
||||
|
||||
disclosure.updatePreference = function(_) {
|
||||
if (!arguments.length) return _updatePreference;
|
||||
_updatePreference = _;
|
||||
return disclosure;
|
||||
};
|
||||
|
||||
|
||||
disclosure.content = function(_) {
|
||||
if (!arguments.length) return content;
|
||||
content = _;
|
||||
if (!arguments.length) return _content;
|
||||
_content = _;
|
||||
return disclosure;
|
||||
};
|
||||
|
||||
|
||||
@@ -9,7 +9,9 @@ import marked from 'marked';
|
||||
import { t, textDirection } from '../util/locale';
|
||||
import { svgIcon } from '../svg';
|
||||
import { uiCmd } from './cmd';
|
||||
import { uiBackground } from './background';
|
||||
import { uiIntro } from './intro';
|
||||
import { uiMapData } from './map_data';
|
||||
import { uiShortcuts } from './shortcuts';
|
||||
import { uiTooltipHtml } from './tooltipHtml';
|
||||
import { tooltip } from '../util/tooltip';
|
||||
@@ -260,12 +262,12 @@ export function uiHelp(context) {
|
||||
|
||||
function help(selection) {
|
||||
|
||||
function hide() {
|
||||
function hidePane() {
|
||||
setVisible(false);
|
||||
}
|
||||
|
||||
|
||||
function toggle() {
|
||||
function togglePane() {
|
||||
if (d3_event) d3_event.preventDefault();
|
||||
tooltipBehavior.hide(button);
|
||||
setVisible(!button.classed('active'));
|
||||
@@ -278,14 +280,15 @@ export function uiHelp(context) {
|
||||
shown = show;
|
||||
|
||||
if (show) {
|
||||
selection.on('mousedown.help-inside', function() {
|
||||
return d3_event.stopPropagation();
|
||||
});
|
||||
uiBackground.hidePane();
|
||||
uiMapData.hidePane();
|
||||
|
||||
pane.style('display', 'block')
|
||||
.style('right', '-500px')
|
||||
.transition()
|
||||
.duration(200)
|
||||
.style('right', '0px');
|
||||
|
||||
} else {
|
||||
pane.style('right', '0px')
|
||||
.transition()
|
||||
@@ -294,7 +297,6 @@ export function uiHelp(context) {
|
||||
.on('end', function() {
|
||||
d3_select(this).style('display', 'none');
|
||||
});
|
||||
selection.on('mousedown.help-inside', null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -375,13 +377,14 @@ export function uiHelp(context) {
|
||||
.title(uiTooltipHtml(t('help.title'), key)),
|
||||
button = selection.append('button')
|
||||
.attr('tabindex', -1)
|
||||
.on('click', toggle)
|
||||
.on('click', togglePane)
|
||||
.call(svgIcon('#icon-help', 'light'))
|
||||
.call(tooltipBehavior),
|
||||
shown = false;
|
||||
|
||||
|
||||
var toc = pane.append('ul')
|
||||
var toc = pane
|
||||
.append('ul')
|
||||
.attr('class', 'toc');
|
||||
|
||||
var menuItems = toc.selectAll('li')
|
||||
@@ -424,26 +427,34 @@ export function uiHelp(context) {
|
||||
.text(t('splash.walkthrough'));
|
||||
|
||||
|
||||
var content = pane.append('div')
|
||||
var content = pane
|
||||
.append('div')
|
||||
.attr('class', 'left-content');
|
||||
|
||||
var doctitle = content.append('h2')
|
||||
var doctitle = content
|
||||
.append('h2')
|
||||
.text(t('help.title'));
|
||||
|
||||
var body = content.append('div')
|
||||
var body = content
|
||||
.append('div')
|
||||
.attr('class', 'body');
|
||||
|
||||
var nav = content.append('div')
|
||||
var nav = content
|
||||
.append('div')
|
||||
.attr('class', 'nav');
|
||||
|
||||
clickHelp(docs[0], 0);
|
||||
|
||||
var keybinding = d3_keybinding('help')
|
||||
.on(key, toggle)
|
||||
.on([t('background.key'), t('map_data.key')], hide);
|
||||
.on(key, togglePane)
|
||||
.on([t('background.key'), t('map_data.key')], hidePane);
|
||||
|
||||
d3_select(document)
|
||||
.call(keybinding);
|
||||
|
||||
uiHelp.hidePane = hidePane;
|
||||
uiHelp.togglePane = togglePane;
|
||||
uiHelp.setVisible = setVisible;
|
||||
}
|
||||
|
||||
return help;
|
||||
|
||||
@@ -2,6 +2,8 @@ export { uiInit } from './init';
|
||||
export { uiAccount } from './account';
|
||||
export { uiAttribution } from './attribution';
|
||||
export { uiBackground } from './background';
|
||||
export { uiBackgroundDisplayOptions } from './background_display_options';
|
||||
export { uiBackgroundOffset } from './background_offset';
|
||||
export { uiChangesetEditor } from './changeset_editor';
|
||||
export { uiCmd } from './cmd';
|
||||
export { uiCommit } from './commit';
|
||||
|
||||
@@ -5,380 +5,423 @@ import {
|
||||
|
||||
import { d3keybinding as d3_keybinding } from '../lib/d3.keybinding.js';
|
||||
|
||||
import { t, textDirection } from '../util/locale';
|
||||
import { svgIcon } from '../svg';
|
||||
import { uiTooltipHtml } from './tooltipHtml';
|
||||
import { t, textDirection } from '../util/locale';
|
||||
import { tooltip } from '../util/tooltip';
|
||||
import { uiBackground } from './background';
|
||||
import { uiDisclosure } from './disclosure';
|
||||
import { uiHelp } from './help';
|
||||
import { uiTooltipHtml } from './tooltipHtml';
|
||||
|
||||
|
||||
export function uiMapData(context) {
|
||||
var key = t('map_data.key'),
|
||||
features = context.features().keys(),
|
||||
layers = context.layers(),
|
||||
fills = ['wireframe', 'partial', 'full'],
|
||||
fillDefault = context.storage('area-fill') || 'partial',
|
||||
fillSelected = fillDefault;
|
||||
var key = t('map_data.key');
|
||||
var features = context.features().keys();
|
||||
var layers = context.layers();
|
||||
var fills = ['wireframe', 'partial', 'full'];
|
||||
|
||||
var _fillDefault = context.storage('area-fill') || 'partial';
|
||||
var _fillSelected = _fillDefault;
|
||||
var _shown = false;
|
||||
var _dataLayerContainer = d3_select(null);
|
||||
var _fillList = d3_select(null);
|
||||
var _featureList = d3_select(null);
|
||||
|
||||
|
||||
function map_data(selection) {
|
||||
function showsFeature(d) {
|
||||
return context.features().enabled(d);
|
||||
}
|
||||
|
||||
function showsFeature(d) {
|
||||
return context.features().enabled(d);
|
||||
|
||||
function autoHiddenFeature(d) {
|
||||
return context.features().autoHidden(d);
|
||||
}
|
||||
|
||||
|
||||
function clickFeature(d) {
|
||||
context.features().toggle(d);
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
function showsFill(d) {
|
||||
return _fillSelected === d;
|
||||
}
|
||||
|
||||
|
||||
function setFill(d) {
|
||||
fills.forEach(function(opt) {
|
||||
context.surface().classed('fill-' + opt, Boolean(opt === d));
|
||||
});
|
||||
|
||||
_fillSelected = d;
|
||||
if (d !== 'wireframe') {
|
||||
_fillDefault = d;
|
||||
context.storage('area-fill', d);
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
function autoHiddenFeature(d) {
|
||||
return context.features().autoHidden(d);
|
||||
function showsLayer(which) {
|
||||
var layer = layers.layer(which);
|
||||
if (layer) {
|
||||
return layer.enabled();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function clickFeature(d) {
|
||||
context.features().toggle(d);
|
||||
function setLayer(which, enabled) {
|
||||
var layer = layers.layer(which);
|
||||
if (layer) {
|
||||
layer.enabled(enabled);
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function showsFill(d) {
|
||||
return fillSelected === d;
|
||||
function toggleLayer(which) {
|
||||
setLayer(which, !showsLayer(which));
|
||||
}
|
||||
|
||||
|
||||
function drawPhotoItems(selection) {
|
||||
var photoKeys = ['mapillary-images', 'mapillary-signs', 'openstreetcam-images'];
|
||||
var photoLayers = layers.all().filter(function(obj) { return photoKeys.indexOf(obj.id) !== -1; });
|
||||
var data = photoLayers.filter(function(obj) { return obj.layer.supported(); });
|
||||
|
||||
function layerSupported(d) {
|
||||
return d.layer && d.layer.supported();
|
||||
}
|
||||
function layerEnabled(d) {
|
||||
return layerSupported(d) && d.layer.enabled();
|
||||
}
|
||||
|
||||
var ul = selection
|
||||
.selectAll('.layer-list-photos')
|
||||
.data([0]);
|
||||
|
||||
function setFill(d) {
|
||||
fills.forEach(function(opt) {
|
||||
context.surface().classed('fill-' + opt, Boolean(opt === d));
|
||||
ul = ul.enter()
|
||||
.append('ul')
|
||||
.attr('class', 'layer-list layer-list-photos')
|
||||
.merge(ul);
|
||||
|
||||
var li = ul.selectAll('.list-item-photos')
|
||||
.data(data);
|
||||
|
||||
li.exit()
|
||||
.remove();
|
||||
|
||||
var liEnter = li.enter()
|
||||
.append('li')
|
||||
.attr('class', function(d) { return 'list-item-photos list-item-' + d.id; });
|
||||
|
||||
var labelEnter = liEnter
|
||||
.append('label')
|
||||
.each(function(d) {
|
||||
d3_select(this)
|
||||
.call(tooltip()
|
||||
.title(t(d.id.replace('-', '_') + '.tooltip'))
|
||||
.placement('top')
|
||||
);
|
||||
});
|
||||
|
||||
fillSelected = d;
|
||||
if (d !== 'wireframe') {
|
||||
fillDefault = d;
|
||||
context.storage('area-fill', d);
|
||||
}
|
||||
update();
|
||||
}
|
||||
labelEnter
|
||||
.append('input')
|
||||
.attr('type', 'checkbox')
|
||||
.on('change', function(d) { toggleLayer(d.id); });
|
||||
|
||||
labelEnter
|
||||
.append('span')
|
||||
.text(function(d) { return t(d.id.replace('-', '_') + '.title'); });
|
||||
|
||||
|
||||
function showsLayer(which) {
|
||||
var layer = layers.layer(which);
|
||||
if (layer) {
|
||||
return layer.enabled();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Update
|
||||
li = li
|
||||
.merge(liEnter);
|
||||
|
||||
li
|
||||
.classed('active', layerEnabled)
|
||||
.selectAll('input')
|
||||
.property('checked', layerEnabled);
|
||||
}
|
||||
|
||||
|
||||
function setLayer(which, enabled) {
|
||||
var layer = layers.layer(which);
|
||||
if (layer) {
|
||||
layer.enabled(enabled);
|
||||
update();
|
||||
}
|
||||
}
|
||||
function drawOsmItem(selection) {
|
||||
var osm = layers.layer('osm'),
|
||||
showsOsm = osm.enabled();
|
||||
|
||||
var ul = selection
|
||||
.selectAll('.layer-list-osm')
|
||||
.data(osm ? [0] : []);
|
||||
|
||||
// Exit
|
||||
ul.exit()
|
||||
.remove();
|
||||
|
||||
// Enter
|
||||
var ulEnter = ul.enter()
|
||||
.append('ul')
|
||||
.attr('class', 'layer-list layer-list-osm');
|
||||
|
||||
var liEnter = ulEnter
|
||||
.append('li')
|
||||
.attr('class', 'list-item-osm');
|
||||
|
||||
var labelEnter = liEnter
|
||||
.append('label')
|
||||
.call(tooltip()
|
||||
.title(t('map_data.layers.osm.tooltip'))
|
||||
.placement('top')
|
||||
);
|
||||
|
||||
labelEnter
|
||||
.append('input')
|
||||
.attr('type', 'checkbox')
|
||||
.on('change', function() { toggleLayer('osm'); });
|
||||
|
||||
labelEnter
|
||||
.append('span')
|
||||
.text(t('map_data.layers.osm.title'));
|
||||
|
||||
// Update
|
||||
ul = ul
|
||||
.merge(ulEnter);
|
||||
|
||||
ul.selectAll('.list-item-osm')
|
||||
.classed('active', showsOsm)
|
||||
.selectAll('input')
|
||||
.property('checked', showsOsm);
|
||||
}
|
||||
|
||||
|
||||
function toggleLayer(which) {
|
||||
setLayer(which, !showsLayer(which));
|
||||
}
|
||||
function drawGpxItem(selection) {
|
||||
var gpx = layers.layer('gpx'),
|
||||
hasGpx = gpx && gpx.hasGpx(),
|
||||
showsGpx = hasGpx && gpx.enabled();
|
||||
|
||||
var ul = selection
|
||||
.selectAll('.layer-list-gpx')
|
||||
.data(gpx ? [0] : []);
|
||||
|
||||
function drawPhotoItems(selection) {
|
||||
var photoKeys = ['mapillary-images', 'mapillary-signs', 'openstreetcam-images'];
|
||||
var photoLayers = layers.all().filter(function(obj) { return photoKeys.indexOf(obj.id) !== -1; });
|
||||
var data = photoLayers.filter(function(obj) { return obj.layer.supported(); });
|
||||
// Exit
|
||||
ul.exit()
|
||||
.remove();
|
||||
|
||||
function layerSupported(d) {
|
||||
return d.layer && d.layer.supported();
|
||||
}
|
||||
function layerEnabled(d) {
|
||||
return layerSupported(d) && d.layer.enabled();
|
||||
}
|
||||
// Enter
|
||||
var ulEnter = ul.enter()
|
||||
.append('ul')
|
||||
.attr('class', 'layer-list layer-list-gpx');
|
||||
|
||||
var ul = selection
|
||||
.selectAll('.layer-list-photos')
|
||||
.data([0]);
|
||||
var liEnter = ulEnter
|
||||
.append('li')
|
||||
.attr('class', 'list-item-gpx');
|
||||
|
||||
ul = ul.enter()
|
||||
.append('ul')
|
||||
.attr('class', 'layer-list layer-list-photos')
|
||||
.merge(ul);
|
||||
liEnter
|
||||
.append('button')
|
||||
.attr('class', 'list-item-gpx-extent')
|
||||
.call(tooltip()
|
||||
.title(t('gpx.zoom'))
|
||||
.placement((textDirection === 'rtl') ? 'right' : 'left')
|
||||
)
|
||||
.on('click', function() {
|
||||
d3_event.preventDefault();
|
||||
d3_event.stopPropagation();
|
||||
gpx.fitZoom();
|
||||
})
|
||||
.call(svgIcon('#icon-search'));
|
||||
|
||||
var li = ul.selectAll('.list-item-photos')
|
||||
.data(data);
|
||||
|
||||
li.exit()
|
||||
.remove();
|
||||
|
||||
var liEnter = li.enter()
|
||||
.append('li')
|
||||
.attr('class', function(d) { return 'list-item-photos list-item-' + d.id; });
|
||||
|
||||
var labelEnter = liEnter
|
||||
.append('label')
|
||||
.each(function(d) {
|
||||
d3_select(this)
|
||||
.call(tooltip()
|
||||
.title(t(d.id.replace('-', '_') + '.tooltip'))
|
||||
.placement('top')
|
||||
);
|
||||
});
|
||||
|
||||
labelEnter
|
||||
.append('input')
|
||||
.attr('type', 'checkbox')
|
||||
.on('change', function(d) { toggleLayer(d.id); });
|
||||
|
||||
labelEnter
|
||||
.append('span')
|
||||
.text(function(d) { return t(d.id.replace('-', '_') + '.title'); });
|
||||
|
||||
|
||||
// Update
|
||||
li = li
|
||||
.merge(liEnter);
|
||||
|
||||
li
|
||||
.classed('active', layerEnabled)
|
||||
.selectAll('input')
|
||||
.property('checked', layerEnabled);
|
||||
}
|
||||
|
||||
|
||||
function drawOsmItem(selection) {
|
||||
var osm = layers.layer('osm'),
|
||||
showsOsm = osm.enabled();
|
||||
|
||||
var ul = selection
|
||||
.selectAll('.layer-list-osm')
|
||||
.data(osm ? [0] : []);
|
||||
|
||||
// Exit
|
||||
ul.exit()
|
||||
.remove();
|
||||
|
||||
// Enter
|
||||
var ulEnter = ul.enter()
|
||||
.append('ul')
|
||||
.attr('class', 'layer-list layer-list-osm');
|
||||
|
||||
var liEnter = ulEnter
|
||||
.append('li')
|
||||
.attr('class', 'list-item-osm');
|
||||
|
||||
var labelEnter = liEnter
|
||||
.append('label')
|
||||
.call(tooltip()
|
||||
.title(t('map_data.layers.osm.tooltip'))
|
||||
.placement('top')
|
||||
);
|
||||
|
||||
labelEnter
|
||||
.append('input')
|
||||
.attr('type', 'checkbox')
|
||||
.on('change', function() { toggleLayer('osm'); });
|
||||
|
||||
labelEnter
|
||||
.append('span')
|
||||
.text(t('map_data.layers.osm.title'));
|
||||
|
||||
// Update
|
||||
ul = ul
|
||||
.merge(ulEnter);
|
||||
|
||||
ul.selectAll('.list-item-osm')
|
||||
.classed('active', showsOsm)
|
||||
.selectAll('input')
|
||||
.property('checked', showsOsm);
|
||||
}
|
||||
|
||||
|
||||
function drawGpxItem(selection) {
|
||||
var gpx = layers.layer('gpx'),
|
||||
hasGpx = gpx && gpx.hasGpx(),
|
||||
showsGpx = hasGpx && gpx.enabled();
|
||||
|
||||
var ul = selection
|
||||
.selectAll('.layer-list-gpx')
|
||||
.data(gpx ? [0] : []);
|
||||
|
||||
// Exit
|
||||
ul.exit()
|
||||
.remove();
|
||||
|
||||
// Enter
|
||||
var ulEnter = ul.enter()
|
||||
.append('ul')
|
||||
.attr('class', 'layer-list layer-list-gpx');
|
||||
|
||||
var liEnter = ulEnter
|
||||
.append('li')
|
||||
.attr('class', 'list-item-gpx');
|
||||
|
||||
liEnter
|
||||
.append('button')
|
||||
.attr('class', 'list-item-gpx-extent')
|
||||
.call(tooltip()
|
||||
.title(t('gpx.zoom'))
|
||||
.placement((textDirection === 'rtl') ? 'right' : 'left'))
|
||||
.on('click', function() {
|
||||
d3_event.preventDefault();
|
||||
d3_event.stopPropagation();
|
||||
gpx.fitZoom();
|
||||
})
|
||||
.call(svgIcon('#icon-search'));
|
||||
|
||||
liEnter
|
||||
.append('button')
|
||||
.attr('class', 'list-item-gpx-browse')
|
||||
.call(tooltip()
|
||||
.title(t('gpx.browse'))
|
||||
.placement((textDirection === 'rtl') ? 'right' : 'left')
|
||||
)
|
||||
.on('click', function() {
|
||||
d3_select(document.createElement('input'))
|
||||
.attr('type', 'file')
|
||||
.on('change', function() {
|
||||
gpx.files(d3_event.target.files);
|
||||
})
|
||||
.node().click();
|
||||
})
|
||||
.call(svgIcon('#icon-geolocate'));
|
||||
|
||||
var labelEnter = liEnter
|
||||
.append('label')
|
||||
.call(tooltip()
|
||||
.title(t('gpx.drag_drop'))
|
||||
.placement('top')
|
||||
);
|
||||
|
||||
labelEnter
|
||||
.append('input')
|
||||
.attr('type', 'checkbox')
|
||||
.on('change', function() { toggleLayer('gpx'); });
|
||||
|
||||
labelEnter
|
||||
.append('span')
|
||||
.text(t('gpx.local_layer'));
|
||||
|
||||
// Update
|
||||
ul = ul
|
||||
.merge(ulEnter);
|
||||
|
||||
ul.selectAll('.list-item-gpx')
|
||||
.classed('active', showsGpx)
|
||||
.selectAll('label')
|
||||
.classed('deemphasize', !hasGpx)
|
||||
.selectAll('input')
|
||||
.property('disabled', !hasGpx)
|
||||
.property('checked', showsGpx);
|
||||
}
|
||||
|
||||
|
||||
function drawList(selection, data, type, name, change, active) {
|
||||
var items = selection.selectAll('li')
|
||||
.data(data);
|
||||
|
||||
// Exit
|
||||
items.exit()
|
||||
.remove();
|
||||
|
||||
// Enter
|
||||
var enter = items.enter()
|
||||
.append('li')
|
||||
.attr('class', 'layer')
|
||||
.call(tooltip()
|
||||
.html(true)
|
||||
.title(function(d) {
|
||||
var tip = t(name + '.' + d + '.tooltip'),
|
||||
key = (d === 'wireframe' ? t('area_fill.wireframe.key') : null);
|
||||
|
||||
if (name === 'feature' && autoHiddenFeature(d)) {
|
||||
var msg = showsLayer('osm') ? t('map_data.autohidden') : t('map_data.osmhidden');
|
||||
tip += '<div>' + msg + '</div>';
|
||||
}
|
||||
return uiTooltipHtml(tip, key);
|
||||
liEnter
|
||||
.append('button')
|
||||
.attr('class', 'list-item-gpx-browse')
|
||||
.call(tooltip()
|
||||
.title(t('gpx.browse'))
|
||||
.placement((textDirection === 'rtl') ? 'right' : 'left')
|
||||
)
|
||||
.on('click', function() {
|
||||
d3_select(document.createElement('input'))
|
||||
.attr('type', 'file')
|
||||
.on('change', function() {
|
||||
gpx.files(d3_event.target.files);
|
||||
})
|
||||
.placement('top')
|
||||
);
|
||||
.node().click();
|
||||
})
|
||||
.call(svgIcon('#icon-geolocate'));
|
||||
|
||||
var label = enter
|
||||
.append('label');
|
||||
var labelEnter = liEnter
|
||||
.append('label')
|
||||
.call(tooltip()
|
||||
.title(t('gpx.drag_drop'))
|
||||
.placement('top')
|
||||
);
|
||||
|
||||
label
|
||||
.append('input')
|
||||
.attr('type', type)
|
||||
.attr('name', name)
|
||||
.on('change', change);
|
||||
labelEnter
|
||||
.append('input')
|
||||
.attr('type', 'checkbox')
|
||||
.on('change', function() { toggleLayer('gpx'); });
|
||||
|
||||
label
|
||||
.append('span')
|
||||
.text(function(d) { return t(name + '.' + d + '.description'); });
|
||||
labelEnter
|
||||
.append('span')
|
||||
.text(t('gpx.local_layer'));
|
||||
|
||||
// Update
|
||||
items = items
|
||||
.merge(enter);
|
||||
// Update
|
||||
ul = ul
|
||||
.merge(ulEnter);
|
||||
|
||||
items
|
||||
.classed('active', active)
|
||||
.selectAll('input')
|
||||
.property('checked', active)
|
||||
.property('indeterminate', function(d) {
|
||||
return (name === 'feature' && autoHiddenFeature(d));
|
||||
});
|
||||
ul.selectAll('.list-item-gpx')
|
||||
.classed('active', showsGpx)
|
||||
.selectAll('label')
|
||||
.classed('deemphasize', !hasGpx)
|
||||
.selectAll('input')
|
||||
.property('disabled', !hasGpx)
|
||||
.property('checked', showsGpx);
|
||||
}
|
||||
|
||||
|
||||
function drawListItems(selection, data, type, name, change, active) {
|
||||
var items = selection.selectAll('li')
|
||||
.data(data);
|
||||
|
||||
// Exit
|
||||
items.exit()
|
||||
.remove();
|
||||
|
||||
// Enter
|
||||
var enter = items.enter()
|
||||
.append('li')
|
||||
.attr('class', 'layer')
|
||||
.call(tooltip()
|
||||
.html(true)
|
||||
.title(function(d) {
|
||||
var tip = t(name + '.' + d + '.tooltip'),
|
||||
key = (d === 'wireframe' ? t('area_fill.wireframe.key') : null);
|
||||
|
||||
if (name === 'feature' && autoHiddenFeature(d)) {
|
||||
var msg = showsLayer('osm') ? t('map_data.autohidden') : t('map_data.osmhidden');
|
||||
tip += '<div>' + msg + '</div>';
|
||||
}
|
||||
return uiTooltipHtml(tip, key);
|
||||
})
|
||||
.placement('top')
|
||||
);
|
||||
|
||||
var label = enter
|
||||
.append('label');
|
||||
|
||||
label
|
||||
.append('input')
|
||||
.attr('type', type)
|
||||
.attr('name', name)
|
||||
.on('change', change);
|
||||
|
||||
label
|
||||
.append('span')
|
||||
.text(function(d) { return t(name + '.' + d + '.description'); });
|
||||
|
||||
// Update
|
||||
items = items
|
||||
.merge(enter);
|
||||
|
||||
items
|
||||
.classed('active', active)
|
||||
.selectAll('input')
|
||||
.property('checked', active)
|
||||
.property('indeterminate', function(d) {
|
||||
return (name === 'feature' && autoHiddenFeature(d));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function renderDataLayers(selection) {
|
||||
var container = selection.selectAll('data-layer-container')
|
||||
.data([0]);
|
||||
|
||||
_dataLayerContainer = container.enter()
|
||||
.append('div')
|
||||
.attr('class', 'data-layer-container')
|
||||
.merge(container);
|
||||
}
|
||||
|
||||
|
||||
function renderFillList(selection) {
|
||||
var container = selection.selectAll('layer-fill-list')
|
||||
.data([0]);
|
||||
|
||||
_fillList = container.enter()
|
||||
.append('ul')
|
||||
.attr('class', 'layer-list layer-fill-list')
|
||||
.merge(container);
|
||||
}
|
||||
|
||||
|
||||
function renderFeatureList(selection) {
|
||||
var container = selection.selectAll('layer-feature-list')
|
||||
.data([0]);
|
||||
|
||||
_featureList = container.enter()
|
||||
.append('ul')
|
||||
.attr('class', 'layer-list layer-feature-list')
|
||||
.merge(container);
|
||||
}
|
||||
|
||||
|
||||
function update() {
|
||||
_dataLayerContainer
|
||||
.call(drawOsmItem)
|
||||
.call(drawPhotoItems)
|
||||
.call(drawGpxItem);
|
||||
|
||||
_fillList
|
||||
.call(drawListItems, fills, 'radio', 'area_fill', setFill, showsFill);
|
||||
|
||||
_featureList
|
||||
.call(drawListItems, features, 'checkbox', 'feature', clickFeature, showsFeature);
|
||||
}
|
||||
|
||||
|
||||
function toggleWireframe() {
|
||||
if (d3_event) {
|
||||
d3_event.preventDefault();
|
||||
d3_event.stopPropagation();
|
||||
}
|
||||
setFill((_fillSelected === 'wireframe' ? _fillDefault : 'wireframe'));
|
||||
context.map().pan([0,0]); // trigger a redraw
|
||||
}
|
||||
|
||||
|
||||
function update() {
|
||||
dataLayerContainer
|
||||
.call(drawOsmItem)
|
||||
.call(drawPhotoItems)
|
||||
.call(drawGpxItem);
|
||||
function mapData(selection) {
|
||||
|
||||
fillList
|
||||
.call(drawList, fills, 'radio', 'area_fill', setFill, showsFill);
|
||||
|
||||
featureList
|
||||
.call(drawList, features, 'checkbox', 'feature', clickFeature, showsFeature);
|
||||
}
|
||||
|
||||
|
||||
function hidePanel() {
|
||||
function hidePane() {
|
||||
setVisible(false);
|
||||
}
|
||||
|
||||
|
||||
function togglePanel() {
|
||||
function togglePane() {
|
||||
if (d3_event) d3_event.preventDefault();
|
||||
tooltipBehavior.hide(button);
|
||||
paneTooltip.hide(button);
|
||||
setVisible(!button.classed('active'));
|
||||
}
|
||||
|
||||
|
||||
function toggleWireframe() {
|
||||
if (d3_event) {
|
||||
d3_event.preventDefault();
|
||||
d3_event.stopPropagation();
|
||||
}
|
||||
setFill((fillSelected === 'wireframe' ? fillDefault : 'wireframe'));
|
||||
context.map().pan([0,0]); // trigger a redraw
|
||||
}
|
||||
|
||||
|
||||
function setVisible(show) {
|
||||
if (show !== shown) {
|
||||
if (show !== _shown) {
|
||||
button.classed('active', show);
|
||||
shown = show;
|
||||
_shown = show;
|
||||
|
||||
if (show) {
|
||||
uiBackground.hidePane();
|
||||
uiHelp.hidePane();
|
||||
update();
|
||||
selection.on('mousedown.map_data-inside', function() {
|
||||
return d3_event.stopPropagation();
|
||||
});
|
||||
content.style('display', 'block')
|
||||
|
||||
pane
|
||||
.style('display', 'block')
|
||||
.style('right', '-300px')
|
||||
.transition()
|
||||
.duration(200)
|
||||
.style('right', '0px');
|
||||
|
||||
} else {
|
||||
content.style('display', 'block')
|
||||
pane
|
||||
.style('display', 'block')
|
||||
.style('right', '0px')
|
||||
.transition()
|
||||
.duration(200)
|
||||
@@ -386,113 +429,80 @@ export function uiMapData(context) {
|
||||
.on('end', function() {
|
||||
d3_select(this).style('display', 'none');
|
||||
});
|
||||
selection.on('mousedown.map_data-inside', null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var content = selection
|
||||
.append('div')
|
||||
.attr('class', 'fillL map-overlay col3 content hide'),
|
||||
tooltipBehavior = tooltip()
|
||||
.placement((textDirection === 'rtl') ? 'right' : 'left')
|
||||
.html(true)
|
||||
.title(uiTooltipHtml(t('map_data.description'), key)),
|
||||
button = selection
|
||||
.append('button')
|
||||
.attr('tabindex', -1)
|
||||
.on('click', togglePanel)
|
||||
.call(svgIcon('#icon-data', 'light'))
|
||||
.call(tooltipBehavior),
|
||||
shown = false;
|
||||
var pane = selection
|
||||
.append('div')
|
||||
.attr('class', 'fillL map-overlay col3 content hide');
|
||||
|
||||
content
|
||||
.append('h4')
|
||||
var paneTooltip = tooltip()
|
||||
.placement((textDirection === 'rtl') ? 'right' : 'left')
|
||||
.html(true)
|
||||
.title(uiTooltipHtml(t('map_data.description'), key));
|
||||
|
||||
var button = selection
|
||||
.append('button')
|
||||
.attr('tabindex', -1)
|
||||
.on('click', togglePane)
|
||||
.call(svgIcon('#icon-data', 'light'))
|
||||
.call(paneTooltip);
|
||||
|
||||
|
||||
pane
|
||||
.append('h2')
|
||||
.text(t('map_data.title'));
|
||||
|
||||
|
||||
// data layers
|
||||
content
|
||||
.append('a')
|
||||
.text(t('map_data.data_layers'))
|
||||
.attr('href', '#')
|
||||
.classed('hide-toggle', true)
|
||||
.classed('expanded', true)
|
||||
.on('click', function() {
|
||||
var exp = d3_select(this).classed('expanded');
|
||||
dataLayerContainer.style('display', exp ? 'none' : 'block');
|
||||
d3_select(this).classed('expanded', !exp);
|
||||
d3_event.preventDefault();
|
||||
});
|
||||
|
||||
var dataLayerContainer = content
|
||||
pane
|
||||
.append('div')
|
||||
.attr('class', 'data-data-layers')
|
||||
.style('display', 'block');
|
||||
|
||||
.attr('class', 'map-data-data-layers')
|
||||
.call(uiDisclosure(context, 'data_layers', true)
|
||||
.title(t('map_data.data_layers'))
|
||||
.content(renderDataLayers)
|
||||
);
|
||||
|
||||
// area fills
|
||||
content
|
||||
.append('a')
|
||||
.text(t('map_data.fill_area'))
|
||||
.attr('href', '#')
|
||||
.classed('hide-toggle', true)
|
||||
.classed('expanded', false)
|
||||
.on('click', function() {
|
||||
var exp = d3_select(this).classed('expanded');
|
||||
fillContainer.style('display', exp ? 'none' : 'block');
|
||||
d3_select(this).classed('expanded', !exp);
|
||||
d3_event.preventDefault();
|
||||
});
|
||||
|
||||
var fillContainer = content
|
||||
pane
|
||||
.append('div')
|
||||
.attr('class', 'data-area-fills')
|
||||
.style('display', 'none');
|
||||
|
||||
var fillList = fillContainer
|
||||
.append('ul')
|
||||
.attr('class', 'layer-list layer-fill-list');
|
||||
|
||||
.attr('class', 'map-data-area-fills')
|
||||
.call(uiDisclosure(context, 'fill_area', false)
|
||||
.title(t('map_data.fill_area'))
|
||||
.content(renderFillList)
|
||||
);
|
||||
|
||||
// feature filters
|
||||
content
|
||||
.append('a')
|
||||
.text(t('map_data.map_features'))
|
||||
.attr('href', '#')
|
||||
.classed('hide-toggle', true)
|
||||
.classed('expanded', false)
|
||||
.on('click', function() {
|
||||
var exp = d3_select(this).classed('expanded');
|
||||
featureContainer.style('display', exp ? 'none' : 'block');
|
||||
d3_select(this).classed('expanded', !exp);
|
||||
d3_event.preventDefault();
|
||||
});
|
||||
|
||||
var featureContainer = content
|
||||
pane
|
||||
.append('div')
|
||||
.attr('class', 'data-feature-filters')
|
||||
.style('display', 'none');
|
||||
|
||||
var featureList = featureContainer
|
||||
.append('ul')
|
||||
.attr('class', 'layer-list layer-feature-list');
|
||||
.attr('class', 'map-data-feature-filters')
|
||||
.call(uiDisclosure(context, 'map_features', false)
|
||||
.title(t('map_data.map_features'))
|
||||
.content(renderFeatureList)
|
||||
);
|
||||
|
||||
|
||||
// add listeners
|
||||
context.features()
|
||||
.on('change.map_data-update', update);
|
||||
|
||||
setFill(fillDefault);
|
||||
update();
|
||||
setFill(_fillDefault);
|
||||
|
||||
var keybinding = d3_keybinding('features')
|
||||
.on(key, togglePanel)
|
||||
.on(key, togglePane)
|
||||
.on(t('area_fill.wireframe.key'), toggleWireframe)
|
||||
.on([t('background.key'), t('help.key')], hidePanel);
|
||||
.on([t('background.key'), t('help.key')], hidePane);
|
||||
|
||||
d3_select(document)
|
||||
.call(keybinding);
|
||||
|
||||
uiMapData.hidePane = hidePane;
|
||||
uiMapData.togglePane = togglePane;
|
||||
uiMapData.setVisible = setVisible;
|
||||
}
|
||||
|
||||
return map_data;
|
||||
return mapData;
|
||||
}
|
||||
|
||||
@@ -284,9 +284,10 @@ export function uiMapInMap(context) {
|
||||
|
||||
isHidden = !isHidden;
|
||||
|
||||
var label = d3_select('.minimap-toggle');
|
||||
label.classed('active', !isHidden)
|
||||
.select('input').property('checked', !isHidden);
|
||||
d3_select('.minimap-toggle-item')
|
||||
.classed('active', !isHidden)
|
||||
.select('input')
|
||||
.property('checked', !isHidden);
|
||||
|
||||
if (isHidden) {
|
||||
wrap
|
||||
|
||||
@@ -16,7 +16,6 @@ import { utilRebind } from '../util';
|
||||
export function uiPresetEditor(context) {
|
||||
var dispatch = d3_dispatch('change'),
|
||||
formFields = uiFormFields(context),
|
||||
expandedPreference = (context.storage('preset_fields.expanded') !== 'false'),
|
||||
state,
|
||||
fieldsArr,
|
||||
preset,
|
||||
@@ -25,17 +24,10 @@ export function uiPresetEditor(context) {
|
||||
|
||||
|
||||
function presetEditor(selection) {
|
||||
selection.call(uiDisclosure()
|
||||
selection.call(uiDisclosure(context, 'preset_fields', true)
|
||||
.title(t('inspector.all_fields'))
|
||||
.expanded(expandedPreference)
|
||||
.on('toggled', toggled)
|
||||
.content(render)
|
||||
);
|
||||
|
||||
function toggled(expanded) {
|
||||
expandedPreference = expanded;
|
||||
context.storage('preset_fields.expanded', expanded);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@ import {
|
||||
|
||||
|
||||
export function uiRawMemberEditor(context) {
|
||||
var id,
|
||||
taginfo = services.taginfo;
|
||||
var taginfo = services.taginfo,
|
||||
_entityID;
|
||||
|
||||
|
||||
function selectMember(d) {
|
||||
@@ -53,7 +53,7 @@ export function uiRawMemberEditor(context) {
|
||||
|
||||
|
||||
function rawMemberEditor(selection) {
|
||||
var entity = context.entity(id),
|
||||
var entity = context.entity(_entityID),
|
||||
memberships = [];
|
||||
|
||||
entity.members.slice(0, 1000).forEach(function(member, index) {
|
||||
@@ -68,21 +68,17 @@ export function uiRawMemberEditor(context) {
|
||||
});
|
||||
|
||||
var gt = entity.members.length > 1000 ? '>' : '';
|
||||
selection.call(uiDisclosure()
|
||||
selection.call(uiDisclosure(context, 'raw_member_editor', true)
|
||||
.title(t('inspector.all_members') + ' (' + gt + memberships.length + ')')
|
||||
.expanded(true)
|
||||
.on('toggled', toggled)
|
||||
.updatePreference(false)
|
||||
.on('toggled', function(expanded) {
|
||||
if (expanded) { selection.node().parentNode.scrollTop += 200; }
|
||||
})
|
||||
.content(content)
|
||||
);
|
||||
|
||||
|
||||
function toggled(expanded) {
|
||||
if (expanded) {
|
||||
selection.node().parentNode.scrollTop += 200;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function content(wrap) {
|
||||
var list = wrap.selectAll('.member-list')
|
||||
.data([0]);
|
||||
@@ -201,8 +197,8 @@ export function uiRawMemberEditor(context) {
|
||||
|
||||
|
||||
rawMemberEditor.entityID = function(_) {
|
||||
if (!arguments.length) return id;
|
||||
id = _;
|
||||
if (!arguments.length) return _entityID;
|
||||
_entityID = _;
|
||||
return rawMemberEditor;
|
||||
};
|
||||
|
||||
|
||||
@@ -28,7 +28,8 @@ import { utilDisplayName, utilNoAuto } from '../util';
|
||||
|
||||
export function uiRawMembershipEditor(context) {
|
||||
var taginfo = services.taginfo,
|
||||
id, showBlank;
|
||||
_entityID,
|
||||
_showBlank;
|
||||
|
||||
|
||||
function selectRelation(d) {
|
||||
@@ -47,11 +48,13 @@ export function uiRawMembershipEditor(context) {
|
||||
|
||||
|
||||
function addMembership(d, role) {
|
||||
showBlank = false;
|
||||
_showBlank = false;
|
||||
|
||||
var member = { id: _entityID, type: context.entity(_entityID).type, role: role };
|
||||
|
||||
if (d.relation) {
|
||||
context.perform(
|
||||
actionAddMember(d.relation.id, { id: id, type: context.entity(id).type, role: role }),
|
||||
actionAddMember(d.relation.id, member),
|
||||
t('operations.add_member.annotation')
|
||||
);
|
||||
|
||||
@@ -59,7 +62,7 @@ export function uiRawMembershipEditor(context) {
|
||||
var relation = osmRelation();
|
||||
context.perform(
|
||||
actionAddEntity(relation),
|
||||
actionAddMember(relation.id, { id: id, type: context.entity(id).type, role: role }),
|
||||
actionAddMember(relation.id, member),
|
||||
t('operations.add.annotation.relation')
|
||||
);
|
||||
|
||||
@@ -77,15 +80,12 @@ export function uiRawMembershipEditor(context) {
|
||||
|
||||
|
||||
function relations(q) {
|
||||
var newRelation = {
|
||||
relation: null,
|
||||
value: t('inspector.new_relation')
|
||||
},
|
||||
result = [],
|
||||
graph = context.graph();
|
||||
var newRelation = { relation: null, value: t('inspector.new_relation') };
|
||||
var result = [];
|
||||
var graph = context.graph();
|
||||
|
||||
context.intersects(context.extent()).forEach(function(entity) {
|
||||
if (entity.type !== 'relation' || entity.id === id)
|
||||
if (entity.type !== 'relation' || entity.id === _entityID)
|
||||
return;
|
||||
|
||||
var matched = context.presets().match(entity, graph),
|
||||
@@ -96,10 +96,7 @@ export function uiRawMembershipEditor(context) {
|
||||
if (q && value.toLowerCase().indexOf(q.toLowerCase()) === -1)
|
||||
return;
|
||||
|
||||
result.push({
|
||||
relation: entity,
|
||||
value: value
|
||||
});
|
||||
result.push({ relation: entity, value: value });
|
||||
});
|
||||
|
||||
result.sort(function(a, b) {
|
||||
@@ -124,7 +121,7 @@ export function uiRawMembershipEditor(context) {
|
||||
|
||||
|
||||
function rawMembershipEditor(selection) {
|
||||
var entity = context.entity(id),
|
||||
var entity = context.entity(_entityID),
|
||||
parents = context.graph().parentRelations(entity),
|
||||
memberships = [];
|
||||
|
||||
@@ -137,21 +134,17 @@ export function uiRawMembershipEditor(context) {
|
||||
});
|
||||
|
||||
var gt = parents.length > 1000 ? '>' : '';
|
||||
selection.call(uiDisclosure()
|
||||
selection.call(uiDisclosure(context, 'raw_membership_editor', true)
|
||||
.title(t('inspector.all_relations') + ' (' + gt + memberships.length + ')')
|
||||
.expanded(true)
|
||||
.on('toggled', toggled)
|
||||
.updatePreference(false)
|
||||
.on('toggled', function(expanded) {
|
||||
if (expanded) { selection.node().parentNode.scrollTop += 200; }
|
||||
})
|
||||
.content(content)
|
||||
);
|
||||
|
||||
|
||||
function toggled(expanded) {
|
||||
if (expanded) {
|
||||
selection.node().parentNode.scrollTop += 200;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function content(wrap) {
|
||||
var list = wrap.selectAll('.member-list')
|
||||
.data([0]);
|
||||
@@ -218,7 +211,7 @@ export function uiRawMembershipEditor(context) {
|
||||
|
||||
|
||||
var newrow = list.selectAll('.member-row-new')
|
||||
.data(showBlank ? [0] : []);
|
||||
.data(_showBlank ? [0] : []);
|
||||
|
||||
newrow.exit()
|
||||
.remove();
|
||||
@@ -272,7 +265,7 @@ export function uiRawMembershipEditor(context) {
|
||||
addrel
|
||||
.call(svgIcon('#icon-plus', 'light'))
|
||||
.on('click', function() {
|
||||
showBlank = true;
|
||||
_showBlank = true;
|
||||
content(wrap);
|
||||
list.selectAll('.member-entity-input').node().focus();
|
||||
});
|
||||
@@ -308,7 +301,7 @@ export function uiRawMembershipEditor(context) {
|
||||
taginfo.roles({
|
||||
debounce: true,
|
||||
rtype: rtype || '',
|
||||
geometry: context.geometry(id),
|
||||
geometry: context.geometry(_entityID),
|
||||
query: role
|
||||
}, function(err, data) {
|
||||
if (!err) callback(sort(role, data));
|
||||
@@ -328,8 +321,8 @@ export function uiRawMembershipEditor(context) {
|
||||
|
||||
|
||||
rawMembershipEditor.entityID = function(_) {
|
||||
if (!arguments.length) return id;
|
||||
id = _;
|
||||
if (!arguments.length) return _entityID;
|
||||
_entityID = _;
|
||||
return rawMembershipEditor;
|
||||
};
|
||||
|
||||
|
||||
@@ -25,34 +25,36 @@ import {
|
||||
export function uiRawTagEditor(context) {
|
||||
var taginfo = services.taginfo,
|
||||
dispatch = d3_dispatch('change'),
|
||||
expandedPreference = (context.storage('raw_tag_editor.expanded') === 'true'),
|
||||
expandedCurrent = expandedPreference,
|
||||
updatePreference = true,
|
||||
readOnlyTags = [],
|
||||
showBlank = false,
|
||||
newRow,
|
||||
state,
|
||||
preset,
|
||||
tags,
|
||||
id;
|
||||
_readOnlyTags = [],
|
||||
_showBlank = false,
|
||||
_updatePreference = true,
|
||||
_expanded = false,
|
||||
_newRow,
|
||||
_state,
|
||||
_preset,
|
||||
_tags,
|
||||
_entityID;
|
||||
|
||||
|
||||
function rawTagEditor(selection) {
|
||||
var count = Object.keys(tags).filter(function(d) { return d; }).length;
|
||||
var count = Object.keys(_tags).filter(function(d) { return d; }).length;
|
||||
|
||||
selection.call(uiDisclosure()
|
||||
var disclosure = uiDisclosure(context, 'raw_tag_editor', false)
|
||||
.title(t('inspector.all_tags') + ' (' + count + ')')
|
||||
.expanded(expandedCurrent)
|
||||
.on('toggled', toggled)
|
||||
.content(content)
|
||||
);
|
||||
.updatePreference(_updatePreference)
|
||||
.content(content);
|
||||
|
||||
// Sometimes we want to force the raw_tag_editor to be opened/closed..
|
||||
// When undefined, uiDisclosure will use the user's stored preference.
|
||||
if (_expanded !== undefined) {
|
||||
disclosure.expanded(_expanded);
|
||||
}
|
||||
|
||||
selection.call(disclosure);
|
||||
|
||||
function toggled(expanded) {
|
||||
expandedCurrent = expanded;
|
||||
if (updatePreference) {
|
||||
expandedPreference = expanded;
|
||||
context.storage('raw_tag_editor.expanded', expanded);
|
||||
}
|
||||
_expanded = expanded;
|
||||
if (expanded) {
|
||||
selection.node().parentNode.scrollTop += 200;
|
||||
}
|
||||
@@ -61,14 +63,14 @@ export function uiRawTagEditor(context) {
|
||||
|
||||
|
||||
function content(wrap) {
|
||||
var entries = _map(tags, function(v, k) {
|
||||
var entries = _map(_tags, function(v, k) {
|
||||
return { key: k, value: v };
|
||||
});
|
||||
|
||||
if (!entries.length || showBlank) {
|
||||
showBlank = false;
|
||||
if (!entries.length || _showBlank) {
|
||||
_showBlank = false;
|
||||
entries.push({key: '', value: ''});
|
||||
newRow = '';
|
||||
_newRow = '';
|
||||
}
|
||||
|
||||
var list = wrap.selectAll('.tag-list')
|
||||
@@ -138,8 +140,8 @@ export function uiRawTagEditor(context) {
|
||||
items = items
|
||||
.merge(enter)
|
||||
.sort(function(a, b) {
|
||||
return (a.key === newRow && b.key !== newRow) ? 1
|
||||
: (a.key !== newRow && b.key === newRow) ? -1
|
||||
return (a.key === _newRow && b.key !== _newRow) ? 1
|
||||
: (a.key !== _newRow && b.key === _newRow) ? -1
|
||||
: d3_ascending(a.key, b.key);
|
||||
});
|
||||
|
||||
@@ -149,11 +151,11 @@ export function uiRawTagEditor(context) {
|
||||
key = row.select('input.key'), // propagate bound data to child
|
||||
value = row.select('input.value'); // propagate bound data to child
|
||||
|
||||
if (id && taginfo) {
|
||||
if (_entityID && taginfo) {
|
||||
bindTypeahead(key, value);
|
||||
}
|
||||
|
||||
var isRelation = (id && context.entity(id).type === 'relation'),
|
||||
var isRelation = (_entityID && context.entity(_entityID).type === 'relation'),
|
||||
reference;
|
||||
|
||||
if (isRelation && tag.key === 'type') {
|
||||
@@ -162,7 +164,7 @@ export function uiRawTagEditor(context) {
|
||||
reference = uiTagReference({ key: tag.key, value: tag.value }, context);
|
||||
}
|
||||
|
||||
if (state === 'hover') {
|
||||
if (_state === 'hover') {
|
||||
reference.showing(false);
|
||||
}
|
||||
|
||||
@@ -187,8 +189,8 @@ export function uiRawTagEditor(context) {
|
||||
|
||||
|
||||
function isReadOnly(d) {
|
||||
for (var i = 0; i < readOnlyTags.length; i++) {
|
||||
if (d.key.match(readOnlyTags[i]) !== null) {
|
||||
for (var i = 0; i < _readOnlyTags.length; i++) {
|
||||
if (d.key.match(_readOnlyTags[i]) !== null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -206,7 +208,7 @@ export function uiRawTagEditor(context) {
|
||||
|
||||
function bindTypeahead(key, value) {
|
||||
if (isReadOnly({ key: key })) return;
|
||||
var geometry = context.geometry(id);
|
||||
var geometry = context.geometry(_entityID);
|
||||
|
||||
key.call(d3_combobox()
|
||||
.container(context.container())
|
||||
@@ -275,7 +277,7 @@ export function uiRawTagEditor(context) {
|
||||
var match = kNew.match(/^(.*?)(?:_(\d+))?$/),
|
||||
base = match[1],
|
||||
suffix = +(match[2] || 1);
|
||||
while (tags[kNew]) { // rename key if already in use
|
||||
while (_tags[kNew]) { // rename key if already in use
|
||||
kNew = base + '_' + suffix++;
|
||||
}
|
||||
}
|
||||
@@ -284,8 +286,8 @@ export function uiRawTagEditor(context) {
|
||||
|
||||
d.key = kNew; // Maintain DOM identity through the subsequent update.
|
||||
|
||||
if (newRow === kOld) { // see if this row is still a new row
|
||||
newRow = ((d.value === '' || kNew === '') ? kNew : undefined);
|
||||
if (_newRow === kOld) { // see if this row is still a new row
|
||||
_newRow = ((d.value === '' || kNew === '') ? kNew : undefined);
|
||||
}
|
||||
|
||||
this.value = kNew;
|
||||
@@ -298,8 +300,8 @@ export function uiRawTagEditor(context) {
|
||||
var tag = {};
|
||||
tag[d.key] = this.value;
|
||||
|
||||
if (newRow === d.key && d.key !== '' && d.value !== '') { // not a new row anymore
|
||||
newRow = undefined;
|
||||
if (_newRow === d.key && d.key !== '' && d.value !== '') { // not a new row anymore
|
||||
_newRow = undefined;
|
||||
}
|
||||
|
||||
dispatch.call('change', this, tag);
|
||||
@@ -320,7 +322,7 @@ export function uiRawTagEditor(context) {
|
||||
// handler. Without the setTimeout, the call to `content` would
|
||||
// wipe out the pending value change.
|
||||
setTimeout(function() {
|
||||
showBlank = true;
|
||||
_showBlank = true;
|
||||
content(wrap);
|
||||
list.selectAll('li:last-child input.key').node().focus();
|
||||
}, 0);
|
||||
@@ -329,51 +331,51 @@ export function uiRawTagEditor(context) {
|
||||
|
||||
|
||||
rawTagEditor.state = function(_) {
|
||||
if (!arguments.length) return state;
|
||||
state = _;
|
||||
if (!arguments.length) return _state;
|
||||
_state = _;
|
||||
return rawTagEditor;
|
||||
};
|
||||
|
||||
|
||||
rawTagEditor.preset = function(_) {
|
||||
if (!arguments.length) return preset;
|
||||
preset = _;
|
||||
if (preset.isFallback()) {
|
||||
expandedCurrent = true;
|
||||
updatePreference = false;
|
||||
if (!arguments.length) return _preset;
|
||||
_preset = _;
|
||||
if (_preset.isFallback()) {
|
||||
_expanded = true;
|
||||
_updatePreference = false;
|
||||
} else {
|
||||
expandedCurrent = expandedPreference;
|
||||
updatePreference = true;
|
||||
_expanded = undefined;
|
||||
_updatePreference = true;
|
||||
}
|
||||
return rawTagEditor;
|
||||
};
|
||||
|
||||
|
||||
rawTagEditor.tags = function(_) {
|
||||
if (!arguments.length) return tags;
|
||||
tags = _;
|
||||
if (!arguments.length) return _tags;
|
||||
_tags = _;
|
||||
return rawTagEditor;
|
||||
};
|
||||
|
||||
|
||||
rawTagEditor.entityID = function(_) {
|
||||
if (!arguments.length) return id;
|
||||
id = _;
|
||||
if (!arguments.length) return _entityID;
|
||||
_entityID = _;
|
||||
return rawTagEditor;
|
||||
};
|
||||
|
||||
|
||||
rawTagEditor.expanded = function(_) {
|
||||
if (!arguments.length) return expandedCurrent;
|
||||
expandedCurrent = _;
|
||||
updatePreference = false;
|
||||
if (!arguments.length) return _expanded;
|
||||
_expanded = _;
|
||||
_updatePreference = false;
|
||||
return rawTagEditor;
|
||||
};
|
||||
|
||||
|
||||
rawTagEditor.readOnlyTags = function(_) {
|
||||
if (!arguments.length) return readOnlyTags;
|
||||
readOnlyTags = _;
|
||||
if (!arguments.length) return _readOnlyTags;
|
||||
_readOnlyTags = _;
|
||||
return rawTagEditor;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user