纬度、经度和 SVG

问题描述 投票:0回答:1

我正在尝试使用 SVG 来表示机场及其空域。我已经三次检查了坐标,但 y 轴及其转换方式看起来仍然有问题。当您加载下面的代码时,代表跑道 09L / 27R 的行应高于 09R / 27L,并且 LON 应高于两条线。使用 svg 是否有一些魔术可以做到这一点,或者我的逻辑是错误的?

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Radar Screen</title>
  <style>
    body {
      margin: 0;
      padding: 0;
      overflow: hidden; /* Prevent scrolling */
    }

    #radar-container {
      position: fixed;
      top: 0;
      left: 0;
      width: 100vw;
      height: 100vh;
    }

    svg {
      width: 100%; /* Take full width of container */
      height: 100%; /* Take full height of container */
      border: 1px solid black;
    }
  </style>
</head>
<body>
  <div id="radar-container">
    <svg id="radar-svg">
      <!-- Runways, waypoints, and airport will be dynamically drawn here -->
    </svg>
  </div>
  <script>
    // Function to convert latitude and longitude to screen coordinates
    function convertCoordinates(latitude, longitude) {
        // Airport coordinates
        const airportLatitude = 51.4775; // Decimal degrees
        const airportLongitude = -0.46139; // Decimal degrees

        // Calculate center of SVG based on airport coordinates
        const centerX = window.innerWidth / 2;
        const centerY = window.innerHeight / 2;

        // Assume some mapping between latitude and y-axis, and longitude and x-axis
        // You may need to adjust these calculations based on your specific mapping
        const scaleFactor = 2000; // Adjust based on the scale of your radar screen
        const offsetX = centerX - (airportLongitude * scaleFactor);
        const offsetY = centerY - (airportLatitude * scaleFactor);
        const screenX = (longitude * scaleFactor) + offsetX;
        const screenY = (latitude * scaleFactor) + offsetY;
        return { x: screenX, y: screenY };
    }

    // Waypoint coordinates
    const waypointCoordinates = [
      { name: "LON", latitude: 51.4861, longitude: -0.4666 },
    ];

    // Runway coordinates
    const runwayCoordinates = [
      { id: "27R", start: { latitude: 51.4776, longitude: -0.4332 }, end: { latitude: 51.4775, longitude: -0.4849 }},
      { id: "09L", start: { latitude: 51.4775, longitude: -0.4849 }, end: { latitude: 51.4776, longitude: -0.4332 }},
      { id: "09R", start: { latitude: 51.4647, longitude: -0.4823 }, end: { latitude: 51.4655, longitude: -0.4341 }},
      { id: "27L", start: { latitude: 51.4655, longitude: -0.4341 }, end: { latitude: 51.4647, longitude: -0.4823 }}
    ];

    // Get the SVG container
    const svgContainer = document.getElementById('radar-svg');

    // Function to draw waypoints
    function drawWaypoints() {
      // Draw new waypoints
      waypointCoordinates.forEach(waypoint => {
        const position = convertCoordinates(waypoint.latitude, waypoint.longitude);

        console.log(`Waypoint ${waypoint.name} position: (${position.x}, ${position.y})`);

        // Draw square representing waypoint
        const square = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
        square.setAttribute('x', position.x - 5); // Adjust position to center square
        square.setAttribute('y', position.y - 5); // Adjust position to center square
        square.setAttribute('width', 10);
        square.setAttribute('height', 10);
        square.setAttribute('fill', 'blue');
        svgContainer.appendChild(square);

        // Add label for the waypoint
        const label = document.createElementNS('http://www.w3.org/2000/svg', 'text');
        label.setAttribute('x', position.x + 10); // Offset label position
        label.setAttribute('y', position.y - 10); // Offset label position
        label.setAttribute('text-anchor', 'start'); // Align text to start of label
        label.setAttribute('dominant-baseline', 'middle'); // Center the text vertically
        label.setAttribute('font-family', 'Arial');
        label.setAttribute('font-size', '12');
        label.setAttribute('fill', 'black');
        label.textContent = waypoint.name;
        svgContainer.appendChild(label);
      });
    }

    // Function to draw runways
    function drawRunways() {
      // Draw new runways
      runwayCoordinates.forEach(runway => {
        const start = convertCoordinates(runway.start.latitude, runway.start.longitude);
        const end = convertCoordinates(runway.end.latitude, runway.end.longitude);

        console.log(`Runway ${runway.id} start: (${start.x}, ${start.y})`);
        console.log(`Runway ${runway.id} end: (${end.x}, ${end.y})`);

        const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
        line.setAttribute('x1', start.x);
        line.setAttribute('y1', start.y);
        line.setAttribute('x2', end.x);
        line.setAttribute('y2', end.y);
        line.setAttribute('stroke', 'black');
        line.setAttribute('stroke-width', '2');
        svgContainer.appendChild(line);
        // Add label
        const label = document.createElementNS('http://www.w3.org/2000/svg', 'text');
        label.setAttribute('x', start.x + 10); // Offset label position
        label.setAttribute('y', start.y - 10); // Offset label position
        label.setAttribute('text-anchor', 'start'); // Align text to start of label
        label.setAttribute('dominant-baseline', 'middle'); // Center the text vertically
        label.setAttribute('font-family', 'Arial');
        label.setAttribute('font-size', '12');
        label.setAttribute('fill', 'black');
        label.textContent = runway.id;
        svgContainer.appendChild(label);
      });
    }

    // Draw waypoints and runways initially
    drawWaypoints();
    drawRunways();
  </script>
