peaks.js icon indicating copy to clipboard operation
peaks.js copied to clipboard

Display the segments text labels inside each respective segments, instead of in the top left corner.

Open richardbonneau opened this issue 4 years ago • 2 comments

Is there a way to customize the segments in order to achieve this? I would like the text labels to be visible at all time, and to be displayed inside of the segments.

I took a look at the Customizing Peak.js section but I can't find info as to how to change the behavior of the labeltext other than not displaying it.

richardbonneau avatar Apr 05 '21 21:04 richardbonneau

I am very close to making it work, what I did is I created a custom Segment marker with an additional Konva.Text object. Now the only thing that I'm missing is how to get the width of a segment, so that the text doesn't overflow outside of one. Any pointers for that?

Once I am done I will post my code and solution here.

richardbonneau avatar Apr 06 '21 15:04 richardbonneau

This is an interesting question. The current customization API doesn't give you control over where the segment label is placed. I did a quick experiment:

If you want the label to always be shown, and not show/hide on mouseover, I removed the code in SegmentShape here, here, and here. To do this properly, instead of removing the code we could add an option flag.

Next, I looked at SegmentShape._updateSegment, which is responsible for updating the position of all displayed segments, e.g., after adding or removing a segment or scrolling the waveform view.

I think this can be refactored to move the code that updates the marker positions into SegmentShape:

// in src/segments-layer.js:

SegmentsLayer.prototype._updateSegment = function(segment) {
  var segmentShape = this._findOrAddSegmentShape(segment);

  segmentShape.updatePosition();
};

// in src/segment-shape.js:

SegmentShape.prototype.updatePosition = function() {
  var segmentStartOffset = this._view.timeToPixels(this._segment.startTime);
  var segmentEndOffset   = this._view.timeToPixels(this._segment.endTime);

  var frameStartOffset = this._view.getFrameOffset();

  var startPixel = segmentStartOffset - frameStartOffset;
  var endPixel   = segmentEndOffset   - frameStartOffset;

  var marker = this.getStartMarker();

  if (marker) {
    marker.setX(startPixel - marker.getWidth());
  }

  marker = this.getEndMarker();

  if (marker) {
    marker.setX(endPixel);
  }
};

With this in place, we could now add code to adjust the label position by adding to SegmentShape.updatePosition. As an example, we could do this:

if (this._label) {
  var labelX = startPixel > 0 ? startPixel : 0;

  this._label.setX(labelX);
}

The functions you need for positioning the label are:

  • view.getFrameOffset() - the start position of the waveform shown in the view, in pixels
  • view.timeToPixels() - converts from time in seconds to pixels

The width of the segment can be calculated from the segmentStartOffset and segmentEndOffset variables.

Some other things to think about:

  • Is different behaviour is needed between the zoomable and the overview waveform views?
  • What should happen if there are multiple segments close together such that the labels would overlap each other?

chrisn avatar Apr 07 '21 07:04 chrisn