草庐IT

javascript - 根据所选选项更改 Canvas 的尺寸

coder 2023-08-02 原文

我在 Canvas 上工作时遇到了改变立方体尺寸的想法。因此,通过使用 HTML5 Canvas,我制作了这个立方体,它有两个由线条连接的正方形,使它看起来像一个立方体。

我想要的是,当我从 select 中选择立方体类型时,立方体应该根据所选选项的长度和宽度自动更改。高度保持不变。就像如果我选择 5x5 的立方体,默认情况下它是一个立方体,但是当我选择 5x10 的选项时,宽度(正面)不应更改,但立方体的长度(边)应该扩展,反之亦然,如果我选择 10x5 我的最大选项是 25x15。如您所见,我在下面创建的 Canvas 以像素为单位,首先我需要将这些像素转换为厘米 (cm),然后将厘米转换为立方米。

整个立方体应该在指定的固定 Canvas 区域对齐。

这里是 fiddle

var canvas = document.querySelector('canvas');

canvas.width = 500;
canvas.height = 300;

var contxt = canvas.getContext('2d');

//squares
/*
contxt.fillRect(x, y, widht, height);
*/
contxt.strokeStyle = 'grey';
var fillRect = false;
contxt.fillStyle = 'rgba(0, 0, 0, 0.2)';
contxt.rect(80, 80, 100, 100);
contxt.rect(120, 40, 100, 100);
if (fillRect) {
  contxt.fill();
}
contxt.stroke();

/*Lines
contxt.beginPath();
contxt.moveTo(x, y);
contxt.lineTo(300, 100);
*/
contxt.beginPath();

contxt.moveTo(80, 80);
contxt.lineTo(120, 40);

contxt.moveTo(180, 80);
contxt.lineTo(220, 40);

contxt.moveTo(80, 180);
contxt.lineTo(120, 140);

contxt.moveTo(180, 180);
contxt.lineTo(220, 140);

