首页 > 解决方案 > 是否有可以更改 html 元素的样式属性的最大数量?

问题描述

我正在使用ElectronJS创建一个从灰度图像生成 STL 文件的应用程序。在这种情况下,我有一些嵌套循环,它们会遍历每个其他像素,以将每个方面的坐标写入文件。我正在尝试通过更新 div 的 width 属性来实现进程的进度条(处理 4k 图像可能需要 30 分钟)。但是,即使我在循环中设置了新宽度,似乎直到循环完成后宽度才会更新。我更新样式太快了吗?

由于我不包括下面的其余 js,因此选择文件按钮允许用户从他们的文件系统中选择一个文件(即图像)。转换按钮使用该文件路径和Opencv来查找图像像素的“高度”(读取为灰度),并将连接这些“高度”所产生的方面写入 stl 文件。

这是我的 HTML:

<!DOCTYPE html>
<html>
   <head>
      <title>File Select</title>
      <link rel="stylesheet" href="../css/convert.css"/>
   </head>
   <body>
      <button id="select-file-button" onclick="selectFile()">Select File</button>
      <p id="filename"></p>
      <div id="progress-bar" style="--width: 2%"></div>
      <button id="test" onclick="convert()">Convert</button>
      <!-- Excluded from page -->
      <img id="img-for-analysis" src=""/>
      <!-- Scripts -->
      <script type="text/javascript" src="../js/convert.js"></script>
   </body>
</html>

这是CSS:

@font-face {font-family: "Orkney Light"; src: url('./fonts/orkney/Orkney\ Light.ttf')}
@font-face {font-family: "Orkney Medium"; src: url('./fonts/orkney/Orkney\ Medium.ttf')}
@font-face {font-family: "Orkney Bold"; src: url('./fonts/orkney/Orkney\ Bold.ttf')}

body {
   margin: 0;  
   height: 100%;
   overflow: hidden;
}

#progress-bar {
   width: 50vw;
   height: 5vh;
   background-color: black;
   border-radius: 5vw;
   position: relative
}
#progress-bar::before {
   content: "";
   width: calc(var(--width, 0) * 1%);
   position: absolute;
   left: 1vw;
   top: 1vh;
   bottom: 1vh;
   min-width: 0.1vw;
   max-width: calc(100% - 2vw);
   background-color: red;
   border-radius: 10000vw;
}
#img-for-analysis {
   margin-top: 100vh;
   opacity: 0;
   position: fixed;
}

这里是发生转换过程的链接的js文件部分,包括进度条的代码:

/*
 * Progress bar
 */
const progressBar = document.getElementById('progress-bar')

/**
 * Returns the current width of the progress bar
 */
function getProgressBarWidth() {
  const computedStyle = getComputedStyle(progressBar)
  const width = parseFloat(computedStyle.getPropertyValue('--width')) || 0
  return width
}

/**
 * Update the progress bar with the given value
 * @param {number} newWidth - A positive number meant to be the new percent of the progress bar
 */
function updateProgressBar (newWidth) {
  progressBar.style.setProperty('--width', newWidth * 100)
}


/*
 * Convert
 */

/**
 * Writes the generic beginning of a facet to the given stream
 * @param {fs write stream} stream 
 */
function writeFacetBeginning (stream) {
  stream.write("facet normal 0 0 0" + "\n" + "outer loop" + "\n")
}

/**
 * Writes the generic beginning of a caet to the given stream
 * @param {fs write stream} stream 
 */
function writeFacetEnd (stream) {
  stream.write("endloop" + "\n" + "endfacet" + "\n")
}

/**
 * Coverts the already selected file to an stl file
 */
