diff --git a/src/plugins/plot/res/templates/plot-options-browse.html b/src/plugins/plot/res/templates/plot-options-browse.html index 55e8c2db32..4462b762dc 100644 --- a/src/plugins/plot/res/templates/plot-options-browse.html +++ b/src/plugins/plot/res/templates/plot-options-browse.html @@ -44,7 +44,7 @@
  • Line Style
    + title="The rendering method to join lines for this series.">Line Method
    {{ { 'none': 'None', 'linear': 'Linear interpolation', @@ -56,7 +56,7 @@
    Markers
    - {{series.get('markers') ? "Enabled: " + series.get('markerSize') + "px" : "Disabled"}} + {{ series.markerOptionsDisplayText() }}
  • diff --git a/src/plugins/plot/res/templates/plot-options-edit.html b/src/plugins/plot/res/templates/plot-options-edit.html index 618bd78495..be3fa00eaf 100644 --- a/src/plugins/plot/res/templates/plot-options-edit.html +++ b/src/plugins/plot/res/templates/plot-options-edit.html @@ -52,7 +52,7 @@
  • Line Style
    + title="The rendering method to join lines for this series.">Line Method
    +
    + + +
  • Alarm Markers
    -
    +
    + +
  • 1) { + vec2 clipSpacePointCoord = 2.0 * gl_PointCoord - 1.0; + + if (uMarkerShape == 2) { // circle + float distance = length(clipSpacePointCoord); + + if (distance > 1.0) { + discard; + } + } else if (uMarkerShape == 3) { // diamond + float distance = abs(clipSpacePointCoord.x) + abs(clipSpacePointCoord.y); + + if (distance > 1.0) { + discard; + } + } else if (uMarkerShape == 4) { // triangle + float x = clipSpacePointCoord.x; + float y = clipSpacePointCoord.y; + float distance = 2.0 * x - 1.0; + float distance2 = -2.0 * x - 1.0; + + if (distance > y || distance2 > y) { + discard; + } + } + + } + } + `; + + const VERTEX_SHADER = ` + attribute vec2 aVertexPosition; + uniform vec2 uDimensions; + uniform vec2 uOrigin; + uniform float uPointSize; + + void main(void) { + gl_Position = vec4(2.0 * ((aVertexPosition - uOrigin) / uDimensions) - vec2(1,1), 0, 1); + gl_PointSize = uPointSize; + } + `; /** * Create a draw api utilizing WebGL. @@ -90,6 +124,7 @@ define([ this.vertexShader = this.gl.createShader(this.gl.VERTEX_SHADER); this.gl.shaderSource(this.vertexShader, VERTEX_SHADER); this.gl.compileShader(this.vertexShader); + this.fragmentShader = this.gl.createShader(this.gl.FRAGMENT_SHADER); this.gl.shaderSource(this.fragmentShader, FRAGMENT_SHADER); this.gl.compileShader(this.fragmentShader); @@ -105,6 +140,7 @@ define([ // shader programs (to pass values into shaders at draw-time) this.aVertexPosition = this.gl.getAttribLocation(this.program, "aVertexPosition"); this.uColor = this.gl.getUniformLocation(this.program, "uColor"); + this.uMarkerShape = this.gl.getUniformLocation(this.program, "uMarkerShape"); this.uDimensions = this.gl.getUniformLocation(this.program, "uDimensions"); this.uOrigin = this.gl.getUniformLocation(this.program, "uOrigin"); this.uPointSize = this.gl.getUniformLocation(this.program, "uPointSize"); @@ -114,9 +150,6 @@ define([ // Create a buffer to holds points which will be drawn this.buffer = this.gl.createBuffer(); - // Use a line width of 2.0 for legibility - this.gl.lineWidth(2.0); - // Enable blending, for smoothness this.gl.enable(this.gl.BLEND); this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE_MINUS_SRC_ALPHA); @@ -138,14 +171,18 @@ define([ ((v - this.origin[1]) / this.dimensions[1]) * this.height; }; - DrawWebGL.prototype.doDraw = function (drawType, buf, color, points) { + DrawWebGL.prototype.doDraw = function (drawType, buf, color, points, shape) { if (this.isContextLost) { return; } + + const shapeCode = MARKER_SHAPES[shape] ? MARKER_SHAPES[shape].drawWebGL : 0; + this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.buffer); this.gl.bufferData(this.gl.ARRAY_BUFFER, buf, this.gl.DYNAMIC_DRAW); this.gl.vertexAttribPointer(this.aVertexPosition, 2, this.gl.FLOAT, false, 0, 0); this.gl.uniform4fv(this.uColor, color); + this.gl.uniform1i(this.uMarkerShape, shapeCode) this.gl.drawArrays(drawType, 0, points); }; @@ -210,12 +247,12 @@ define([ * Draw the buffer as points. * */ - DrawWebGL.prototype.drawPoints = function (buf, color, points, pointSize) { + DrawWebGL.prototype.drawPoints = function (buf, color, points, pointSize, shape) { if (this.isContextLost) { return; } this.gl.uniform1f(this.uPointSize, pointSize); - this.doDraw(this.gl.POINTS, buf, color, points); + this.doDraw(this.gl.POINTS, buf, color, points, shape); }; /** diff --git a/src/plugins/plot/src/draw/MarkerShapes.js b/src/plugins/plot/src/draw/MarkerShapes.js new file mode 100644 index 0000000000..3c2afe7f8f --- /dev/null +++ b/src/plugins/plot/src/draw/MarkerShapes.js @@ -0,0 +1,90 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2020, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT is licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * Open MCT includes source code licensed under additional open source + * licenses. See the Open Source Licenses file (LICENSES.md) included with + * this source code distribution or the Licensing information page available + * at runtime from the About dialog for additional information. + *****************************************************************************/ + +define([], function () { + /** + * @label string (required) display name of shape + * @drawWebGL integer (unique, required) index provided to WebGL Fragment Shader + * @drawC2D function (required) canvas2d draw function + */ + const MARKER_SHAPES = { + point: { + label: 'Point', + drawWebGL: 1, + drawC2D: function (x, y, size) { + const offset = size / 2; + + this.c2d.fillRect(x - offset, y - offset, size, size); + } + }, + circle: { + label: 'Circle', + drawWebGL: 2, + drawC2D: function (x, y, size) { + const radius = size / 2; + + this.c2d.beginPath(); + this.c2d.arc(x, y, radius, 0, 2 * Math.PI, false); + this.c2d.closePath(); + this.c2d.fill(); + } + }, + diamond: { + label: 'Diamond', + drawWebGL: 3, + drawC2D: function (x, y, size) { + const offset = size / 2; + const top = [x, y + offset]; + const right = [x + offset, y]; + const bottom = [x, y - offset]; + const left = [x - offset, y]; + + this.c2d.beginPath(); + this.c2d.moveTo(...top); + this.c2d.lineTo(...right); + this.c2d.lineTo(...bottom); + this.c2d.lineTo(...left); + this.c2d.closePath(); + this.c2d.fill(); + } + }, + triangle: { + label: 'Triangle', + drawWebGL: 4, + drawC2D: function (x, y, size) { + const offset = size / 2; + const v1 = [x, y - offset]; + const v2 = [x - offset, y + offset]; + const v3 = [x + offset, y + offset]; + + this.c2d.beginPath(); + this.c2d.moveTo(...v1); + this.c2d.lineTo(...v2); + this.c2d.lineTo(...v3); + this.c2d.closePath(); + this.c2d.fill(); + } + } + }; + + return MARKER_SHAPES; +}); diff --git a/src/plugins/plot/src/inspector/PlotSeriesFormController.js b/src/plugins/plot/src/inspector/PlotSeriesFormController.js index d6b815c8f1..43335e403c 100644 --- a/src/plugins/plot/src/inspector/PlotSeriesFormController.js +++ b/src/plugins/plot/src/inspector/PlotSeriesFormController.js @@ -22,9 +22,11 @@ define([ './PlotModelFormController', + '../draw/MarkerShapes', 'lodash' ], function ( PlotModelFormController, + MARKER_SHAPES, _ ) { @@ -93,6 +95,13 @@ define([ value: o.key }; }); + this.$scope.markerShapeOptions = Object.entries(MARKER_SHAPES) + .map(([key, obj]) => { + return { + name: obj.label, + value: key + }; + }); }, fields: [ @@ -108,6 +117,10 @@ define([ modelProp: 'markers', objectPath: dynamicPathForKey('markers') }, + { + modelProp: 'markerShape', + objectPath: dynamicPathForKey('markerShape') + }, { modelProp: 'markerSize', coerce: Number,