</body>
</html>

我尝试通过以下方式反转 Y 轴:

const screenY = -(latitude * scaleFactor) + offsetY;

我也检查了三倍坐标。

javascript html css svg coordinates
1个回答
0
投票

我向您的

waypointCoordinates
对象添加了四个新点,即:北、东、南和西。

通过此更改,您可以清楚地看到 NORTH 位置低于 LON,SOUTH 高于 LON。

一种解决方案确实是将返回的对象从

convertCoordinates()
更改为
return { x: screenX, y: window.innerHeight - screenY };
正如 Jaromanda 在您问题的评论中提到的。

这里的问题是,对于经度和纬度,纬度原点位于赤道(即

0
),并且随着我们向北移动而增加。然而,SVG 的原点是左上角,并随着向下移动而增加。为此,我们需要对上面返回的对象中的
screenY
加上负号,并通过添加
window.innerHeight
来调整垂直屏幕位置。

为了更容易看到,我在左上角添加了一个翻转复选框,该复选框位于容器上方,这要归功于将

z-index: -1
添加到
radar-container
div

const flipCheckbox = document.getElementById("flipCheckbox");

flipCheckbox.addEventListener("click", () => {
  while (svgContainer.lastChild) {
    svgContainer.removeChild(svgContainer.lastChild);
  }
  drawWaypoints();
  drawRunways();
});

// Function to convert latitude and longitude to screen coordinates
function convertCoordinates(latitude, longitude) {
  // Airport coordinates
  const airportLatitude = 51.4775; // Decimal degrees
  const airportLongitude = -0.46139; // Decimal degrees

  // Calculate center of SVG based on airport coordinates
  const centerX = window.innerWidth / 2;
  const centerY = window.innerHeight / 2;

  // Assume some mapping between latitude and y-axis, and longitude and x-axis
  // You may need to adjust these calculations based on your specific mapping
  const scaleFactor = 2000; // Adjust based on the scale of your radar screen
  const offsetX = centerX - (airportLongitude * scaleFactor);
  const offsetY = centerY - (airportLatitude * scaleFactor);
  const screenX = (longitude * scaleFactor) + offsetX;
  const screenY = (latitude * scaleFactor) + offsetY;
  return flipCheckbox.checked ? {
    x: screenX,
    y: window.innerHeight - screenY
  } : {
    x: screenX,
    y: screenY
  };
}

// Waypoint coordinates
const waypointCoordinates = [{
    name: "LON",
    latitude: 51.4861,
    longitude: -0.4666
  },
  {
    name: "EAST",
    latitude: 51.4861,
    longitude: -0.3375
  },
  {
    name: "NORTH",
    latitude: 51.5133,
    longitude: -0.4666
  },
  {
    name: "SOUTH",
    latitude: 51.4123,
    longitude: -0.4666
  },
  {
    name: "WEST",
    latitude: 51.4861,
    longitude: -0.5479
  }
];

