提交 1ae08d8b 编写于 作者: V vlin17 提交者: Jiangtao Hu

Dreamview: consolidate navigation/standard mode

上级 31ea7358
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<title>Apollo Navigator </title>
<style type="text/css">
html{height:100%}
body{height:100%;margin:0px;padding:0px}
</style>
<script type="text/javascript" src="https://maps.google.com/maps/api/js?key=AIzaSyArRypN9OdShkutQzOcbxC4cwrIHU1xi3Y"></script>
<script type="text/javascript" src="http://api.map.baidu.com/api?v=3.0&ak=0kKZnWWhXEPfzIkklmzAa3dZ"></script>
</head>
<body style="margin:0px; padding:0px;">
<div id="map_canvas" style="width: 100%; height: 100%;"></div>
<script type="text/javascript" src="/navigation.bundle.js"></script>
</body>
</html>
\ No newline at end of file
......@@ -4,6 +4,8 @@
<meta charset="UTF-8">
<title>Dreamview</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script type="text/javascript" src="https://maps.google.com/maps/api/js?key=AIzaSyArRypN9OdShkutQzOcbxC4cwrIHU1xi3Y"></script>
<script type="text/javascript" src="http://api.map.baidu.com/api?v=3.0&ak=0kKZnWWhXEPfzIkklmzAa3dZ"></script>
<link rel="apple-touch-icon" sizes="57x57" href="/icons-35549e149c746afd95464c71b413b5e9/apple-touch-icon-57x57.png"><link rel="apple-touch-icon" sizes="60x60" href="/icons-35549e149c746afd95464c71b413b5e9/apple-touch-icon-60x60.png"><link rel="apple-touch-icon" sizes="72x72" href="/icons-35549e149c746afd95464c71b413b5e9/apple-touch-icon-72x72.png"><link rel="apple-touch-icon" sizes="76x76" href="/icons-35549e149c746afd95464c71b413b5e9/apple-touch-icon-76x76.png"><link rel="apple-touch-icon" sizes="114x114" href="/icons-35549e149c746afd95464c71b413b5e9/apple-touch-icon-114x114.png"><link rel="apple-touch-icon" sizes="120x120" href="/icons-35549e149c746afd95464c71b413b5e9/apple-touch-icon-120x120.png"><link rel="apple-touch-icon" sizes="144x144" href="/icons-35549e149c746afd95464c71b413b5e9/apple-touch-icon-144x144.png"><link rel="apple-touch-icon" sizes="152x152" href="/icons-35549e149c746afd95464c71b413b5e9/apple-touch-icon-152x152.png"><link rel="apple-touch-icon" sizes="180x180" href="/icons-35549e149c746afd95464c71b413b5e9/apple-touch-icon-180x180.png"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"><meta name="apple-mobile-web-app-title" content="dreamview"><link rel="icon" type="image/png" sizes="32x32" href="/icons-35549e149c746afd95464c71b413b5e9/favicon-32x32.png"><link rel="icon" type="image/png" sizes="16x16" href="/icons-35549e149c746afd95464c71b413b5e9/favicon-16x16.png"><link rel="shortcut icon" href="/icons-35549e149c746afd95464c71b413b5e9/favicon.ico"><meta name="mobile-web-app-capable" content="yes"><meta name="theme-color" content="#fff"><meta name="application-name" content="dreamview"><link rel="apple-touch-startup-image" media="(device-width: 320px) and (device-height: 480px) and (-webkit-device-pixel-ratio: 1)" href="/icons-35549e149c746afd95464c71b413b5e9/apple-touch-startup-image-320x460.png"><link rel="apple-touch-startup-image" media="(device-width: 320px) and (device-height: 480px) and (-webkit-device-pixel-ratio: 2)" href="/icons-35549e149c746afd95464c71b413b5e9/apple-touch-startup-image-640x920.png"><link rel="apple-touch-startup-image" media="(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2)" href="/icons-35549e149c746afd95464c71b413b5e9/apple-touch-startup-image-640x1096.png"><link rel="apple-touch-startup-image" media="(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2)" href="/icons-35549e149c746afd95464c71b413b5e9/apple-touch-startup-image-750x1294.png"><link rel="apple-touch-startup-image" media="(device-width: 414px) and (device-height: 736px) and (orientation: landscape) and (-webkit-device-pixel-ratio: 3)" href="/icons-35549e149c746afd95464c71b413b5e9/apple-touch-startup-image-1182x2208.png"><link rel="apple-touch-startup-image" media="(device-width: 414px) and (device-height: 736px) and (orientation: portrait) and (-webkit-device-pixel-ratio: 3)" href="/icons-35549e149c746afd95464c71b413b5e9/apple-touch-startup-image-1242x2148.png"><link rel="apple-touch-startup-image" media="(device-width: 768px) and (device-height: 1024px) and (orientation: landscape) and (-webkit-device-pixel-ratio: 1)" href="/icons-35549e149c746afd95464c71b413b5e9/apple-touch-startup-image-748x1024.png"><link rel="apple-touch-startup-image" media="(device-width: 768px) and (device-height: 1024px) and (orientation: portrait) and (-webkit-device-pixel-ratio: 1)" href="/icons-35549e149c746afd95464c71b413b5e9/apple-touch-startup-image-768x1004.png"><link rel="apple-touch-startup-image" media="(device-width: 768px) and (device-height: 1024px) and (orientation: landscape) and (-webkit-device-pixel-ratio: 2)" href="/icons-35549e149c746afd95464c71b413b5e9/apple-touch-startup-image-1496x2048.png"><link rel="apple-touch-startup-image" media="(device-width: 768px) and (device-height: 1024px) and (orientation: portrait) and (-webkit-device-pixel-ratio: 2)" href="/icons-35549e149c746afd95464c71b413b5e9/apple-touch-startup-image-1536x2008.png"></head>
<body>
<div id="root"></div>
......
......@@ -21,22 +21,26 @@ class SensorCamera extends React.Component {
@inject("store") @observer
class SceneView extends React.Component {
render() {
const { sceneDimension, meters, monitor, options, trafficSignal, video } = this.props.store;
const { sceneDimension, meters, monitor,
options, trafficSignal, video, hmi } = this.props.store;
return (
<div className="main-view" style={{height: sceneDimension.height}}>
<div className="main-view" style={{ height: sceneDimension.height }}>
<Scene width={sceneDimension.width}
height={sceneDimension.height}
options={options}
invisible={false}/>
invisible={false} />
{options.showRouteEditingBar
? <RouteEditingBar />
: <StatusBar meters={meters}
trafficSignal={trafficSignal}
showNotification={!options.showTasks}
monitor={monitor}/>}
{options.showVideo && <SensorCamera /> }
monitor={monitor} />}
{options.showVideo && <SensorCamera />}
{OFFLINE_PLAYBACK && <PlaybackControls />}
{hmi.showNavigationMap &&
<Navigation viewHeight={sceneDimension.height}
viewWidth={sceneDimension.width} />}
</div>
);
}
......@@ -45,12 +49,10 @@ class SceneView extends React.Component {
@inject("store") @observer
export default class MainView extends React.Component {
render() {
const { isInitialized, sceneDimension, hmi } = this.props.store;
const { isInitialized, sceneDimension } = this.props.store;
if (hmi.showNavigationMap) {
return <Navigation height={sceneDimension.height}/>;
} else if (!isInitialized && !OFFLINE_PLAYBACK) {
return <Loader height={sceneDimension.height}/>;
if (!isInitialized && !OFFLINE_PLAYBACK) {
return <Loader height={sceneDimension.height} />;
} else {
return <SceneView />;
}
......
export default class BaiduMapAdapter {
constructor() {
this.map = null;
this.controls = [];
}
isInitialized() {
......@@ -84,8 +85,20 @@ export default class BaiduMapAdapter {
new BMap.Size(offsetX, offsetY),
onClickHandler
);
this.map.addControl(myControl);
this.controls.push(myControl);
}
disableControls() {
this.controls.forEach(control => {
this.map.removeControl(control);
});
}
enableControls() {
this.controls.forEach(control => {
this.map.addControl(control);
});
}
getMarkerPosition(marker) {
......
export default class GoogleMapAdapter {
constructor() {
this.map = null;
this.controls = [];
}
isInitialized() {
......@@ -84,9 +85,24 @@ export default class GoogleMapAdapter {
controlUI.appendChild(controlText);
// Setup the click event listeners: simply set the map to Chicago.
controlUI.addEventListener("click", onClickHandler);
controlUI.addEventListener("click", () => {
onClickHandler(controlText);
});
this.map.controls[google.maps.ControlPosition.TOP_CENTER].push(controlDiv);
this.controls.push(controlDiv);
}
disableControls() {
this.controls.forEach(control => {
control.style.display = "none";
});
}
enableControls() {
this.controls.forEach(control => {
control.style.display = "block";
});
}
getMarkerPosition(marker) {
......
......@@ -35,6 +35,10 @@ class MapNavigator {
});
}
isInitialized() {
return this.WS && this.mapAdapter && this.mapAdapter.isInitialized();
}
createControls() {
this.mapAdapter.createControl({
text: "Center Vehicle is ON",
......@@ -102,8 +106,16 @@ class MapNavigator {
});
}
disableControls() {
this.mapAdapter.disableControls();
}
enableControls() {
this.mapAdapter.enableControls();
}
update(data) {
if (!this.WS || !this.mapAdapter || !this.mapAdapter.isInitialized()) {
if (!this.isInitialized()) {
return;
}
......
import React from "react";
export default class WindowResizeControl extends React.PureComponent {
getMaximizingIcon() {
return (
<svg viewBox="0 0 20 20">
<defs>
<path d="M20 0L0 20h20V0z" id="a" />
<path d="M11.53 18.5l-.03-7h7" id="b" />
<path d="M12 12l7 7" id="c" />
</defs>
<use xlinkHref="#a" opacity=".6" fill="#549BFF" />
<use xlinkHref="#b" fillOpacity="0" stroke="#006AFF" strokeWidth="2" />
<use xlinkHref="#c" fillOpacity="0" stroke="#006AFF" strokeWidth="2" />
</svg>
);
}
getMinimizingIcon() {
return (
<svg viewBox="0 0 20 20">
<defs>
<path d="M20 0L0 20h20V0z" id="a" />
<path d="M18.47 11.5l.03 7h-7" id="b" />
<path d="M11 11l7 7" id="c" />
</defs>
<use xlinkHref="#a" opacity=".6" fill="#549BFF" />
<use xlinkHref="#b" fillOpacity="0" stroke="#006AFF" strokeWidth="2" />
<use xlinkHref="#c" fillOpacity="0" stroke="#006AFF" strokeWidth="2" />
</svg>
);
}
render() {
const { type, onClick } = this.props;
let icon = null;
switch (type) {
case "minimizing":
icon = this.getMinimizingIcon();
break;
case "maximizing":
icon = this.getMaximizingIcon();
break;
}
return (
<div className="window-resize-control" onClick={onClick}>
{icon}
</div>
);
}
}
import PARAMETERS from "store/config/parameters.yml";
import MAP_NAVIGATOR from "components/Navigation/MapNavigator";
import BaiduMapAdapter from "components/Navigation/BaiduMapAdapter";
import GoogleMapAdapter from "components/Navigation/GoogleMapAdapter";
import NavigationWebSocketEndpoint from "store/websocket/websocket_navigation";
function deduceWebsocketServerAddr() {
const server = window.location.origin;
const link = document.createElement("a");
link.href = server;
const protocol = location.protocol === "https:" ? "wss" : "ws";
return `${protocol}://${link.hostname}:${PARAMETERS.server.port}/websocket`;
}
window.onload = function() {
const serverAddr = deduceWebsocketServerAddr();
const WS = new NavigationWebSocketEndpoint(serverAddr);
WS.initialize();
const mapAdapter =
PARAMETERS.navigation.map === "GoogleMap" ? new GoogleMapAdapter() : new BaiduMapAdapter();
MAP_NAVIGATOR.initialize(WS, mapAdapter);
};
import React from "react";
import PARAMETERS from "store/config/parameters.yml";
import WindowResizeControl from "components/Navigation/WindowResizeControl";
import MAP_NAVIGATOR from "components/Navigation/MapNavigator";
import BaiduMapAdapter from "components/Navigation/BaiduMapAdapter";
import GoogleMapAdapter from "components/Navigation/GoogleMapAdapter";
import WS from "store/websocket";
export default class Navigation extends React.Component {
constructor(props) {
super(props);
this.state = {
routingView: false,
};
this.onClickHandler = this.onClickHandler.bind(this);
}
onClickHandler() {
const newRoutingView = !this.state.routingView;
if (newRoutingView) {
MAP_NAVIGATOR.enableControls();
} else {
MAP_NAVIGATOR.disableControls();
}
this.setState({
routingView: newRoutingView,
});
}
componentDidMount() {
const mapAdapter =
PARAMETERS.navigation.map === "GoogleMap"
? new GoogleMapAdapter()
: new BaiduMapAdapter();
MAP_NAVIGATOR.initialize(WS, mapAdapter);
MAP_NAVIGATOR.disableControls();
}
render() {
const {height} = this.props;
const { viewHeight, viewWidth } = this.props;
let top = 0;
let left = 0;
let width = viewWidth;
let height = viewHeight;
let iconType = "maximizing";
if (!this.state.routingView) {
top = 10;
left = 20;
width = Math.min(viewWidth * 0.3, 250);
height = Math.min(viewHeight * 0.5, 300);
iconType = "minimizing";
}
return (
<div className="main-view" style={{height: height}}>
<iframe src="components/Navigation/navigation_viewer.html"
style={{width: "100%", height: "100%"}}/>
<div
displayname="navigation"
className="navigation-view"
style={{ width: width, height: height, top: top, left: left }} >
<div id="map_canvas" />
<WindowResizeControl type={iconType} onClick={this.onClickHandler} />
</div>
);
}
......
......@@ -8,7 +8,7 @@ import LayerMenuIcon from "assets/images/sidebar/layer_menu.png";
import RouteEditingIcon from "assets/images/sidebar/route_editing.png";
import DataRecorderIcon from "assets/images/sidebar/data_recorder.png";
class SideBarButton extends React.Component {
class SideBarButton extends React.PureComponent {
render() {
const { disabled, onClick, active, label, extraClasses, iconSrc } = this.props;
return (
......@@ -25,9 +25,9 @@ class SideBarButton extends React.Component {
}
}
export default class ButtonPanel extends React.Component {
export default class ButtonPanel extends React.PureComponent {
render() {
const { enableHMIButtonsOnly,
const { enableHMIButtonsOnly, inNavigationMode,
onTasks, showTasks,
onModuleController, showModuleController,
onMenu, showMenu,
......@@ -52,7 +52,7 @@ export default class ButtonPanel extends React.Component {
onClick={onMenu}
active={showMenu} />
<SideBarButton label="Route Editing"
disabled={enableHMIButtonsOnly}
disabled={enableHMIButtonsOnly || inNavigationMode}
iconSrc={RouteEditingIcon}
onClick={onRouteEditingBar}
active={showRouteEditingBar} />
......
......@@ -8,11 +8,12 @@ import WS from "store/websocket";
@inject("store") @observer
export default class SideBar extends React.Component {
render() {
const { options, enableHMIButtonsOnly } = this.props.store;
const { options, enableHMIButtonsOnly, hmi } = this.props.store;
return (
<div className="side-bar">
<ButtonPanel enableHMIButtonsOnly={enableHMIButtonsOnly}
inNavigationMode={hmi.showNavigationMap}
onTasks={() => {
this.props.store.handleOptionToggle('showTasks');
}}
......
......@@ -19,7 +19,7 @@ export default class Others extends React.Component {
onClick={() => {
WS.resetBackend();
}}>Reset Backend Data</button>
<button disabled={false}
<button disabled={disablePanel}
onClick={() => {
WS.dumpMessages();
}}>Dump Message</button>
......
......@@ -108,7 +108,8 @@ export default class QuickStarter extends React.Component {
<CommandGroup disabled={false} commands={this.version} />
<CommandGroup disabled={tasksPanelLocked} commands={this.setup} />
<CommandGroup disabled={tasksPanelLocked} commands={this.reset} />
<CommandGroup disabled={!hmi.enableStartAuto} commands={this.auto}
<CommandGroup disabled={!hmi.enableStartAuto || tasksPanelLocked}
commands={this.auto}
extraButtonClass="start-auto-button"
extraCommandClass="start-auto-command" />
{hmi.showRTKCommands &&
......
......@@ -4,6 +4,8 @@
<meta charset="UTF-8">
<title>Dreamview</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script type="text/javascript" src="https://maps.google.com/maps/api/js?key=AIzaSyArRypN9OdShkutQzOcbxC4cwrIHU1xi3Y"></script>
<script type="text/javascript" src="http://api.map.baidu.com/api?v=3.0&ak=0kKZnWWhXEPfzIkklmzAa3dZ"></script>
</head>
<body>
<div id="root"></div>
......
......@@ -53,7 +53,7 @@ class DreamviewStore {
@observable moduleDelay = observable.map();
@computed get enableHMIButtonsOnly() {
return !this.isInitialized || this.hmi.showNavigationMap;
return !this.isInitialized;
}
@action updateTimestamp(newTimestamp) {
......
import Worker from "utils/webworker.js";
import MAP_NAVIGATOR from "components/Navigation/MapNavigator";
export default class NavigationWebSocketEndpoint {
constructor(serverAddr) {
this.serverAddr = serverAddr;
this.websocket = null;
this.worker = new Worker();
}
initialize() {
try {
this.websocket = new WebSocket(this.serverAddr);
this.websocket.binaryType = "arraybuffer";
} catch (error) {
console.error("Failed to establish a connection: " + error);
setTimeout(() => {
this.initialize();
}, 1000);
return;
}
this.websocket.onmessage = event => {
this.worker.postMessage({
source: "realtime",
data: event.data,
});
};
this.worker.onmessage = event => {
const message = event.data;
switch (message.type) {
case "SimWorldUpdate":
MAP_NAVIGATOR.update(message);
break;
default:
break;
}
};
this.websocket.onclose = event => {
console.log("WebSocket connection closed, close_code: " + event.code);
this.initialize();
};
// Request simulation world every 100ms.
clearInterval(this.timer);
this.timer = setInterval(() => {
if (this.websocket.readyState === this.websocket.OPEN) {
this.requestSimulationWorld();
}
}, 100);
}
requestSimulationWorld() {
this.websocket.send(
JSON.stringify({
type: "RequestSimulationWorld",
planning: false,
})
);
}
publishNavigationInfo(data) {
this.websocket.send(data);
}
}
import STORE from "store";
import RENDERER from "renderer";
import MAP_NAVIGATOR from "components/Navigation/MapNavigator";
import Worker from 'utils/webworker.js';
export default class RosWebSocketEndpoint {
......@@ -74,6 +75,9 @@ export default class RosWebSocketEndpoint {
this.requestRoutePath();
this.routingTime = message.routingTime;
}
if (STORE.hmi.showNavigationMap && MAP_NAVIGATOR.isInitialized()) {
MAP_NAVIGATOR.update(message);
}
this.counter += 1;
break;
case "MapElementIds":
......@@ -96,8 +100,7 @@ export default class RosWebSocketEndpoint {
// Request simulation world every 100ms.
clearInterval(this.timer);
this.timer = setInterval(() => {
if (this.websocket.readyState === this.websocket.OPEN &&
!STORE.hmi.showNavigationMap) {
if (this.websocket.readyState === this.websocket.OPEN) {
// Load default routing end point.
if (this.updatePOI) {
this.requestDefaultRoutingEndPoint();
......@@ -228,4 +231,8 @@ export default class RosWebSocketEndpoint {
type: "RequestRoutePath",
}));
}
publishNavigationInfo(data) {
this.websocket.send(data);
}
}
......@@ -195,6 +195,7 @@ body {
.main-view {
flex: 0 0 auto;
position: relative;
min-width: 600px;
}
}
}
......@@ -1365,3 +1366,23 @@ body {
}
}
}
.navigation-view {
z-index: 20;
position: relative;
#map_canvas {
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
}
.window-resize-control {
position: absolute;
bottom: 0px;
right: 0px;
width: 25px;
height: 25px;
}
}
\ No newline at end of file
......@@ -13,7 +13,6 @@ module.exports = {
entry: {
app: "./app.js",
navigation: "./components/Navigation/entry.js"
},
output: {
......@@ -181,10 +180,6 @@ module.exports = {
new FaviconsWebpackPlugin("./favicon.png"),
new CopyWebpackPlugin([
{
from: 'components/Navigation/navigation_viewer.html',
to: 'components/Navigation/navigation_viewer.html',
toType: 'file',
}, {
from: '../node_modules/three/examples/fonts',
to: 'fonts',
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册