спасибо заранее за проверку этого вопроса.Я создал карту хороплета D3, и у меня возникают проблемы при попытке выяснить, почему всплывающая подсказка имеет некоторые проблемы в отношении того, где карта находится в браузере (например, прокрутка вверх и вниз по странице и перемещение карты вверх / вниз),Для начала вот код, с которым я работаю, "choropleth.tag":
<%@ include file="/WEB-INF/jsp/site/taglib.jsp"%>
<%@ attribute name="baseDataUrl" required="true" %>
<%@ attribute name="domain" required="true" %>
<%@ attribute name="id" required="true" %>
<%@ attribute name="dataInputLabel" required="false" %>
<div class="container">
<div class="row">
<div class="chropleth-map">
<svg id="${id}-d3-choroplethmap" viewBox="-120 -150 1200 700" class="d3-map-animation" preserveAspectRatio="xMidYMid meet"></svg>
<!--<svg id="${id}-svgkey" viewBox="650 -25 150 50" class="fade-in-slow-2 svgkey"></svg>-->
</div>
<div class="col-xs-6 tooltip" style="opacity: 0;"></div>
</div>
</div>
<script src="<c:url value="/js/libs/d3v4/d3.v4.min.js"/>"></script>
<script src="<c:url value="/js/libs/d3v4/d3-scale-chromatic.v1.min.js"/>"></script>
<script src="<c:url value="/js/libs/d3v4/topojson.v2.min.js"/>"></script>
<script src="https://d3js.org/d3-axis.v1.min.js"></script>
<script type="text/javascript">
var panZoomMaps;
var drawMapFunctions;
panZoomMaps = ( typeof panZoomMaps !== 'undefined' && panZoomMaps instanceof Array ) ? panZoomMaps : [];
drawMapFunctions = ( typeof drawMapFunctions !== 'undefined' && drawMapFunctions instanceof Array ) ? drawMapFunctions : [];
$.EventBus("currentOrganizationChange").subscribe(function(){
/*panZoomMaps["${id}"].destroy();*/
$("#${id}-d3-choroplethmap").empty();
drawMapFunctions["${id}"]();
});
drawMapFunctions["${id}"] = function (){
var svgMap = d3.select("#${id}-d3-choroplethmap");
width = +svgMap
.attr("width");
height = +svgMap
.attr("height");
var cbsaMap = d3.map();
var color = d3.scaleLinear().domain(${domain}).range(d3.schemeBlues[${domain}.length])
var orgId = sessionStorage.getItem("currentOrganizationId");
if (!orgId){
orgId = -1;
}
d3.queue()
.defer(d3.json, "${contextRoot}/2013_us.topojson.json")
.defer(d3.json, "${baseDataUrl}/"+orgId)
.await(ready);
function ready(error, cbsa, d) {
var width = 960,
height = 500,
centered;
var projection = d3.geoAlbersUsa()
.scale(1070)
.translate([width / 2, height / 2]);
var path = d3.geoPath().projection(projection);
var svg = d3.select("#${id}-d3-choroplethmap");
width = +svg
.attr("width");
height = +svg
.attr("height");
svg.append("rect")
.attr("class", "d3MapBackground")
.attr("width", width)
.attr("height", height)
.on("click", clicked);
var g = svg.append("g");
d3.json("${contextRoot}/2013_us.topojson.json", function(error, us) {
if (error) throw error;
});
function clicked(d) {
var x, y, k;
if (d && centered !== d) {
var centroid = path.centroid(d);
x = centroid[0];
y = centroid[1];
k = 4;
centered = d;
$('#btn').click(function(){
var btn = $(this);
$.post(/*...*/).complete(function(){
btn.prop('disabled', false);
});
btn.prop('disabled', true);
});
$("#dialogBox, #mobileDialogBox").css("display", "block").css("visibility", "visible").css("height", "104");
} else {
x = width / 2;
y = height / 2;
k = 1;
centered = null;
$("#dialogBoxCloseButton, #mobileDialogBoxCloseButton").click();
$("#dialogBox, #mobileDialogBox").css("display", "table-column").css("visibility", "hidden").css("height", "0");
}
d3.select("#${id}-d3MapCbsa").selectAll("path")
.classed("active", centered && function(d) { return d === centered; });
d3.select("#${id}-d3MapState").transition()
.duration(750)
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")scale(" + k + ")translate(" + -x + "," + -y + ")")
.attr("transform-origin", "-160px -60px 10px")
.style("stroke-width", 1.5 / k + "px");
d3.select("#${id}-d3MapCbsa").transition()
.duration(750)
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")scale(" + k + ")translate(" + -x + "," + -y + ")")
.attr("transform-origin", "-160px -60px 10px")
.style("stroke-width", 1.5 / k + "px");
d3.select("#${id}-d3MapStateBorder").transition()
.duration(750)
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")scale(" + k + ")translate(" + -x + "," + -y + ")")
.attr("transform-origin", "-160px -60px 10px")
.style("stroke-width", 1.5 / k + "px");
}
var tooltip = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var us = cbsa;
var svgMap = d3.select("#${id}-d3-choroplethmap");
var mouseDownTime=new Date().getTime();
var prevMouseUp=new Date().getTime();
var clicks=0;
var timeout;
var path = d3.geoPath().projection(projection);
var stateAndMicroColor= "#cccccc";
if (error)
throw error;
for (var i=0; i<d.length; i++){
cbsaMap.set(d[i].cbsaId, +d[i].num);
}
svgMap.append("g")
.attr("class", "state")
.attr("id", "${id}-d3MapState")
.selectAll("path").data(topojson.feature(us, us.objects.states).features)
.enter()
.append("path")
.attr("fill", function(){
return stateAndMicroColor;
})
.attr("d", path)
.attr("pointer-events", "none")
.on("click", clicked);
svgMap.append("g")
.attr("class", "cbsa")
.attr("id", "${id}-d3MapCbsa")
.selectAll("path")
.data(topojson.feature(us, us.objects.cbsas).features)
.enter().append("path")
.attr("fill", function(d){
if(cbsaMap.has(d.properties.id)){
return color(cbsaMap.get(d.properties.id));
}
return stateAndMicroColor;
})
.attr("stroke", function(){
return "#ffffff";
})
.attr("stroke-width", 0.5)
.attr("d", path)
.on("click", clicked)
.on("mouseover", function(d) {
var data = cbsaMap.get(d.properties.id)
tooltip.transition()
.duration(200)
.style("opacity", .9);
tooltip.html("${dataInputLabel}: "+ data)
.style("left", (d3.event.pageX + 20) + "px")
.style("top", (d3.event.pageY - 45) + "px");
})
.on("mouseout", function(d) {
tooltip.transition()
.duration(500)
.style("opacity", 0);
})
.on("mousedown", function(){
mouseDownTime=new Date().getTime();
clearTimeout(timeout);
})
.on("mouseup", function(d) {
clicks++;
if (clicks === 1){
var x = d3.event.pageX - document.getElementById("${id}-d3-choroplethmap").getBoundingClientRect().x + 700;
var y = d3.event.pageY - document.getElementById("${id}-d3-choroplethmap").getBoundingClientRect().y + 380;
timeout = setTimeout(function () {
if(new Date().getTime() - mouseDownTime < 250 && cbsaMap.has(d.properties.id)){
$('#dialogText, #mobileDialogText').text("Header");
$('#dialogText, #mobileDialogText').html("The ID of this Core Based Statistical Area (CBSA) is <b>" + d.properties.id + "</b>.<br/> There are a total of <b>" + cbsaMap.get(d.properties.id) + "</b> ${dataInputLabel}. ");
/* NOTE: The following function works on smaller devices and viewports with the help of the "#dialogBox" media query. The dialog box is stuck to the bottom of the map and is updated on CBSA clicking. Space is made or reduced to fit the dialog box. */
/* $('#dialogBox').show().draggable(); */
/* NOTE: The following jQuery funtion works on desktop screensizes and not on mobile or tablet. How can the .offset({}) be adjusted for different screensizes like CSS media queries? */
$('#dialogBox, #mobileDialogBox').show().offset({top: y,left: x}).draggable();
$('#dialogBoxCloseButton, #mobileDialogBoxCloseButton').click(function() {
$('#dialogBox, #mobileDialogBox').hide();
});
}
clicks=0;
}, 100);
} else if (clicks === 2) {
clearTimeout(timeout);
$("#dialogBoxCloseButton, #mobileDialogBoxCloseButton").click();
clicks = 0;
}
prevMouseUp=new Date().getTime();
})
;
svgMap.append("g")
.attr("class", "stateBorder")
.attr("id", "${id}-d3MapStateBorder")
.selectAll("path").data(topojson.feature(us, us.objects.states).features)
.enter().append("path")
.attr("fill", function(){
return "transparent";
})
.attr("stroke", "#fff")
.attr("stroke-width", 0.8)
.attr("d", path)
.attr("pointer-events", "none")
.on("click", clicked);
}
}
drawMapFunctions["${id}"]();
/* Closing of the D3 map dialog box upon clicking each of the four CTA's. */
$('#cardholdersCTA, #transactionsCTA, #ordersCTA, #pointsCTA' ).click(function(){
$("#dialogBoxCloseButton, #mobileDialogBoxCloseButton").click();
});
</script>
Итак, для начала при начальной загрузке страницы создается карта, и если вы наводите указатель мыши на любую CBSA / географическую область в Соединенных Штатах, подсказка DIV будет правильно сгенерирована и расположенарядом с курсором мыши.Проблема начинается, когда пользователь прокручивает страницу вниз.В этот момент, если пользователь наводит курсор на одну и ту же область карты.всплывающая подсказка находится в той же области в окне обозревателя, а на карте нет регистратора.Это похоже на то, что всплывающая подсказка размещается не на основе курсора мыши, а на основе размеров окна баузера.Я считаю, что проблема заключается в коде:
.style("left", (d3.event.pageX + 20) + "px")
.style("top", (d3.event.pageY - 45) + "px");
Вся карта полностью отзывчива, за исключением этой проблемы.Вот несколько скриншотов курсора, наведенного на область CBSA около Денвера, штат Колорадо, и прокручивающего страницу вниз:
Начальная загрузка страницы и представление карты;парящий над Денвером, штат Колорадо:
Номер зависания и прокрутки1
Я прокручиваю страницу вниз и снова зависаю над Денвером, штат Колорадо;всплывающая подсказка находится в том же месте в браузере, но должна располагаться рядом с тем местом, где находится мышь, Денвер, Колорадо:
Наведение и прокрутка №.2
Я прокручиваю дальше и снова зависаю над Денвером, штат Колорадо:
Наведение и прокрутка №.3
... и еще один скриншот прокрутки вниз страницы, а затем повторного наведения над Денвером.
Наведение и прокрутка №.4
Таким образом, похоже, что всплывающая подсказка размещается на основе размеров браузера, а не карты.Чего мне не хватает?Как я могу это исправить?Какие-либо предложения?Большое спасибо за вашу помощь и понимание.Я очень ценю это.
ОБНОВЛЕНИЕ: Вот что я изменил для функции наведения мыши:
var scrollNumber = window.pageYOffset;
var data = cbsaMap.get(d.properties.id)
tooltip.transition()
.duration(200)
.style("opacity", .9);
tooltip.html("${dataInputLabel}: "+ data)
.style("left", (d3.event.pageX + 20) + "px")
.style("top", (d3.event.pageY - scrollNumber - 45) + "px");