// Runway coordinates
const runwayCoordinates = [{
    id: "27R",
    start: {
      latitude: 51.4776,
      longitude: -0.4332
    },
    end: {
      latitude: 51.4775,
      longitude: -0.4849
    }
  },
  {
    id: "09L",
    start: {
      latitude: 51.4775,
      longitude: -0.4849
    },
    end: {
      latitude: 51.4776,
      longitude: -0.4332
    }
  },
  {
    id: "09R",
    start: {
      latitude: 51.4647,
      longitude: -0.4823
    },
    end: {
      latitude: 51.4655,
      longitude: -0.4341
    }
  },
  {
    id: "27L",
    start: {
      latitude: 51.4655,
      longitude: -0.4341
    },
    end: {
      latitude: 51.4647,
      longitude: -0.4823
    }
  }
];

// Get the SVG container
const svgContainer = document.getElementById('radar-svg');

// Function to draw waypoints
function drawWaypoints() {
  // Draw new waypoints
  waypointCoordinates.forEach(waypoint => {
    const position = convertCoordinates(waypoint.latitude, waypoint.longitude);

    console.log(`Waypoint ${waypoint.name} position: (${position.x}, ${position.y})`);

    // Draw square representing waypoint
    const square = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
    square.setAttribute('x', position.x - 5); // Adjust position to center square
    square.setAttribute('y', position.y - 5); // Adjust position to center square
    square.setAttribute('width', 10);
    square.setAttribute('height', 10);
    square.setAttribute('fill', 'blue');
    svgContainer.appendChild(square);

    // Add label for the waypoint
    const label = document.createElementNS('http://www.w3.org/2000/svg', 'text');
    label.setAttribute('x', position.x + 10); // Offset label position
    label.setAttribute('y', position.y - 10); // Offset label position
    label.setAttribute('text-anchor', 'start'); // Align text to start of label
    label.setAttribute('dominant-baseline', 'middle'); // Center the text vertically
    label.setAttribute('font-family', 'Arial');
    label.setAttribute('font-size', '12');
    label.setAttribute('fill', 'black');
    label.textContent = waypoint.name;
    svgContainer.appendChild(label);
  });
}

// Function to draw runways
function drawRunways() {
  // Draw new runways
  runwayCoordinates.forEach(runway => {
    const start = convertCoordinates(runway.start.latitude, runway.start.longitude);
    const end = convertCoordinates(runway.end.latitude, runway.end.longitude);

    console.log(`Runway ${runway.id} start: (${start.x}, ${start.y})`);
    console.log(`Runway ${runway.id} end: (${end.x}, ${end.y})`);

    const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
    line.setAttribute('x1', start.x);
    line.setAttribute('y1', start.y);
    line.setAttribute('x2', end.x);
    line.setAttribute('y2', end.y);
    line.setAttribute('stroke', 'black');
    line.setAttribute('stroke-width', '2');
    svgContainer.appendChild(line);
    // Add label
    const label = document.createElementNS('http://www.w3.org/2000/svg', 'text');
    label.setAttribute('x', start.x + 10); // Offset label position
    label.setAttribute('y', start.y - 10); // Offset label position
    label.setAttribute('text-anchor', 'start'); // Align text to start of label
    label.setAttribute('dominant-baseline', 'middle'); // Center the text vertically
    label.setAttribute('font-family', 'Arial');
    label.setAttribute('font-size', '12');
    label.setAttribute('fill', 'black');
    label.textContent = runway.id;
    svgContainer.appendChild(label);
  });
}

// Draw waypoints and runways initially
drawWaypoints();
drawRunways();
body {
  margin: 0;
  padding: 0;
  overflow: hidden;
  /* Prevent scrolling */
}

#radar-container {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  z-index: -1;
}

svg {
  width: 100%;
  /* Take full width of container */
  height: 100%;
  /* Take full height of container */
  border: 1px solid black;
}
Flip Coordinates: <input type="checkbox" id="flipCheckbox">
<div id="radar-container">
  <svg id="radar-svg">
      <!-- Runways, waypoints, and airport will be dynamically drawn here -->
  </svg>
</div>

© www.soinside.com 2019 - 2024. All rights reserved.