我对d3js相对较新,并尝试使用地图创建我的四重奏音乐会时间表的可视化。我的第一次尝试在桌面Chrome浏览器和桌面Safari浏览器中运行良好。
在移动设备上的Android设备上,除美国外,地图会错误地渲染整个地球。
http://test.chiaraquartet.net/topo/index.html
对于我做错了什么/如果d3中有错误的任何见解将不胜感激。
以下是相关代码:
var center = [90, -38.7],
ratio = window.devicePixelRatio || 1,
graticule = d3.geo.graticule(),
width = 500,
height = 500,
degrees = 180 / Math.PI,
projection = d3.geo.orthographic()
.scale(height / 2 - 1)
.rotate(center)
.translate([width / 2, height / 2])
.clipAngle(90)
.precision(.1)
var graticule = d3.geo.graticule()()
// Round to integer pixels for speed, and set pixel ratio.
function roundRatioContext(context) {
return {
moveTo: function(x, y) { context.moveTo(Math.round(x * ratio), Math.round(y * ratio)); },
lineTo: function(x, y) { context.lineTo(Math.round(x * ratio), Math.round(y * ratio)); },
closePath: function() { context.closePath(); }
};
}
var canvas = d3.select("body").append("canvas")
.attr("width", width * ratio)
.attr("height", height * ratio)
.style("width", width + "px")
.style("height", height + "px")
var c = canvas.node().getContext("2d");
var path = d3.geo.path()
.projection(projection)
.context(roundRatioContext(c));
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append('g')
var textbox = d3.select("body").append("div")
.style('position', 'absolute')
.attr('class', 'popup')
.classed('hidden', true)
var sphere = svg.append("path")
.datum({type: "Sphere"})
.attr("id", "sphere")
.attr("d", path)
var runner = queue()
.defer(d3.json, 'world.json')
.defer(d3.xhr('/concertrpc.php')
.header('content-type', 'application/json')
.post, JSON.stringify({
params: [],
id: 1
}))
.await(function(error, world, info) {
if (error) return console.error(error);
var features = topojson.feature(world, world.objects.states)
var countries = topojson.feature(world, world.objects.countries)
console.log(world)
var concerts = JSON.parse(info.responseText)
if (concerts.error) {
console.log(concerts.error)
return
}
concerts = concerts.result.concerts
console.log(concerts)
var globe = {type: "Sphere"},
graticule = d3.geo.graticule()(),
countries = topojson.feature(world, world.objects.countries),
states = topojson.feature(world, world.objects.states),
country_borders = topojson.mesh(world, world.objects.countries, function(a, b) { return a !== b }),
state_borders = topojson.mesh(world, world.objects.states, function(a, b) { return a.id !== b.id }),
temp_context
temp_context = path.context()
path.context(null)
svg.selectAll('.concert')
.data(concerts, function(d) { return d.properties.id })
.enter().append("path")
.attr('class', 'concert')
.attr('d', path)
.on('mouseover', concertMouseover)
.on('mouseout', function(d) {
textbox.classed('hidden', true)
})
path.context(temp_context)
d3.select('body').append('div').append('button')
.attr('type', 'button')
.text('This season')
.on('click', function() {
getConcertData('This season')
})
var zoom = d3.geo.zoom()
.projection(projection)
.duration(function(S) { return 2000 * Math.sqrt(S); }) // assume ease="quad-in-out"
.scaleExtent([height / 2 - 1, Infinity])
.on("zoom", function() {
projection.clipAngle(Math.asin(Math.min(1, .5 * Math.sqrt(width * width + height * height) / projection.scale())) * degrees);
c.clearRect(0, 0, width * ratio, height * ratio);
c.strokeStyle = "#999", c.lineWidth = .25 * ratio, c.beginPath(), path(graticule), c.stroke();
c.fillStyle = "#69d2e7", c.beginPath(), path(countries), c.fill();
c.fillStyle = "#00f", c.beginPath(), path(states), c.fill();
c.strokeStyle = "#fff", c.lineWidth = .5 * ratio, c.beginPath(), path(country_borders), c.stroke();
c.strokeStyle = "#fff", c.lineWidth = .5 * ratio, c.beginPath(), path(state_borders), c.stroke();
c.strokeStyle = "#000", c.lineWidth = .5 * ratio, c.beginPath(), path(globe), c.stroke();
temp_context = path.context()
path.context(null)
svg.selectAll("path").attr("d",path);
path.context(temp_context)
})
//.on("zoomend", transition);
canvas
.call(zoom)
.call(zoom.event);
sphere
.call(zoom)
function transition() {
zoomBounds(projection, states.features[30]);
canvas.transition()
.ease("quad-in-out")
.duration(2000) // see https://github.com/mbostock/d3/pull/2045
.call(zoom.projection(projection).event);
}
function zoomBounds(projection, o) {
var centroid = d3.geo.centroid(o),
clip = projection.clipExtent();
projection
.rotate([-centroid[0], -centroid[1]])
.clipExtent(null)
.scale(1)
.translate([0, 0]);
var b = path.bounds(o),
k = Math.min(1000, .45 / Math.max(Math.max(Math.abs(b[1][0]), Math.abs(b[0][0])) / width, Math.max(Math.abs(b[1][1]), Math.abs(b[0][1])) / height));
projection
.clipExtent(clip)
.scale(k)
.translate([width / 2, height / 2]);
}
})
function concertMouseover(d) {
var loc = projection(d3.select(this).datum().geometry.coordinates)
textbox.style('top', loc[1] + "px")
textbox.style('left', loc[0] + 15 + "px")
textbox.text(d.properties.title)
textbox.classed('hidden', false)
}
function getConcertData(request) {
d3.xhr('/concertrpc.php')
.header('content-type', 'application/json')
.post(JSON.stringify({
params: [request],
id: 1
}), function(error, info) {
var concerts = JSON.parse(info.responseText)
if (concerts.error) {
console.log(concerts.error)
return
}
var c = svg.selectAll('.concert')
.data(concerts.result.concerts, function(d) { return d.properties.id })
c.transition()
.style('opacity', '1')
c.enter()
.append('path')
.attr('class', 'concert')
.attr('d', path)
.on('mouseover', concertMouseover)
.on('mouseout', function(d) {
textbox.classed('hidden', true)
})
c.exit().transition()
.duration(1000)
.style('opacity', '0')
.remove()
})
}
答案 0 :(得分:1)
我不确定导致问题的原因,但罪魁祸首是我试图将世界各国的地图与美国各州的地图结合起来生成的topojson文件。我找到了一个不同的世界地图,现在地图在手机和桌面上都以相同的方式显示。