You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在QtWebEngineView谷歌地图应用中计算并显示真实FPS

问题描述

我用QtWebEngineView开发了一个项目,通过加载谷歌地图展示从CSV文件读取的车辆位置。项目逻辑为每16ms读取一组经纬度数据并更新地图上的车辆标记,预期达到60FPS,但无法确认实际帧率是否符合预期。此前尝试通过统计getLocation()函数的调用次数计算FPS,但该方式不准确——真实FPS取决于地图的渲染操作(如拖拽窗口、缩放地图时的渲染),而非数据更新频率。需要解决正确计算并显示真实FPS的问题。

现有代码

MyMap.qml

Window {
    id: myMap
    title: "Google Map"
    width: 1600
    height: 900

    QtObject{
        id: backendId
        WebChannel.id: "backend"
    }

    WebChannel {
        id: myWebChannel
        registeredObjects: backendId
    }

    WebEngineView {
        id: webview
        anchors.fill: parent
        webChannel: myWebChannel
        settings.javascriptEnabled: true
        url: "html/index.html"

        settings {
            autoLoadImages: true
            dnsPrefetchEnabled: false
            accelerated2dCanvasEnabled: true
            javascriptEnabled: true
            webGLEnabled:true
            pdfViewerEnabled: false
        }
    }
}

index.html

<!DOCTYPE html>
<html>

<head>
    <title>Google Maps Example</title>
    <link rel="stylesheet" type="text/css" href="style.css">
    <script src="qwebchannel.js"></script>
</head>
<body>
    <div id="map-container">
        <div id="map"></div>
            <div class="velocity">
                    <p id="Fps">0 </p>
            </div>
    </div>

    <br>
        <script async
            src="https://maps.googleapis.com/maps/api/js?v=3.54&key=apiKey&language=ja&callback=initMap">
        </script>
        <script src="index.js"></script>
    <br>
</body>
</html>

index.js

// Define
let TILT = 55;
let HEADING = 0;
let ZOOM = 18;

// Variable
let map;
let directionsRenderer;
let directionsService;

let backend;
let rawMarker;
let icon;

//calculate fps
let m_fps;
let prevTime;
let curTime;
let isFirstCount;

// Function
function initMap() {
    var webChannel = new QWebChannel(qt.webChannelTransport, function(channel){
        backend = channel.objects.backend;
    });

    map = new google.maps.Map(document.getElementById("map"), mapOptions);

    directionsRenderer = new google.maps.DirectionsRenderer();
    directionsRenderer.setMap(map);
    directionsService = new google.maps.DirectionsService();

    geocoder = new google.maps.Geocoder();

    rawMarker = new google.maps.Marker({
       position: { lat: 21.007571859312662, lng: 105.79382411840304 },
       map: map,
       draggable: false,
       title: "Raw Marker",
       icon: {
           url: 'http://maps.google.com/mapfiles/ms/icons/green-dot.png',
           scaledSize: new google.maps.Size(40, 40) 
       }
   });

    fps_disp = document.getElementById("Fps");

    //fps
    m_fps = 0;
    prevTime = 0;
    curTime = 0;
    isFirstCount = true;
}

function getLocation(lat0, lon0) {
    var rawLocation = new google.maps.LatLng(lat0, lon0);

    myMarker.setPosition(rawLocation);
    map.setCenter(rawLocation);
    calFps();
}


function calFps() {
    window.requestAnimationFrame(() => {
        curTime = performance.now();
        if(isFirstCount) {
            isFirstCount = false;
            prevTime = curTime;
        }

        if(curTime-prevTime>= 1000) {
            dispFps(m_fps)
            m_fps = 0;
            prevTime = curTime;
        } else {
            m_fps++;
        }
      });
}

function dispFps(m_fps){
    fps_disp.innerHTML = "<b>FPS:</b> " + m_fps;
}
解决方案

核心思路:用requestAnimationFrame的回调次数统计真实渲染帧率——这个API会在浏览器每次准备绘制新帧时触发,完全同步于渲染周期,能准确反映地图的实际渲染FPS,覆盖数据更新、拖拽、缩放等所有触发渲染的场景。

修改步骤:

  1. 移除getLocation()中的calFps()调用,避免数据更新频率干扰渲染帧率统计。
  2. 重构FPS统计逻辑,启动持续的requestAnimationFrame循环,独立统计渲染帧数量。
  3. 修复原代码中myMarker未定义、mapOptions缺失的问题,确保代码可正常运行。

修改后的index.js代码:

// Define
let TILT = 55;
let HEADING = 0;
let ZOOM = 18;

// Variable
let map;
let directionsRenderer;
let directionsService;

let backend;
let rawMarker;
let icon;

// FPS统计变量
let fpsCount = 0;
let lastTimestamp = 0;
let fpsDisplay = null;

// Function
function initMap() {
    var webChannel = new QWebChannel(qt.webChannelTransport, function(channel){
        backend = channel.objects.backend;
    });

    // 补充缺失的地图配置
    const mapOptions = {
        center: { lat: 21.007571859312662, lng: 105.79382411840304 },
        zoom: ZOOM,
        tilt: TILT,
        heading: HEADING
    };

    map = new google.maps.Map(document.getElementById("map"), mapOptions);

    directionsRenderer = new google.maps.DirectionsRenderer();
    directionsRenderer.setMap(map);
    directionsService = new google.maps.DirectionsService();

    geocoder = new google.maps.Geocoder();

    rawMarker = new google.maps.Marker({
       position: { lat: 21.007571859312662, lng: 105.79382411840304 },
       map: map,
       draggable: false,
       title: "Raw Marker",
       icon: {
           url: 'http://maps.google.com/mapfiles/ms/icons/green-dot.png',
           scaledSize: new google.maps.Size(40, 40) 
       }
   });

    fpsDisplay = document.getElementById("Fps");
    // 启动FPS统计循环
    requestAnimationFrame(updateFps);
}

function getLocation(lat0, lon0) {
    var rawLocation = new google.maps.LatLng(lat0, lon0);
    // 修正原代码中myMarker未定义的问题
    rawMarker.setPosition(rawLocation);
    map.setCenter(rawLocation);
}

// 持续统计FPS的函数
function updateFps(timestamp) {
    if (!lastTimestamp) {
        lastTimestamp = timestamp;
    }

    fpsCount++;
    const elapsed = timestamp - lastTimestamp;

    // 每1秒计算并展示一次FPS
    if (elapsed >= 1000) {
        const fps = Math.round(fpsCount / (elapsed / 1000));
        fpsDisplay.innerHTML = `<b>FPS:</b> ${fps}`;
        fpsCount = 0;
        lastTimestamp = timestamp;
    }

    // 持续循环,同步渲染周期
    requestAnimationFrame(updateFps);
}

关键说明:

  • requestAnimationFrame(updateFps)会持续触发,每次触发对应浏览器的一次渲染帧,计数该回调的次数即为真实渲染帧率。
  • 使用浏览器提供的timestamp参数计算时间差,比performance.now()更贴合渲染周期的时间基准。
  • 修复了原代码中的两处错误,确保项目可正常运行。

内容的提问来源于stack exchange,提问作者Huy Nguyễn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 07:05:00