contxt.stroke();
canvas {
  border: 1px solid #000;
}
select {
  display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select>
  <option>5x5</option>
  <option>5x10</option>
  <option>10x5</option>
</select>

<canvas></canvas>

最佳答案

绘制立方体:

要生成动态多维数据集,您必须监听 <select> 上的 onChange 事件。元素。每次选择的选项发生变化时,您都需要重新绘制立方体。

要重新绘制立方体,您需要创建一个 renderCube该函数应采用立方体的新尺寸,并指定一个定位偏移量。在此函数中,您必须清除之前绘制的立方体并使用给定的尺寸和偏移重新绘制新立方体。

添加过渡效果:

由于您不能将 css 转换应用于 Canvas 元素,因此您必须自己实现转换。您必须创建一个动画函数来计算过渡阶段立方体的尺寸,并在每一帧将其重新呈现到屏幕上。

具有过渡效果的可调整大小的立方体的实现是:
( if you prefer here is a fiddle too )
( if you do not need the transition effect check the fiddle before it has been implemented )

var canvas = document.querySelector('canvas');
canvas.width = 320;
canvas.height = 150;
var contxt = canvas.getContext('2d');

var currentHeight = 0, currentWidth = 0, currentDepth = 0, animationId = 0;

function renderCube(height, width, depth, offsetX, offsetY) {
  currentHeight = height;
  currentWidth = width;
  currentDepth = depth;

  // Clear possible existing cube
  contxt.clearRect(0, 0, canvas.width, canvas.height);
  contxt.beginPath();

  // Calculate depth, width and height based on given input
  depth = (depth * 10 * 0.8) / 2;
  width = width * 10;
  height = height * 10;

  // Draw 2 squares to the canvas
  contxt.strokeStyle = 'grey';
  var fillRect = false;
  contxt.fillStyle = 'rgba(0, 0, 0, 0.2)';
  contxt.rect(offsetX, offsetY, width, height);
  contxt.rect(offsetX + depth, offsetY - depth, width, height);
  if (fillRect) {
    contxt.fill();
  }
  contxt.stroke();


  // An array which specifies where to draw the depth lines between the 2 rects
  // The offset will be applied while drawing the lines
  var depthLineCoordinates = [
    // posX, posY, posX2, posY2
    [0, 0, depth, -depth],
    [width, 0, width + depth, -depth],
    [0, height, depth, height - depth],
    [width, height, width + depth, height - depth]
  ];

  // Draw the depth lines to the canvas
  depthLineCoordinates.forEach(function(element) {
    contxt.moveTo(offsetX + element[0], offsetY + element[1]);
    contxt.lineTo(offsetX + element[2], offsetY + element[3]);
  });
  contxt.stroke();
}

// As requested by OP an example of a transition to the cube
// The transitionDuration may be a double which specifies the transition duration in seconds
function renderCubeWithTransistion(height, width, depth, offsetX, offsetY, transitionDuration) {
  var fps = 60;
  var then = Date.now();
  var startTime = then;
  var finished = false;

  var heightDifference = (height - currentHeight);
  var widthDifference = (width - currentWidth);
  var depthDifference = (depth - currentDepth);

  // Get an "id" for the current animation to prevent multiple animations from running at the same time.
  // Only the last recently started animation will be executed.
  // If a new one should be run, the last one will get aborted.
  var transitionStartMillis = (new Date()).getMilliseconds();
  animationId = transitionStartMillis;

  function animate() {
    // Do not continue rendering the current animation if a new one has been started
    if (transitionStartMillis != animationId) return;
    // request another frame if animation has not been finished
    if (!finished) requestAnimationFrame(animate);

    // Control FPS
    now = Date.now();
    elapsed = now - then;

    if (elapsed > (1000 / fps)) {
      then = now - (elapsed % (1000 / fps));

      // Calculate a linear transition effect
      if (parseInt(currentHeight, 0) != parseInt(height, 0)) currentHeight += heightDifference / (transitionDuration * fps);
      if (parseInt(currentWidth, 0) != parseInt(width, 0)) currentWidth += widthDifference / (transitionDuration * fps);
      if (parseInt(currentDepth, 0) != parseInt(depth, 0)) currentDepth += depthDifference / (transitionDuration * fps);

      // Render the cube
      renderCube(currentHeight, currentWidth, currentDepth, offsetX, offsetY);

      // Check if the current dimensions of the cube are equal to the specified dimensions of the cube
      // If they are the same, finish the transition
      if (parseInt(currentHeight, 0) === parseInt(height, 0) && parseInt(currentWidth, 0) === parseInt(width, 0) && parseInt(currentDepth, 0) === parseInt(depth, 0)) {
        finished = true;
      }
    }
  }

  // Start the animation process
  animate();

  return true;
}

// Draw the cube initially with 5x5
renderCube(5, 5, 5, 80, 70);

// Add the onChange event listener to the select element
var cubeSizeSelector = document.getElementById('cubeSizeSelector');
cubeSizeSelector.onchange = function(e) {
  var cubeSize = e.target.value.split('x');
  renderCubeWithTransistion(5, parseInt(cubeSize[0], 0), parseInt(cubeSize[1], 0), 80, 70, 0.3);
}
canvas {
  border: 1px solid #000;
}
select {
  display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"> </script>
<select id="cubeSizeSelector">
  <option>5x5</option>
  <option>5x10</option>
  <option>10x5</option>
</select>

<canvas></canvas>

关于javascript - 根据所选选项更改 Canvas 的尺寸,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50253589/

有关javascript - 根据所选选项更改 Canvas 的尺寸的更多相关文章

  1. ruby-on-rails - Ruby on Rails 迁移,将表更改为 MyISAM - 2

    如何正确创建Rails迁移,以便将表更改为MySQL中的MyISAM?目前是InnoDB。运行原始执行语句会更改表,但它不会更新db/schema.rb,因此当在测试环境中重新创建表时,它会返回到InnoDB并且我的全文搜索失败。我如何着手更改/添加迁移,以便将现有表修改为MyISAM并更新schema.rb,以便我的数据库和相应的测试数据库得到相应更新? 最佳答案 我没有找到执行此操作的好方法。您可以像有人建议的那样更改您的schema.rb,然后运行:rakedb:schema:load,但是,这将覆盖您的数据。我的做法是(假设

  2. ruby - 默认情况下使选项为 false - 2

    这是在Ruby中设置默认值的常用方法:classQuietByDefaultdefinitialize(opts={})@verbose=opts[:verbose]endend这是一个容易落入的陷阱:classVerboseNoMatterWhatdefinitialize(opts={})@verbose=opts[:verbose]||trueendend正确的做法是:classVerboseByDefaultdefinitialize(opts={})@verbose=opts.include?(:verbose)?opts[:verbose]:trueendend编写Verb

  3. ruby-on-rails - 项目升级后 Pow 不会更改 ruby​​ 版本 - 2

    我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby​​版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby​​版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘

  4. ruby - Capistrano 3 在任务中更改 ssh_options - 2

    我尝试使用不同的ssh_options在同一阶段运行capistranov.3任务。我的production.rb说:set:stage,:productionset:user,'deploy'set:ssh_options,{user:'deploy'}通过此配置,capistrano与用户deploy连接,这对于其余的任务是正确的。但是我需要将它连接到服务器中配置良好的an_other_user以完成一项特定任务。然后我的食谱说:...taskswithoriginaluser...task:my_task_with_an_other_userdoset:user,'an_othe

  5. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  6. ruby - 更改 ActiveRecord 中对象的类 - 2

    假设我有一个FireNinja我的数据库中的对象,使用单表继承存储。后来才知道他真的是WaterNinja.将他更改为不同的子类的最干净的方法是什么?更好的是,我很想创建一个新的WaterNinja对象并替换旧的FireNinja在数据库中,保留ID。编辑我知道如何创建新的WaterNinja来self现有FireNinja的对象,我也知道我可以删除旧的并保存新的。我想做的是改变现有项目的类别。我是通过创建一个新对象并执行一些ActiveRecord魔法来替换行,还是通过对对象本身做一些疯狂的事情,或者甚至通过删除它并使用相同的ID重新插入来做到这一点,这是问题的一部分。

  7. ruby-on-rails - 使用 config.threadsafe 时从 lib/加载模块/类的正确方法是什么!选项? - 2

    我一直致力于让我们的Rails2.3.8应用程序在JRuby下正确运行。一切正常,直到我启用config.threadsafe!以实现JRuby提供的并发性。这导致lib/中的模块和类不再自动加载。使用config.threadsafe!启用:$rubyscript/runner-eproduction'pSim::Sim200Provisioner'/Users/amchale/.rvm/gems/jruby-1.5.1@web-services/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:105:in`co

  8. python - 如何读取 MIDI 文件、更改其乐器并将其写回? - 2

    我想解析一个已经存在的.mid文件,改变它的乐器,例如从“acousticgrandpiano”到“violin”,然后将它保存回去或作为另一个.mid文件。根据我在文档中看到的内容,该乐器通过program_change或patch_change指令进行了更改,但我找不到任何在已经存在的MIDI文件中执行此操作的库.他们似乎都只支持从头开始创建的MIDI文件。 最佳答案 MIDIpackage会为您完成此操作,但具体方法取决于midi文件的原始内容。一个MIDI文件由一个或多个音轨组成,每个音轨是十六个channel中任何一个上的

  9. ruby - 如何使用 Selenium Webdriver 根据 div 的内容执行操作? - 2

    我有一个使用SeleniumWebdriver和Nokogiri的Ruby应用程序。我想选择一个类,然后对于那个类对应的每个div,我想根据div的内容执行一个Action。例如,我正在解析以下页面:https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=puppies这是一个搜索结果页面,我正在寻找描述中包含“Adoption”一词的第一个结果。因此机器人应该寻找带有className:"result"的div,对于每个检查它的.descriptiondiv是否包含单词“adoption

  10. ruby - 如何根据长度将路径数组转换为嵌套数组或散列 - 2

    我需要根据字符串路径的长度将字符串路径数组转换为符号、哈希和数组的数组给定以下数组:array=["info","services","about/company","about/history/part1","about/history/part2"]我想生成以下输出,对不同级别进行分组,根据级别的结构混合使用符号和对象。产生以下输出:[:info,:services,about:[:company,history:[:part1,:part2]]]#altsyntax[:info,:services,{:about=>[:company,{:history=>[:part1,:pa

随机推荐