座位图编辑器 iframe 集成指南
本指南介绍如何通过 iframe 将座位图编辑器嵌入应用,包括配置选项和通信方式。
基础 iframe 集成
iframe 可将外部应用嵌入您的 Web 应用。下文介绍嵌入方法,以及如何通过 postMessage 建立消息通信。
简单嵌入
<!DOCTYPE html>
<html>
<head>
<style>
.container {
height: 100vh;
display: flex;
flex-direction: column;
}
iframe {
flex-grow: 1;
border: none;
}
</style>
</head>
<body>
<div class="container">
<!-- create iframe using js -->
<div class="controls">
<button id="openModalBtn">Open in modal window</button>
<span id="messageDisplay"></span>
</div>
<!-- or html -->
<iframe src="/app/venues/2/schemas/150" width="100%" height="100%"></iframe>
</div>
</body>
</html>
弹窗集成
创建包含 iframe 的弹窗
document.getElementById('openModalBtn').addEventListener('click', function () {
const modal = document.createElement('div');
modal.style.position = 'fixed';
modal.style.top = '0';
modal.style.left = '0';
modal.style.width = '100%';
modal.style.height = '100%';
modal.style.backgroundColor = 'rgba(0,0,0,0.5)';
const iframe = document.createElement('iframe');
iframe.src = '/app/venues/2/schemas/150?hideNavbar=true';
iframe.style.width = '95%';
iframe.style.height = '95%';
modal.appendChild(iframe);
document.body.appendChild(modal);
});
座位图编辑页面配置
座位图编辑界面可通过两种主要 URL 模式访问:
/app/venues/{venueId}/schemas/{schemaId} // Edit existing schema
/app/venues/{venueId}/schemas/new // Create new schema
其中 venueId 为场地 ID,schemaId 为待编辑座位图 ID;使用 “new” 则创建新座位图。
使用 URL 参数自定义界面
可通过以下 URL 参数自定义编辑器界面。
1. 隐藏界面元素
使用 hidden 参数隐藏指定工具栏元素:
/app/venues/2/schemas/150?hidden=pricing,save,shape
上例会隐藏定价模式按钮、保存按钮和形状工具。
2. 隐藏导航栏
要使嵌入体验更自然,可隐藏顶部导航栏:
/app/venues/2/schemas/150?hideNavbar=true
这尤其适合 iframe 集成,界面仅保留编辑器组件。
3. 强制显示定价工具
即使定价工具默认隐藏,或通过 hidden 参数隐藏,也可强制显示:
/app/venues/2/schemas/150?showPricing=true
4. 保存时保留草稿状态
自 Editor 1.74.0 起,添加 draft=true 可在嵌入编辑器保存时保留座位图的草稿状态:
/app/venues/2/schemas/new?hideNavbar=true&draft=true
使用 hideNavbar=true&draft=true 时,发布控件仍然可用。Save 保存草稿,Publish 才对外发布。不设置 draft=true 时,在隐藏定价工具的情况下保存仍会自动发布。此选项保留当前草稿状态,不会将已发布座位图变回草稿。
5. 组合参数
可组合这些参数,定制编辑体验:
/app/venues/2/schemas/150?hideNavbar=true&hidden=save,shape&showPricing=true
完整实现示例
下面的完整示例将编辑器嵌入弹窗,并自定义界面及处理消息:
function openSchemaEditor(venueId, schemaId, options = {}) {
// Create modal container
const modal = document.createElement('div');
modal.style.position = 'fixed';
modal.style.top = '0';
modal.style.left = '0';
modal.style.width = '100%';
modal.style.height = '100%';
modal.style.backgroundColor = 'rgba(0,0,0,0.5)';
modal.style.zIndex = '9999';
modal.style.display = 'flex';
modal.style.justifyContent = 'center';
modal.style.alignItems = 'center';
// Create close button
const closeBtn = document.createElement('button');
closeBtn.textContent = 'Close';
closeBtn.style.position = 'absolute';
closeBtn.style.top = '10px';
closeBtn.style.right = '10px';
closeBtn.style.zIndex = '10000';
modal.appendChild(closeBtn);
// Create iframe
const iframe = document.createElement('iframe');
// Build the base URL
let url = `/app/venues/${venueId}/schemas/${schemaId}`;
// Build query parameters
const params = new URLSearchParams();
// Hide specific UI elements if specified
if (options.hiddenElements && options.hiddenElements.length > 0) {
params.set('hidden', options.hiddenElements.join(','));
}
// Hide navbar if specified (default to true for modal)
if (options.hideNavbar !== false) {
params.set('hideNavbar', 'true');
}
// Force show pricing if specified
if (options.showPricing) {
params.set('showPricing', 'true');
}
if (options.preserveDraft) {
params.set('draft', 'true');
}
// Append parameters if any exist
if (params.toString()) {
url += `?${params.toString()}`;
}
iframe.src = url;
iframe.style.width = '95%';
iframe.style.height = '95%';
iframe.style.border = 'none';
modal.appendChild(iframe);
document.body.appendChild(modal);
let hasUnsavedChanges = false;
// Set up message listener for schema changes
window.addEventListener('message', function (event) {
// Handle schema changes
if (event.data.type === 'SCHEMA_CHANGED') {
console.log('Schema modified:', event.data);
hasUnsavedChanges = event.data.hasChanges;
// Update UI to indicate unsaved changes
if (hasUnsavedChanges) {
closeBtn.textContent = 'Close*';
} else {
closeBtn.textContent = 'Close';
}
}
// Handle close confirmation response
if (event.data.type === 'MODAL_CLOSE_RESPONSE' && event.data.canClose) {
document.body.removeChild(modal);
}
});
// Set up close button handler with confirmation
closeBtn.addEventListener('click', function () {
if (hasUnsavedChanges) {
iframe.contentWindow.postMessage({ type: 'MODAL_CLOSING' }, '*');
} else {
document.body.removeChild(modal);
}
});
// Return control functions
return {
close: function () {
if (hasUnsavedChanges) {
iframe.contentWindow.postMessage({ type: 'MODAL_CLOSING' }, '*');
} else {
document.body.removeChild(modal);
}
},
getIframe: function () {
return iframe;
},
};
}
// Example usage:
document.getElementById('openEditorBtn').addEventListener('click', function () {
const editor = openSchemaEditor(2, 150, {
hiddenElements: ['save', 'tool.shape.circle', 'tool.shape.polygon'],
showPricing: true,
});
});
可用界面元素
编辑器工具栏包含以下可选择隐藏的模式和工具。
编辑器模式
// Mode options that can be hidden
const modes = {
'mode.schema': 'Schema editing mode',
'mode.underlay': 'Underlay/background editing',
'mode.venueShape': 'Venue shape editing',
'mode.pricingZones': 'Pricing zones configuration',
'mode.pricing': 'Pricing management',
'mode.section': 'Section editing mode',
};
座位图工具
// Tools available in Schema mode
const schemaTools = {
'tool.select': 'Selection tool',
'tool.seatRows': 'Add seat rows tool',
'tool.table': 'Add table tool',
'tool.shape': 'Add shapes (all types)',
'tool.shape.rect': 'Add rectangle shape',
'tool.shape.circle': 'Add circle shape',
'tool.shape.line': 'Add line shape',
'tool.shape.polygon': 'Add polygon shape',
'tool.label': 'Add label tool',
};
区域工具
// Tools available in Section mode
const sectionTools = {
'tool.selectSeats': 'Select individual seats',
'tool.selectRows': 'Select entire rows',
'tool.addSeat': 'Add individual seats',
'tool.numberSeats': 'Number seats automatically',
};
定价工具
// Tools available in Pricing modes
const pricingTools = {
'tool.selectSeats': 'Select individual seats',
'tool.selectRows': 'Select entire rows',
'tool.selectSections': 'Select entire sections',
'tool.events': 'The events column and the preview modal event tabs',
};
tool.events(简写 events)同时控制定价模式中的活动列和预览弹窗中的活动标签页。传入 ?hidden=events 会同时隐藏两者。如果您此前用该标识符隐藏预览标签页,自 1.70.0 起定价活动列也会隐藏;如需保留活动列,请移除此标识符。
底图工具
// Tools available in Underlay mode
const underlayTools = {
'tool.importSvgBackground': 'Import SVG as background',
'tool.exportSvgBackground': 'Export SVG background',
'tool.removeSvgBackground': 'Remove SVG background',
'tool.viewbox': 'Adjust viewbox',
};
全局工具
// Global tools
const globalTools = {
'tool.save': 'Save changes',
'tool.publish': 'Publish schema (only appears when in draft mode)',
'tool.preview': 'Preview schema (only appears when event ID is available)',
};
在 URL 中隐藏元素
URL 参数可使用完整标识符(如 mode.schema),也可使用简写(如 schema):
?hidden=schema,pricing,save
使用完整标识符的写法:
?hidden=mode.schema,mode.pricing,tool.save
编辑器布局调整
使用 hideNavbar=true 隐藏导航栏后,编辑器自动调整布局:
- 完全移除顶部导航栏。
- 增加内容区域和侧栏高度,填满可用空间。
- 隐藏发布控件,除非同时设置
draft=true。
这样可提供更简洁、专注的编辑界面,适合 iframe 嵌入。
使用场景与示例
1. 面向客户的只读视图
// Open a read-only view of the schema with minimal UI
openSchemaEditor(2, 150, {
hideNavbar: true,
hiddenElements: [
'save',
'tool.shape',
'tool.table',
'tool.label',
'tool.seatRows',
'mode.underlay',
'mode.venueShape',
'mode.pricingZones',
'mode.pricing',
'tool.addSeat',
'tool.numberSeats',
],
});
2. 以定价为主的编辑器
// Open editor focused on pricing configuration
openSchemaEditor(2, 150, {
hideNavbar: true,
showPricing: true,
hiddenElements: [
'mode.schema',
'mode.underlay',
'mode.venueShape',
'tool.shape',
'tool.label',
'tool.seatRows',
'tool.table',
],
});
3. 座位图创建向导
// Open editor for creating a new schema with step-by-step guidance
openSchemaEditor(2, 'new', {
hideNavbar: true,
hiddenElements: ['mode.pricing', 'mode.pricingZones', 'tool.shape.polygon', 'tool.shape.line'],
});
实现自定义消息类型
实现自定义消息类型可扩展父应用与座位图编辑器之间的通信:
// In the parent application
function sendCustomCommand(iframe, command, data) {
iframe.contentWindow.postMessage(
{
type: 'CUSTOM_COMMAND',
command: command,
data: data,
},
'*',
);
}
// Example: Set zoom level
sendCustomCommand(editorIframe, 'SET_ZOOM', { level: 0.75 });
// Example: Focus on a specific section
sendCustomCommand(editorIframe, 'FOCUS_SECTION', { sectionId: 'A3' });
这些自定义命令需要在 iframe 应用中实现对应的处理器。