在HTML / CSS / JS

时间:2018-06-05 18:28:42

标签: javascript html css reaper

对不起,这会有点长......

一点上下文

作为一个大型项目的一部分,我正在尝试将项目时间表包含在用于远程控制音乐制作程序的网页中(对于那些感兴趣的人称为Reaper)。我试图让它显示当前的游戏位置,项目标记和项目区域。这些都直接来自程序的API,没有问题获取信息。对于初学者,我只是想显示项目标记,但是我已经把头发拉了一个多星期了,现在试着让它发挥作用。

这是一个来自软件内部的快速屏幕截图,用于说明我想要模仿的内容:Reaper ruler screencap

通常情况下,我会使用进度条来完成这样的事情,或者使用网络上成千上万个例子中的一个,但是我无法知道项目的长度,因为软件并没有限制它。结果我又回到了使用每条10px的固定比例。有点武断,我选择了它,因为它是120分钟的5分钟歌曲的最佳选择。不要太担心目前的情况,我只是想让它工作哈哈。

我遇到的问题(代码包含在底部)是因为我正在使用标记的绝对定位,以便从屏幕左侧对齐它们,所以它们是从文档流中拉出来的所以我无法将它们包装在父div中。最后,我打算将父div设置为80%的宽度,并使用滚动条查看其余的标记,所以显然我做错了。但是,我似乎无法找到任何类似于我想要实现的任何编码片段。

所以这是实际的问题:

我应该使用哪种显示/位置/浮动CSS来代替position: absolutefloat: left?如果我需要JS来做,那我该怎么做呢?

感谢您提供给我的任何帮助,无论是实际代码还是只是朝着正确的方向轻推!

这是我的(相关)代码:

的index.html

<html>
    <body>
        <div id="timeline">
            <div id="labels"></div>
            <div id="markers"></div>
        </div>
    </body>
</html>

的script.js:

// hardcoded for debugging purposes
// See section below about the API for info about how I get this data
var markers = [
    {label: "Start", pos: "20.00000000000000"},
    {label: "First", pos: "50.00000000000000"},
    {label: "Second", pos: "200.00000000000000"},
    {label: "Last", pos: "576.845412000000000"}
];

function draw_markers(marker_list) {
    var label_html = "";
    var marker_html = "";

    $.each(marker_list, function(index, obj) {
        var label = obj.label;
        var offset = parseFloat(obj.pos) * 7; // obj.pos is mesured in bars, not px

        label_html = label_html +
                    "<span class='label' style='margin-left:"+offset+"px'>" +
                    label + "</span>";

        marker_html = marker_html +
                    "<span class='marker' style='margin-left:"+offset+"px'>|</span>";
    });

    document.getElementById("labels").innerHTML = label_html;
    document.getElementById("markers").innerHTML = marker_html;
}

draw_markers(markers);

的style.css:

    html, body {
    background: #eeeeee;
}

#timeline {
    height: 4em;
    width: 100%;
    background-color: #9E9E9E;
}

#labels {
    border-bottom: 1px solid black;
    height: 50%;
    width: 100%;
}

#markers {
    height: 50%;
    width: 100%;
}

.label {
    position: absolute;
    float: left;
}
.marker {
    position: absolute;
    float: left;
}

关于API

我们获得了一系列定期轮询服务器并解析(明文)响应的函数。典型的响应看起来像这样:

MARKERLIST_BEGINMARKER_LIST
MARKER \t label \t ID \t position
...
MARKER_LIST_END
TRANSPORT \t playstate \t position_seconds \t isRepeatOn \t position_string \t position_string_beats
...

使用JS我分割每一行并使用switch语句来弄清楚如何处理每一行。然后,我构建了一个包含项目中所有标记的全局数组,只包含我需要的信息。

2 个答案:

答案 0 :(得分:1)

您可以将div用作display: inline-block并将其宽度设置为重叠绝对时间轴位置的增量百分比:

