Skip to content

Commit 34fec6b

Browse files
committed
Added segment 'markers' and 'overlay' options
This allows individual segments to be created as marker-style or overlay-style. This commit also adds a click event handler to marker handles, to bring the segment to the top of the z-order, so it can be dragged. See #544
1 parent e994f9a commit 34fec6b

File tree

5 files changed

+134
-53
lines changed

5 files changed

+134
-53
lines changed

doc/API.md

+6-6
Original file line numberDiff line numberDiff line change
@@ -601,9 +601,7 @@ The top level `Peaks` object exposes a factory function to create new `Peaks` in
601601

602602
### `Peaks.init(options, callback)`
603603

604-
Creates a new `Peaks` instance with the [assigned options](#Configuration).
605-
The callback is invoked after the instance has been created and initialized, or if any errors occur during initialization.
606-
You can create and manage several `Peaks` instances within a single page with one or several configurations.
604+
Creates a new `Peaks` instance with the given [options](#Configuration). The callback is invoked after the instance has been created and initialized, or if any errors occur during initialization. You can create and manage several `Peaks` instances within a single page, each with its own configuration.
607605

608606
```js
609607
const options = { ... };
@@ -1233,9 +1231,11 @@ Adds a segment to the waveform timeline. Accepts an object containing the follow
12331231
* `startTime`: the segment start time (seconds)
12341232
* `endTime`: the segment end time (seconds)
12351233
* `editable`: (optional) sets whether the segment is user editable (boolean, defaults to `false`)
1236-
* `color`: (optional) the segment color. If not specified, the segment is given a default color (set by the [`segmentoptions.waveformColor` option](#Configuration) for marker-style segments or the [`segmentOptions.overlayColor` option](#Configuration) for overlay-style segments)
1237-
* `borderColor`: (optional) the segment border color. This applies only to overlay style segments. If not specified, the segment is given a default border color (set by the [`segmentOptions.overlayBorderColor` option](#Configuration))
1238-
* `labelText`: (option) a text label which is displayed when the user hovers the mouse pointer over the segment
1234+
* `color`: (optional) the segment color. If not specified, the segment is given a default color set by the [`segmentOptions.overlayColor`](#configuration) option for segments with overlays, or [`segmentoptions.waveformColor`](#configuration) option for segments without overlays
1235+
* `borderColor`: (optional) the segment border color. This applies only to segments with overlays. If not specified, the segment is given a default border color (set by the [`segmentOptions.overlayBorderColor` option](#configuration))
1236+
* `markers`: (optional) sets whether the segment has markers. If not specified, the default is set by the [`segmentOptions.markers`](#configuration) option
1237+
* `overlay`: (optional) sets whether the segment has an overlay. If not specified, the default is set by the [`segmentOptions.overlay`](#configuration) option
1238+
* `labelText`: (optional) a text label which is displayed when the user hovers the mouse pointer over the segment
12391239
* `id`: (optional) the segment identifier. If not specified, the segment is automatically given a unique identifier
12401240

12411241
```js

src/segment-marker.js

+13-8
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,16 @@ import Konva from 'konva/lib/Core';
3737
function SegmentMarker(options) {
3838
const self = this;
3939

40-
self._segment = options.segment;
41-
self._marker = options.marker;
42-
self._segmentShape = options.segmentShape;
43-
self._editable = options.editable;
44-
self._startMarker = options.startMarker;
40+
self._segment = options.segment;
41+
self._marker = options.marker;
42+
self._segmentShape = options.segmentShape;
43+
self._editable = options.editable;
44+
self._startMarker = options.startMarker;
4545

46-
self._onDragStart = options.onDragStart;
47-
self._onDragMove = options.onDragMove;
48-
self._onDragEnd = options.onDragEnd;
46+
self._onClick = options.onClick;
47+
self._onDragStart = options.onDragStart;
48+
self._onDragMove = options.onDragMove;
49+
self._onDragEnd = options.onDragEnd;
4950

5051
self._group = new Konva.Group({
5152
name: 'segment-marker',
@@ -65,6 +66,10 @@ function SegmentMarker(options) {
6566
SegmentMarker.prototype._bindDefaultEventHandlers = function() {
6667
const self = this;
6768

69+
self._group.on('click', function(event) {
70+
self._onClick(self, event);
71+
});
72+
6873
self._group.on('dragstart', function(event) {
6974
self._onDragStart(self, event);
7075
});

src/segment-shape.js

+53-38
Original file line numberDiff line numberDiff line change
@@ -71,25 +71,26 @@ function SegmentShape(segment, peaks, layer, view) {
7171

7272
this._overlayOffset = segmentOptions.overlayOffset;
7373

74-
if (!segmentOptions.overlay) {
74+
if (!segment.overlay) {
7575
this._waveformShape = new WaveformShape({
7676
color: segment.color,
7777
view: view,
7878
segment: segment
7979
});
8080
}
8181

82-
this._onMouseEnter = this._onMouseEnter.bind(this);
83-
this._onMouseLeave = this._onMouseLeave.bind(this);
84-
this._onMouseDown = this._onMouseDown.bind(this);
85-
this._onMouseUp = this._onMouseUp.bind(this);
82+
this._onMouseEnter = this._onMouseEnter.bind(this);
83+
this._onMouseLeave = this._onMouseLeave.bind(this);
84+
this._onMouseDown = this._onMouseDown.bind(this);
85+
this._onMouseUp = this._onMouseUp.bind(this);
8686

8787
this._dragBoundFunc = this._dragBoundFunc.bind(this);
8888
this._onSegmentDragStart = this._onSegmentDragStart.bind(this);
8989
this._onSegmentDragMove = this._onSegmentDragMove.bind(this);
9090
this._onSegmentDragEnd = this._onSegmentDragEnd.bind(this);
9191

9292
// Event handlers for markers
93+
this._onSegmentMarkerClick = this._onSegmentMarkerClick.bind(this);
9394
this._onSegmentMarkerDragStart = this._onSegmentMarkerDragStart.bind(this);
9495
this._onSegmentMarkerDragMove = this._onSegmentMarkerDragMove.bind(this);
9596
this._onSegmentMarkerDragEnd = this._onSegmentMarkerDragEnd.bind(this);
@@ -134,7 +135,7 @@ function SegmentShape(segment, peaks, layer, view) {
134135

135136
let overlayBorderColor, overlayBorderWidth, overlayColor, overlayOpacity, overlayCornerRadius;
136137

137-
if (segmentOptions.overlay) {
138+
if (segment.overlay) {
138139
overlayBorderColor = this._borderColor || segmentOptions.overlayBorderColor;
139140
overlayBorderWidth = segmentOptions.overlayBorderWidth;
140141
overlayColor = this._color || segmentOptions.overlayColor;
@@ -156,7 +157,7 @@ function SegmentShape(segment, peaks, layer, view) {
156157

157158
this._overlay.add(this._overlayRect);
158159

159-
if (segmentOptions.overlay) {
160+
if (segment.overlay) {
160161
this._overlayText = new Konva.Text({
161162
x: 0,
162163
y: this._overlayOffset,
@@ -201,22 +202,29 @@ SegmentShape.prototype._createMarkers = function() {
201202
const editable = this._layer.isEditingEnabled() && this._segment.editable;
202203
const segmentOptions = this._view.getViewOptions().segmentOptions;
203204

204-
const createSegmentMarker = segmentOptions.markers ?
205-
this._peaks.options.createSegmentMarker :
206-
createOverlayMarker;
207-
208-
const startMarker = createSegmentMarker({
209-
segment: this._segment,
210-
editable: editable,
211-
startMarker: true,
212-
color: segmentOptions.startMarkerColor,
213-
fontFamily: this._peaks.options.fontFamily || defaultFontFamily,
214-
fontSize: this._peaks.options.fontSize || defaultFontSize,
215-
fontStyle: this._peaks.options.fontStyle || defaultFontShape,
216-
layer: this._layer,
217-
view: this._view.getName(),
218-
segmentOptions: this._view.getViewOptions().segmentOptions
219-
});
205+
let createSegmentMarker, startMarker, endMarker;
206+
207+
if (this._segment.markers) {
208+
createSegmentMarker = this._peaks.options.createSegmentMarker;
209+
}
210+
else if (this._segment.overlay) {
211+
createSegmentMarker = createOverlayMarker;
212+
}
213+
214+
if (createSegmentMarker) {
215+
startMarker = createSegmentMarker({
216+
segment: this._segment,
217+
editable: editable,
218+
startMarker: true,
219+
color: segmentOptions.startMarkerColor,
220+
fontFamily: this._peaks.options.fontFamily || defaultFontFamily,
221+
fontSize: this._peaks.options.fontSize || defaultFontSize,
222+
fontStyle: this._peaks.options.fontStyle || defaultFontShape,
223+
layer: this._layer,
224+
view: this._view.getName(),
225+
segmentOptions: this._view.getViewOptions().segmentOptions
226+
});
227+
}
220228

221229
if (startMarker) {
222230
this._startMarker = new SegmentMarker({
@@ -225,25 +233,28 @@ SegmentShape.prototype._createMarkers = function() {
225233
editable: editable,
226234
startMarker: true,
227235
marker: startMarker,
236+
onClick: this._onSegmentMarkerClick,
228237
onDragStart: this._onSegmentMarkerDragStart,
229238
onDragMove: this._onSegmentMarkerDragMove,
230239
onDragEnd: this._onSegmentMarkerDragEnd,
231240
dragBoundFunc: this._segmentMarkerDragBoundFunc
232241
});
233242
}
234243

235-
const endMarker = createSegmentMarker({
236-
segment: this._segment,
237-
editable: editable,
238-
startMarker: false,
239-
color: segmentOptions.endMarkerColor,
240-
fontFamily: this._peaks.options.fontFamily || defaultFontFamily,
241-
fontSize: this._peaks.options.fontSize || defaultFontSize,
242-
fontStyle: this._peaks.options.fontStyle || defaultFontShape,
243-
layer: this._layer,
244-
view: this._view.getName(),
245-
segmentOptions: this._view.getViewOptions().segmentOptions
246-
});
244+
if (createSegmentMarker) {
245+
endMarker = createSegmentMarker({
246+
segment: this._segment,
247+
editable: editable,
248+
startMarker: false,
249+
color: segmentOptions.endMarkerColor,
250+
fontFamily: this._peaks.options.fontFamily || defaultFontFamily,
251+
fontSize: this._peaks.options.fontSize || defaultFontSize,
252+
fontStyle: this._peaks.options.fontStyle || defaultFontShape,
253+
layer: this._layer,
254+
view: this._view.getName(),
255+
segmentOptions: this._view.getViewOptions().segmentOptions
256+
});
257+
}
247258

248259
if (endMarker) {
249260
this._endMarker = new SegmentMarker({
@@ -252,6 +263,7 @@ SegmentShape.prototype._createMarkers = function() {
252263
editable: editable,
253264
startMarker: false,
254265
marker: endMarker,
266+
onClick: this._onSegmentMarkerClick,
255267
onDragStart: this._onSegmentMarkerDragStart,
256268
onDragMove: this._onSegmentMarkerDragMove,
257269
onDragEnd: this._onSegmentMarkerDragEnd,
@@ -301,9 +313,7 @@ SegmentShape.prototype.update = function(options) {
301313
this._overlayText.text(this._segment.labelText);
302314
}
303315

304-
const segmentOptions = this._view.getViewOptions().segmentOptions;
305-
306-
if (segmentOptions.overlay) {
316+
if (this._segment.overlay) {
307317
if (this._color) {
308318
this._overlayRect.fill(this._color);
309319
}
@@ -941,6 +951,11 @@ SegmentShape.prototype._segmentMarkerDragBoundFunc = function(segmentMarker, pos
941951
};
942952
};
943953

954+
SegmentShape.prototype._onSegmentMarkerClick = function() {
955+
// Move this segment to the top of the z-order.
956+
this._moveToTop();
957+
};
958+
944959
SegmentShape.prototype.fitToView = function() {
945960
if (this._startMarker) {
946961
this._startMarker.fitToView();

src/segment.js

+40-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ import {
1212
} from './utils';
1313

1414
const segmentOptions = [
15-
'id', 'pid', 'startTime', 'endTime', 'labelText', 'color', 'borderColor', 'editable'
15+
'id', 'pid', 'startTime', 'endTime', 'labelText', 'color', 'borderColor',
16+
'markers', 'overlay', 'editable'
1617
];
1718

1819
const invalidOptions = [
@@ -37,6 +38,14 @@ function setDefaultSegmentOptions(options, globalSegmentOptions) {
3738
options.labelText = '';
3839
}
3940

41+
if (isNullOrUndefined(options.markers)) {
42+
options.markers = globalSegmentOptions.markers;
43+
}
44+
45+
if (isNullOrUndefined(options.overlay)) {
46+
options.overlay = globalSegmentOptions.overlay;
47+
}
48+
4049
if (isNullOrUndefined(options.editable)) {
4150
options.editable = false;
4251
}
@@ -80,6 +89,22 @@ function validateSegmentOptions(options, updating) {
8089
throw new TypeError('peaks.segments.' + context + ': labelText must be a string');
8190
}
8291

92+
if (updating && objectHasProperty(options, 'markers')) {
93+
throw new TypeError('peaks.segments.' + context + ': cannot update markers attribute');
94+
}
95+
96+
if (objectHasProperty(options, 'markers') && !isBoolean(options.markers)) {
97+
throw new TypeError('peaks.segments.' + context + ': markers must be true or false');
98+
}
99+
100+
if (updating && objectHasProperty(options, 'overlay')) {
101+
throw new TypeError('peaks.segments.' + context + ': cannot update overlay attribute');
102+
}
103+
104+
if (objectHasProperty(options, 'overlay') && !isBoolean(options.overlay)) {
105+
throw new TypeError('peaks.segments.' + context + ': overlay must be true or false');
106+
}
107+
83108
if (objectHasProperty(options, 'editable') && !isBoolean(options.editable)) {
84109
throw new TypeError('peaks.segments.' + context + ': editable must be true or false');
85110
}
@@ -130,6 +155,8 @@ function Segment(peaks, pid, options) {
130155
this._color = options.color;
131156
this._borderColor = options.borderColor;
132157
this._editable = options.editable;
158+
this._markers = options.markers;
159+
this._overlay = options.overlay;
133160

134161
this._setUserData(options);
135162
}
@@ -190,6 +217,18 @@ Object.defineProperties(Segment.prototype, {
190217
return this._borderColor;
191218
}
192219
},
220+
markers: {
221+
enumerable: true,
222+
get: function() {
223+
return this._markers;
224+
}
225+
},
226+
overlay: {
227+
enumerable: true,
228+
get: function() {
229+
return this._overlay;
230+
}
231+
},
193232
editable: {
194233
enumerable: true,
195234
get: function() {

test/segment-spec.js

+22
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,26 @@ describe('Segment', function() {
199199
}).to.throw(Error);
200200
});
201201

202+
it('should not allow the overlay attribute to be updated', function() {
203+
p.segments.add({ startTime: 0, endTime: 10, labelText: 'test' });
204+
205+
const segment = p.segments.getSegments()[0];
206+
207+
expect(function() {
208+
segment.update({ overlay: false });
209+
}).to.throw(TypeError);
210+
});
211+
212+
it('should not allow the markers attribute to be updated', function() {
213+
p.segments.add({ startTime: 0, endTime: 10, labelText: 'test' });
214+
215+
const segment = p.segments.getSegments()[0];
216+
217+
expect(function() {
218+
segment.update({ markers: false });
219+
}).to.throw(TypeError);
220+
});
221+
202222
it('should allow a user data attribute to be created', function() {
203223
const peaks = { emit: function() {} };
204224
const pid = 0;
@@ -246,6 +266,8 @@ describe('Segment', function() {
246266
'_labelText',
247267
'_color',
248268
'_borderColor',
269+
'_overlay',
270+
'_markers',
249271
'_editable'
250272
].forEach(function(name) {
251273
it('should not allow an invalid user data attribute name: ' + name, function() {

0 commit comments

Comments
 (0)