mirror of
https://github.com/FoggedLens/iD.git
synced 2026-03-01 00:43:45 +00:00
- adding a temp wikipedia icon from http://upload.wikimedia.org/wikipedia/commons/4/45/Right-facing-Arrow-icon.jpg Making the click update and rotate an image marker on the map with comapss direction. Needs to be centered etc. now properly enabling/disabling the different Mapillary layers upon activation/deactivation Upgrade to faster Mapillary API better arrow icon, refactoring to have all single-image operations in the image-layer dist build adding mapillary translation adjusting image link trying to adjust the image link for github deploy better layout removing font-awesome, not needed. https for calls consistent quotes taking care of more translation, fix case of no images found on Mapillary more english translations - scoping image calls to selection. - .inspector-wrap and .panewrap are hard to scope, since they are outside the selection, same for the #mapillary-inspector. -scoping calls in sequences layer adding translation fixing jslint errors more jshint errors adding mapillary to tests trying to lay out single markers, please help with the geo translation, @jfirebaugh - adding the image layer to the active iD SVG instead of background - add a new mode for selecting Mapillary images - first stab of adding the image pane in the sidebar itself in order to contain the selections (needs to be layouted) cleaning trying to mark and keep selected image between mouseovers refactoring to contain mapillary into the iamge mode refactoring to contain mapillary into the iamge mode adding to test html cleaning up handling unset selected image cleanup better sidebar moving image into the lower right Minor visual adjustment mapillaryImage better no_image text and toggling of selected image handling of text disappearing intendation fixing test errors making sequences be below images open Mapillary links in new tabs better arrows and selectability on arrows as a workaround for real navigation in panos more contrast for the selected image adjusting image style - adjusting style, removing sequence lines - adding photos as a mode with shortcut 'm' - fix test errors moving switch back to right sidebar, keeping keyboard shortcut. cleanup file rename to avoid GIT mess with casing. - better scoping - removed unused hover function - making the checkbox follow mode changes removing unused icon handling automatic mode exit
411 lines
13 KiB
JavaScript
411 lines
13 KiB
JavaScript
iD.Map = function(context) {
|
|
var dimensions = [1, 1],
|
|
dispatch = d3.dispatch('move', 'drawn'),
|
|
projection = context.projection,
|
|
roundedProjection = iD.svg.RoundProjection(projection),
|
|
zoom = d3.behavior.zoom()
|
|
.translate(projection.translate())
|
|
.scale(projection.scale() * 2 * Math.PI)
|
|
.scaleExtent([1024, 256 * Math.pow(2, 24)])
|
|
.on('zoom', zoomPan),
|
|
dblclickEnabled = true,
|
|
transformStart,
|
|
transformed = false,
|
|
minzoom = 0,
|
|
points = iD.svg.Points(roundedProjection, context),
|
|
vertices = iD.svg.Vertices(roundedProjection, context),
|
|
lines = iD.svg.Lines(projection),
|
|
areas = iD.svg.Areas(projection),
|
|
midpoints = iD.svg.Midpoints(roundedProjection, context),
|
|
labels = iD.svg.Labels(projection, context),
|
|
sequences = iD.svg.Sequences(projection, context),
|
|
supersurface, surface,
|
|
mouse,
|
|
mousemove;
|
|
|
|
function map(selection) {
|
|
context.history()
|
|
.on('change.map', redraw);
|
|
context.background()
|
|
.on('change.map', redraw);
|
|
|
|
selection.call(zoom);
|
|
|
|
supersurface = selection.append('div')
|
|
.attr('id', 'supersurface');
|
|
|
|
supersurface.call(context.background());
|
|
|
|
// Need a wrapper div because Opera can't cope with an absolutely positioned
|
|
// SVG element: http://bl.ocks.org/jfirebaugh/6fbfbd922552bf776c16
|
|
var dataLayer = supersurface.append('div')
|
|
.attr('class', 'layer-layer layer-data');
|
|
|
|
map.surface = surface = dataLayer.append('svg')
|
|
.on('mousedown.zoom', function() {
|
|
if (d3.event.button === 2) {
|
|
d3.event.stopPropagation();
|
|
}
|
|
}, true)
|
|
.on('mouseup.zoom', function() {
|
|
if (resetTransform()) redraw();
|
|
})
|
|
.attr('id', 'surface')
|
|
.call(iD.svg.Surface(context));
|
|
|
|
surface.on('mousemove.map', function() {
|
|
mousemove = d3.event;
|
|
});
|
|
|
|
surface.on('mouseover.vertices', function() {
|
|
if (map.editable() && !transformed) {
|
|
var hover = d3.event.target.__data__;
|
|
surface.call(vertices.drawHover, context.graph(), hover, map.extent(), map.zoom());
|
|
dispatch.drawn({full: false});
|
|
}
|
|
});
|
|
|
|
surface.on('mouseout.vertices', function() {
|
|
if (map.editable() && !transformed) {
|
|
var hover = d3.event.relatedTarget && d3.event.relatedTarget.__data__;
|
|
surface.call(vertices.drawHover, context.graph(), hover, map.extent(), map.zoom());
|
|
dispatch.drawn({full: false});
|
|
}
|
|
});
|
|
|
|
context.on('enter.map', function() {
|
|
if (map.editable() && !transformed) {
|
|
var all = context.intersects(map.extent()),
|
|
filter = d3.functor(true),
|
|
graph = context.graph();
|
|
surface.call(vertices, graph, all, filter, map.extent(), map.zoom());
|
|
surface.call(midpoints, graph, all, filter, map.trimmedExtent());
|
|
dispatch.drawn({full: false});
|
|
}
|
|
});
|
|
|
|
map.dimensions(selection.dimensions());
|
|
|
|
labels.supersurface(supersurface);
|
|
}
|
|
|
|
function pxCenter() { return [dimensions[0] / 2, dimensions[1] / 2]; }
|
|
|
|
function drawVector(difference, extent) {
|
|
var filter, all,
|
|
graph = context.graph();
|
|
|
|
if (difference) {
|
|
var complete = difference.complete(map.extent());
|
|
all = _.compact(_.values(complete));
|
|
filter = function(d) { return d.id in complete; };
|
|
|
|
} else if (extent) {
|
|
all = context.intersects(map.extent().intersection(extent));
|
|
var set = d3.set(_.pluck(all, 'id'));
|
|
filter = function(d) { return set.has(d.id); };
|
|
|
|
} else {
|
|
all = context.intersects(map.extent());
|
|
filter = d3.functor(true);
|
|
}
|
|
|
|
surface
|
|
.call(vertices, graph, all, filter, map.extent(), map.zoom())
|
|
.call(lines, graph, all, filter)
|
|
.call(areas, graph, all, filter)
|
|
.call(sequences, surface)
|
|
.call(midpoints, graph, all, filter, map.trimmedExtent())
|
|
.call(labels, graph, all, filter, dimensions, !difference && !extent);
|
|
|
|
if (points.points(context.intersects(map.extent()), 100).length >= 100) {
|
|
surface.select('.layer-hit').selectAll('g.point').remove();
|
|
} else {
|
|
surface.call(points, points.points(all), filter);
|
|
}
|
|
|
|
dispatch.drawn({full: true});
|
|
}
|
|
|
|
function editOff() {
|
|
var mode = context.mode();
|
|
surface.selectAll('.layer *').remove();
|
|
dispatch.drawn({full: true});
|
|
if (!(mode && mode.id === 'browse')) {
|
|
context.enter(iD.modes.Browse(context));
|
|
}
|
|
}
|
|
|
|
function zoomPan() {
|
|
if (d3.event && d3.event.sourceEvent.type === 'dblclick') {
|
|
if (!dblclickEnabled) {
|
|
zoom.scale(projection.scale() * 2 * Math.PI)
|
|
.translate(projection.translate());
|
|
return d3.event.sourceEvent.preventDefault();
|
|
}
|
|
}
|
|
|
|
if (Math.log(d3.event.scale / Math.LN2 - 8) < minzoom + 1) {
|
|
iD.ui.flash(context.container())
|
|
.select('.content')
|
|
.text(t('cannot_zoom'));
|
|
return setZoom(16, true);
|
|
}
|
|
|
|
projection
|
|
.translate(d3.event.translate)
|
|
.scale(d3.event.scale / (2 * Math.PI));
|
|
|
|
var scale = d3.event.scale / transformStart[0],
|
|
tX = Math.round((d3.event.translate[0] / scale - transformStart[1][0]) * scale),
|
|
tY = Math.round((d3.event.translate[1] / scale - transformStart[1][1]) * scale);
|
|
|
|
transformed = true;
|
|
iD.util.setTransform(supersurface, tX, tY, scale);
|
|
queueRedraw();
|
|
|
|
dispatch.move(map);
|
|
}
|
|
|
|
function resetTransform() {
|
|
if (!transformed) return false;
|
|
iD.util.setTransform(supersurface, 0, 0);
|
|
transformed = false;
|
|
return true;
|
|
}
|
|
|
|
function redraw(difference, extent) {
|
|
|
|
if (!surface) return;
|
|
|
|
clearTimeout(timeoutId);
|
|
|
|
// If we are in the middle of a zoom/pan, we can't do differenced redraws.
|
|
// It would result in artifacts where differenced entities are redrawn with
|
|
// one transform and unchanged entities with another.
|
|
if (resetTransform()) {
|
|
difference = extent = undefined;
|
|
}
|
|
|
|
var zoom = String(~~map.zoom());
|
|
if (surface.attr('data-zoom') !== zoom) {
|
|
surface.attr('data-zoom', zoom)
|
|
.classed('low-zoom', zoom <= 16);
|
|
}
|
|
|
|
if (!difference) {
|
|
supersurface.call(context.background());
|
|
}
|
|
|
|
if (map.editable()) {
|
|
context.connection().loadTiles(projection, dimensions);
|
|
drawVector(difference, extent);
|
|
} else {
|
|
editOff();
|
|
}
|
|
|
|
transformStart = [
|
|
projection.scale() * 2 * Math.PI,
|
|
projection.translate().slice()];
|
|
|
|
return map;
|
|
}
|
|
|
|
var timeoutId;
|
|
function queueRedraw() {
|
|
clearTimeout(timeoutId);
|
|
timeoutId = setTimeout(function() { redraw(); }, 300);
|
|
}
|
|
|
|
function pointLocation(p) {
|
|
var translate = projection.translate(),
|
|
scale = projection.scale() * 2 * Math.PI;
|
|
return [(p[0] - translate[0]) / scale, (p[1] - translate[1]) / scale];
|
|
}
|
|
|
|
function locationPoint(l) {
|
|
var translate = projection.translate(),
|
|
scale = projection.scale() * 2 * Math.PI;
|
|
return [l[0] * scale + translate[0], l[1] * scale + translate[1]];
|
|
}
|
|
|
|
map.mouse = function() {
|
|
var e = mousemove || d3.event, s;
|
|
while ((s = e.sourceEvent)) e = s;
|
|
return mouse(e);
|
|
};
|
|
|
|
map.mouseCoordinates = function() {
|
|
return projection.invert(map.mouse());
|
|
};
|
|
|
|
map.dblclickEnable = function(_) {
|
|
if (!arguments.length) return dblclickEnabled;
|
|
dblclickEnabled = _;
|
|
return map;
|
|
};
|
|
|
|
function setZoom(_, force) {
|
|
if (_ === map.zoom() && !force)
|
|
return false;
|
|
var scale = 256 * Math.pow(2, _),
|
|
center = pxCenter(),
|
|
l = pointLocation(center);
|
|
scale = Math.max(1024, Math.min(256 * Math.pow(2, 24), scale));
|
|
projection.scale(scale / (2 * Math.PI));
|
|
zoom.scale(scale);
|
|
var t = projection.translate();
|
|
l = locationPoint(l);
|
|
t[0] += center[0] - l[0];
|
|
t[1] += center[1] - l[1];
|
|
projection.translate(t);
|
|
zoom.translate(projection.translate());
|
|
return true;
|
|
}
|
|
|
|
function setCenter(_) {
|
|
var c = map.center();
|
|
if (_[0] === c[0] && _[1] === c[1])
|
|
return false;
|
|
var t = projection.translate(),
|
|
pxC = pxCenter(),
|
|
ll = projection(_);
|
|
projection.translate([
|
|
t[0] - ll[0] + pxC[0],
|
|
t[1] - ll[1] + pxC[1]]);
|
|
zoom.translate(projection.translate());
|
|
return true;
|
|
}
|
|
|
|
map.pan = function(d) {
|
|
var t = projection.translate();
|
|
t[0] += d[0];
|
|
t[1] += d[1];
|
|
projection.translate(t);
|
|
zoom.translate(projection.translate());
|
|
dispatch.move(map);
|
|
return redraw();
|
|
};
|
|
|
|
map.dimensions = function(_) {
|
|
if (!arguments.length) return dimensions;
|
|
var center = map.center();
|
|
dimensions = _;
|
|
surface.dimensions(dimensions);
|
|
context.background().dimensions(dimensions);
|
|
projection.clipExtent([[0, 0], dimensions]);
|
|
mouse = iD.util.fastMouse(supersurface.node());
|
|
setCenter(center);
|
|
return redraw();
|
|
};
|
|
|
|
map.zoomIn = function() { return map.zoom(Math.ceil(map.zoom() + 1)); };
|
|
map.zoomOut = function() { return map.zoom(Math.floor(map.zoom() - 1)); };
|
|
|
|
map.center = function(loc) {
|
|
if (!arguments.length) {
|
|
return projection.invert(pxCenter());
|
|
}
|
|
|
|
if (setCenter(loc)) {
|
|
dispatch.move(map);
|
|
}
|
|
|
|
return redraw();
|
|
};
|
|
|
|
map.zoom = function(z) {
|
|
if (!arguments.length) {
|
|
return Math.max(Math.log(projection.scale() * 2 * Math.PI) / Math.LN2 - 8, 0);
|
|
}
|
|
|
|
if (setZoom(z)) {
|
|
dispatch.move(map);
|
|
}
|
|
|
|
return redraw();
|
|
};
|
|
|
|
map.zoomTo = function(entity, zoomLimits) {
|
|
var extent = entity.extent(context.graph()),
|
|
zoom = map.extentZoom(extent);
|
|
zoomLimits = zoomLimits || [16, 20];
|
|
map.centerZoom(extent.center(), Math.min(Math.max(zoom, zoomLimits[0]), zoomLimits[1]));
|
|
};
|
|
|
|
map.centerZoom = function(loc, z) {
|
|
var centered = setCenter(loc),
|
|
zoomed = setZoom(z);
|
|
|
|
if (centered || zoomed) {
|
|
dispatch.move(map);
|
|
}
|
|
|
|
return redraw();
|
|
};
|
|
|
|
map.centerEase = function(loc) {
|
|
var from = map.center().slice(),
|
|
t = 0,
|
|
stop;
|
|
|
|
surface.one('mousedown.ease', function() {
|
|
stop = true;
|
|
});
|
|
|
|
d3.timer(function() {
|
|
if (stop) return true;
|
|
map.center(iD.geo.interp(from, loc, (t += 1) / 10));
|
|
return t === 10;
|
|
}, 20);
|
|
return map;
|
|
};
|
|
|
|
map.extent = function(_) {
|
|
if (!arguments.length) {
|
|
return new iD.geo.Extent(projection.invert([0, dimensions[1]]),
|
|
projection.invert([dimensions[0], 0]));
|
|
} else {
|
|
var extent = iD.geo.Extent(_);
|
|
map.centerZoom(extent.center(), map.extentZoom(extent));
|
|
}
|
|
};
|
|
|
|
map.trimmedExtent = function() {
|
|
var headerY = 60, footerY = 30, pad = 10;
|
|
return new iD.geo.Extent(projection.invert([pad, dimensions[1] - footerY - pad]),
|
|
projection.invert([dimensions[0] - pad, headerY + pad]));
|
|
};
|
|
|
|
map.extentZoom = function(_) {
|
|
var extent = iD.geo.Extent(_),
|
|
tl = projection([extent[0][0], extent[1][1]]),
|
|
br = projection([extent[1][0], extent[0][1]]);
|
|
|
|
// Calculate maximum zoom that fits extent
|
|
var hFactor = (br[0] - tl[0]) / dimensions[0],
|
|
vFactor = (br[1] - tl[1]) / dimensions[1],
|
|
hZoomDiff = Math.log(Math.abs(hFactor)) / Math.LN2,
|
|
vZoomDiff = Math.log(Math.abs(vFactor)) / Math.LN2,
|
|
newZoom = map.zoom() - Math.max(hZoomDiff, vZoomDiff);
|
|
|
|
return newZoom;
|
|
};
|
|
|
|
map.editable = function() {
|
|
return map.zoom() >= 16;
|
|
};
|
|
|
|
map.minzoom = function(_) {
|
|
if (!arguments.length) return minzoom;
|
|
minzoom = _;
|
|
return map;
|
|
};
|
|
|
|
map.enableSequences = function (enable) {
|
|
sequences.enable(enable);
|
|
};
|
|
|
|
return d3.rebind(map, dispatch, 'on');
|
|
};
|