function draw_markers(marker_list) {
    var label_html = "";
    var marker_html = "";
    var total = null;
    var prev = 0;

    $.each(marker_list, function(index, obj) {
        var delta = parseFloat(obj.pos) - prev;
        obj.delta = delta;
        prev += parseFloat(obj.pos);
        total += delta;

    })

    $.each(marker_list, function(index, obj) {
        var label = obj.label;

        var offset = parseFloat(obj.delta) / (total / 100); // obj.pos is mesured in bars, not px

        label_html = label_html +
                    "<div class='label' style='width:"+offset+"%'>" +
                    label + "</div>";

        marker_html = marker_html +
                    "<div class='marker' style='width:"+offset+"%'>|</div>";
    });

    document.getElementById("labels").innerHTML = label_html;
    document.getElementById("markers").innerHTML = marker_html;
}

draw_markers(markers);

的CSS:

html, body {
    background: #eeeeee;
}

#timeline {
    height: 4em;
    width: 100%;
    background-color: #9E9E9E;
}

#labels {
    border-bottom: 1px solid black;
    height: 50%;
    width: 100%;
}

#markers {
    height: 50%;
    width: 100%;
}

.label {
    position: relative;
    display: inline-block;
}
.marker {
    position: relative;
    display: inline-block;
}

答案 1 :(得分:1)

或者,您可以使用<canvas>从Javascript中绘制时间轴(这是我用于Song Switcher的网络界面)。您还可以使用google.calendar API函数获取项目长度(例如,通过调用脚本将长度放入临时extstate然后从Web界面读取它)。

&#13;
&#13;
GetProjectLength
&#13;
function Timeline(canvas) {
  this.canvas  = canvas;
  this.ctx     = canvas.getContext('2d');
  this.length  = 0;
  this.markers = [];
}

Timeline.prototype.resize = function() {
  this.canvas.width  = this.canvas.clientWidth;
  this.canvas.height = this.canvas.clientHeight;
  
  this.scale = this.length / this.canvas.width;
}

Timeline.prototype.update = function() {
  this.resize();
  
  this.ctx.fillStyle = '#414141';
  this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
  
  this.ctx.textBaseline = 'hanging';
  
  for(var marker of this.markers)
    this.drawMarker(marker);
}

Timeline.prototype.drawMarker = function(marker) {
  const MARKER_WIDTH = 2;
  const FONT_SIZE    = 14;
  const PADDING      = MARKER_WIDTH * 2;
 
  var xpos = this.timeToPx(marker.pos);

  this.ctx.strokeStyle = this.ctx.fillStyle = 'red';
  this.ctx.lineWidth   = MARKER_WIDTH;

  this.ctx.beginPath();
  this.ctx.moveTo(xpos, 0);
  this.ctx.lineTo(xpos, this.canvas.height);
  this.ctx.stroke();

  if(marker.name.length > 0) {
    this.ctx.font = `bold ${FONT_SIZE}px sans-serif`;

    var boxWidth = this.ctx.measureText(marker.name).width + PADDING;
    this.ctx.fillRect(xpos, 0, boxWidth, FONT_SIZE + PADDING);

    this.ctx.fillStyle = 'white';
    this.ctx.fillText(marker.name, xpos + MARKER_WIDTH, PADDING);
  }
}

Timeline.prototype.timeToPx = function(time) {
  return time / this.scale;
}

var timeline = new Timeline(document.getElementById('timeline'));
timeline.length  = 30; // TODO: Fetch using GetProjectLength
timeline.markers = [
  {pos:  3, name: "Hello"},
  {pos: 15, name: "World!"},
  {pos: 29, name: ""},
];
timeline.update();

window.addEventListener('resize', timeline.update.bind(timeline));
&#13;
#timeline {
  height: 50px;
  line-height: 50px;
  image-rendering: pixelated;
  width: 100%;
}
&#13;
&#13;
&#13;