function convert() {
  // Not converting if there is no file selected
  if(filePath == null) {
    return
  }


  // Making the mat
  let src = cv.imread('img-for-analysis', cv.IMREAD_GRAYSCALE)

  // Variable to hold the pixel values of the image
  let pixelValues = [...Array(src.rows)].map(e => Array(src.cols).fill(null))
  //Storing the values of the pixels in the array
  for(let i = 0; i < src.rows; i++) {
    for (let j = 0; j < src.cols; j++) {
      pixelValues[i][j] = parseInt(src.ucharAt(i, j * src.channels()))
    }
  }

  // Creating the read stream
  let stream = fs.createWriteStream(fileName.split('.')[0] + '.stl', {flags: 'w'})

  // Settings
  let scale = 1/255

  // Status
  let maxProgress = (src.rows * src.cols)  // Every pixel + initial triangles for sides
  let currentProgress = 0

  stream.write("solid pic" + "\n")

    /*
    * Iterating through every other pixel to generate the facets of the top face
    *
    *                * -- * -- *
    *                |  \ | /  |
    *                * -- * -- *
    *                |  / | \  |
    *                * -- * -- *
    *
    */

    for (let row = 1; row < src.rows; row+=2)
    {
        for (let col = 1; col < src.cols; col+=2)
        {
            /*
            *
            * Creating facets w/ clockwise vertexes
            *
            * facet normal n1 n2 n3
            *   outer loop
            *     vertex x y z
            *     vertex x y z
            *     vertex x y z
            *   "\n"oop
            * endfacets
            */

            /* Top-Left
                *--*
                 \ |
                   *
            */
            writeFacetBeginning(stream);
          stream.write("vertex " + row + " " + col + " " + pixelValues[row][col] * scale + "\n")
            stream.write("vertex " + (row-1) + " " + col + " " + pixelValues[(row-1)][col] * scale + "\n")
            stream.write("vertex " + (row-1) + " " +(col-1)+ " " + pixelValues[row-1][col-1] * scale + "\n")
            writeFacetEnd(stream);

            /* Top-Left
                *
                | \
                *--*
            */
            writeFacetBeginning(stream);
            stream.write("vertex " + row + " " + col + " " + pixelValues[row][col] * scale + "\n")
            stream.write("vertex " + (row-1) + " " +(col-1)+ " " + pixelValues[(row-1)][col - 1] * scale + "\n")
            stream.write("vertex " + row + " " +(col-1)+ " " + pixelValues[row][col-1] * scale + "\n")
            writeFacetEnd(stream);

            /* Top-Right
                *--*
                | /
                *
            */
            if (col+1 < src.cols) //Is this pixel not on the last column
            {
                writeFacetBeginning(stream);
                stream.write("vertex " + row + " " + col + " " + pixelValues[row][col] * scale + "\n")
                stream.write("vertex " + (row-1) + " " +(col+1)+ " " + pixelValues[(row-1)][col + 1] * scale + "\n")
                stream.write("vertex " + (row-1) + " " + col + " " + pixelValues[(row-1)][col] * scale + "\n")
                writeFacetEnd(stream);

                /* Top-Right
                       *
                     / |
                    *--*
                */
                writeFacetBeginning(stream);
                stream.write("vertex " + row + " " + col + " " + pixelValues[row][col] * scale + "\n")
                stream.write("vertex " + row + " " +(col+1)+ " " + pixelValues[row][col + 1] * scale + "\n")
                stream.write("vertex " + (row-1) + " " +(col+1)+ " " + pixelValues[(row-1)][col + 1] * scale + "\n")
                writeFacetEnd(stream);
            }

            if (row + 1 < src.rows) //Is this pixel not on the last row?
            {
                /* Bottom-Left
                       *
                     / |
                    *--*
                */
                writeFacetBeginning(stream);
                stream.write("vertex " + row + " " + col + " " + pixelValues[row][col] * scale + "\n")
                stream.write("vertex " +(row+1)+ " " +(col-1)+ " " + pixelValues[row + 1][col - 1] * scale + "\n")
                stream.write("vertex " +(row+1)+ " " + col + " " + pixelValues[row + 1][col] * scale + "\n")
                writeFacetEnd(stream);

                /* Bottom-Left
                    *--*
                    | /
                    *
                */
                writeFacetBeginning(stream);
                stream.write("vertex " + row + " " + col + " " + pixelValues[row][col] * scale + "\n")
                stream.write("vertex " + row + " " +(col-1)+ " " + pixelValues[row][col - 1] * scale + "\n")
                stream.write("vertex " +(row+1)+ " " +(col-1)+ " " + pixelValues[row + 1][col - 1] * scale + "\n")
                writeFacetEnd(stream);
            }

            if (row + 1 < src.rows &&(col+1)< src.cols)
            {
                /* Bottom-Right
                    *
                    | \
                    *--*
                */
                writeFacetBeginning(stream);
                stream.write("vertex " + row + " " + col + " " + pixelValues[row][col] * scale + "\n")
                stream.write("vertex " +(row+1)+ " " + col + " " + pixelValues[row + 1][col] * scale + "\n")
                stream.write("vertex " +(row+1)+ " " +(col+1)+ " " + pixelValues[row + 1][col + 1] * scale + "\n")
                writeFacetEnd(stream);

                /* Bottom-Right
                    *--*
                     \ |
                       *
                */
                writeFacetBeginning(stream);
                stream.write("vertex " + row + " " + col + " " + pixelValues[row][col] * scale + "\n")
                stream.write("vertex " +(row+1)+ " " +(col+1)+ " " + pixelValues[row + 1][col + 1] * scale + "\n")
                stream.write("vertex " + row + " " +(col+1)+ " " + pixelValues[row][col + 1] * scale + "\n")
                writeFacetEnd(stream);
            }

            currentProgress += 4
        }
        updateProgressBar(currentProgress/maxProgress)
    }

标签: javascripthtmlcsselectron

解决方案


在您当前的执行周期结束之前,浏览器不会呈现更改。因此,即使您更新了元素的宽度,浏览器也会等待执行周期来呈现更改,这只会在您的整个循环完成后才会发生。

您可以在此处实施 2 种不同类型的解决方案

在循环之间使用 requestAnimationFrame

requestAnimationFrame在渲染当前帧之后,在渲染下一帧之前执行回调。

    function processRow(row = 1) {
      for (let col = 1; col < src.cols; col+=2) {
        // Your code
        currentProgress += 4;
      }
      updateProgressBar(currentProgress/maxProgress);
      if (row < src.rows) {
        requestAnimationFrame(() => processRow(row + 2));
      }
    }

使用WebWorker

由于您不依赖 DOM 或对 DOM 进行任何更改来处理图像,因此将整个计算部分移动到 WebWorker 并在完成循环时将消息发布到主线程。

在主线程中,您可以收听来自 WebWorker 的消息并相应地更新进度条


推荐阅读