js网页模拟野火燃烧蔓延效果

本文探讨了野火蔓延的复杂物理机制,并回顾了近五十年来的数学模型研究,包括统计、经验及物理模型。重点介绍了考虑湍流热对流和化学反应动力学的新型物理模型。同时,提供了一个使用JS实现的在线野火蔓延可视化演示,允许用户点击点燃火苗和设置防火隔离带,以直观理解火势传播。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

野火通过燃床蔓延是自然界的一个复杂现象.本文综述了为认识这一现象所作的研究工作,包括分析各种理化机制及通过基本物理规律构造数学模型。现有的数学模型可分为统计模型、经验模型和物理模型三类.本文着重以统一的观点评述了近五十年来所建立的各种物理模型,并讨论了考虑湍流热对流和化学反应动力学的新方向.

本问通过用js模拟野火蔓延效果来实现一个可视化的蔓延展示:

点击草原上点可以点燃火苗,旋转的箭头表明风的方向。

在线demo地址

index.html

<!doctype html>

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Fire</title>
  <link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
  <link rel="stylesheet" href="style.css">
</head>

<body>
  <div id="tools" style="width: 750px; position: relative; height: 5em;">
    <div style="position: absolute; left: 0; top: 0;">
      <button class="ignite">燃烧</button>
      <button class="firebreak">防火隔离带</button>
      <div class="compass">
        <div class="wind"></div>
      </div>
    </div>


    <div  style="position: absolute; right: 0; top: 0;">
      <span id="fps" style="color: #000; font-weight: bold; margin-right: 1em;">
        <span class="model"></span>
        +
        <span class="view"></span>
      </span>
      <button id="reset-button">重置</button>
    </div>
  </div>
  <div id="burned">
    <div></div>
  </div>
  <div id="grid">
  </div>
  
  <script src="main.js" type="module"></script>
</body>

main.js

import { FireGrid } from './lib/FireGrid.js';
import { FireGridView } from './lib/FireGridView.js';
import { FireGridControl } from './lib/FireGridControl.js';

const width = 375;
const height = 375;
const scale = 2;

const container = document.querySelector('#grid');
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
canvas.id = 'fire-grid';
container.appendChild(canvas);

/*
const target = document.createElement('div');
target.className = 'target';
container.appendChild(target);
*/

const dom = {
  grid: document.querySelector('#fire-grid'),
  target: document.querySelector('#grid .target'),
  reset: document.querySelector('#reset-button'),
  burned: document.querySelector('#burned div'),
  burnedAmount: document.querySelector('#burned div'),
  toolIgnite: document.querySelector('#tools .ignite'),
  toolFirebreak: document.querySelector('#tools .firebreak'),
};

const toolModes = {
  ignite: 0,
  firebreak: 1,
}

let toolMode = toolModes.ignite;
updateTools();
dom.toolIgnite.addEventListener('click', function () {
  toolMode = toolModes.ignite;
  updateTools();
});
dom.toolFirebreak.addEventListener('click', function () {
  toolMode = toolModes.firebreak;
  updateTools();
});
function updateTools () {
  if (toolMode === toolModes.ignite) {
    dom.toolIgnite.classList.add('selected');
    dom.toolFirebreak.classList.remove('selected');
  } else if (toolMode === toolModes.firebreak) {
    dom.toolIgnite.classList.remove('selected');
    dom.toolFirebreak.classList.add('selected');
  }
}

const fireGrid = new FireGrid(width, height);
const fgView = new FireGridView(width, height, dom.grid);
const fgControl = new FireGridControl(fireGrid, fgView);

let lastTime = +new Date();

function handleMouse (event) {
  const rect = dom.grid.getBoundingClientRect();
  const x = event.clientX - rect.left;
  const y = event.clientY - rect.top;

  //const x = event.layerX;
  //const y = event.layerY;  
  const row = Math.floor(y/scale);// scale);
  const col = Math.floor(x/scale);// scale);

  if (toolMode === toolModes.ignite) {
    fgControl.ignite(row, col);
  } else if (toolMode === toolModes.firebreak) {
    fgControl.firebreak(row, col);
  }
}

dom.grid.addEventListener('click', handleMouse);

dom.reset.addEventListener('click', () => {
  fgControl.reset();
});

function step () {
  const now = +new Date();
  const duration = now - lastTime;
  lastTime = now;
  fgControl.step(duration);
  const width = String(Math.round(fgControl.burned * 100)) + '%';
  dom.burnedAmount.style.width = width;
  dom.burned.innerHTML = width;
  window.requestAnimationFrame(step);
}
step();
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值