// namespaces
var dwv = dwv || {};
dwv.tool = dwv.tool || {};
dwv.tool.draw = dwv.tool.draw || {};
/**
* The Konva namespace.
*
* @external Konva
* @see https://konvajs.org/
*/
var Konva = Konva || {};
/**
* Default draw label text.
*/
dwv.tool.draw.defaultRectangleLabelText = '{surface}';
/**
* Rectangle factory.
*
* @class
*/
dwv.tool.draw.RectangleFactory = function () {
/**
* Get the name of the shape group.
*
* @returns {string} The name.
*/
this.getGroupName = function () {
return 'rectangle-group';
};
/**
* Get the number of points needed to build the shape.
*
* @returns {number} The number of points.
*/
this.getNPoints = function () {
return 2;
};
/**
* Get the timeout between point storage.
*
* @returns {number} The timeout in milliseconds.
*/
this.getTimeout = function () {
return 0;
};
};
/**
* Is the input group a group of this factory?
*
* @param {object} group The group to test.
* @returns {boolean} True if the group is from this fcatory.
*/
dwv.tool.draw.RectangleFactory.prototype.isFactoryGroup = function (group) {
return this.getGroupName() === group.name();
};
/**
* Create a rectangle shape to be displayed.
*
* @param {Array} points The points from which to extract the rectangle.
* @param {object} style The drawing style.
* @param {object} viewController The associated view controller.
* @returns {object} The Konva group.
*/
dwv.tool.draw.RectangleFactory.prototype.create = function (
points, style, viewController) {
// physical shape
var rectangle = new dwv.math.Rectangle(points[0], points[1]);
// draw shape
var kshape = new Konva.Rect({
x: rectangle.getBegin().getX(),
y: rectangle.getBegin().getY(),
width: rectangle.getWidth(),
height: rectangle.getHeight(),
stroke: style.getLineColour(),
strokeWidth: style.getStrokeWidth(),
strokeScaleEnabled: false,
name: 'shape'
});
// label text
var ktext = new Konva.Text({
fontSize: style.getFontSize(),
fontFamily: style.getFontFamily(),
fill: style.getLineColour(),
padding: style.getTextPadding(),
shadowColor: style.getShadowLineColour(),
shadowOffset: style.getShadowOffset(),
name: 'text'
});
var textExpr = '';
if (typeof dwv.tool.draw.rectangleLabelText !== 'undefined') {
textExpr = dwv.tool.draw.rectangleLabelText;
} else {
textExpr = dwv.tool.draw.defaultRectangleLabelText;
}
var quant = rectangle.quantify(
viewController,
dwv.utils.getFlags(textExpr));
ktext.setText(dwv.utils.replaceFlags(textExpr, quant));
// meta data
ktext.meta = {
textExpr: textExpr,
quantification: quant
};
// label
var klabel = new Konva.Label({
x: rectangle.getBegin().getX(),
y: rectangle.getEnd().getY(),
scale: style.applyZoomScale(1),
visible: textExpr.length !== 0,
name: 'label'
});
klabel.add(ktext);
klabel.add(new Konva.Tag({
fill: style.getLineColour(),
opacity: style.getTagOpacity()
}));
// debug shadow
var kshadow;
if (dwv.tool.draw.debug) {
kshadow = dwv.tool.draw.getShadowRectangle(rectangle);
}
// return group
var group = new Konva.Group();
group.name(this.getGroupName());
if (kshadow) {
group.add(kshadow);
}
group.add(klabel);
group.add(kshape);
group.visible(true); // dont inherit
return group;
};
/**
* Get anchors to update a rectangle shape.
*
* @param {object} shape The associated shape.
* @param {object} style The application style.
* @returns {Array} A list of anchors.
*/
dwv.tool.draw.RectangleFactory.prototype.getAnchors = function (shape, style) {
var rectX = shape.x();
var rectY = shape.y();
var rectWidth = shape.width();
var rectHeight = shape.height();
var anchors = [];
anchors.push(dwv.tool.draw.getDefaultAnchor(
rectX, rectY, 'topLeft', style
));
anchors.push(dwv.tool.draw.getDefaultAnchor(
rectX + rectWidth, rectY, 'topRight', style
));
anchors.push(dwv.tool.draw.getDefaultAnchor(
rectX + rectWidth, rectY + rectHeight, 'bottomRight', style
));
anchors.push(dwv.tool.draw.getDefaultAnchor(
rectX, rectY + rectHeight, 'bottomLeft', style
));
return anchors;
};
/**
* Update a rectangle shape.
* Warning: do NOT use 'this' here, this method is passed
* as is to the change command.
*
* @param {object} anchor The active anchor.
* @param {object} style The app style.
* @param {object} viewController The associated view controller.
*/
dwv.tool.draw.RectangleFactory.prototype.update = function (
anchor, style, viewController) {
// parent group
var group = anchor.getParent();
// associated shape
var krect = group.getChildren(function (node) {
return node.name() === 'shape';
})[0];
// associated label
var klabel = group.getChildren(function (node) {
return node.name() === 'label';
})[0];
// find special points
var topLeft = group.getChildren(function (node) {
return node.id() === 'topLeft';
})[0];
var topRight = group.getChildren(function (node) {
return node.id() === 'topRight';
})[0];
var bottomRight = group.getChildren(function (node) {
return node.id() === 'bottomRight';
})[0];
var bottomLeft = group.getChildren(function (node) {
return node.id() === 'bottomLeft';
})[0];
// debug shadow
var kshadow;
if (dwv.tool.draw.debug) {
kshadow = group.getChildren(function (node) {
return node.name() === 'shadow';
})[0];
}
// update 'self' (undo case) and special points
switch (anchor.id()) {
case 'topLeft':
topLeft.x(anchor.x());
topLeft.y(anchor.y());
topRight.y(anchor.y());
bottomLeft.x(anchor.x());
break;
case 'topRight':
topRight.x(anchor.x());
topRight.y(anchor.y());
topLeft.y(anchor.y());
bottomRight.x(anchor.x());
break;
case 'bottomRight':
bottomRight.x(anchor.x());
bottomRight.y(anchor.y());
bottomLeft.y(anchor.y());
topRight.x(anchor.x());
break;
case 'bottomLeft':
bottomLeft.x(anchor.x());
bottomLeft.y(anchor.y());
bottomRight.y(anchor.y());
topLeft.x(anchor.x());
break;
default :
dwv.logger.error('Unhandled anchor id: ' + anchor.id());
break;
}
// update shape
krect.position(topLeft.position());
var width = topRight.x() - topLeft.x();
var height = bottomLeft.y() - topLeft.y();
if (width && height) {
krect.size({width: width, height: height});
}
// positions: add possible group offset
var p2d0 = new dwv.math.Point2D(
group.x() + topLeft.x(),
group.y() + topLeft.y()
);
var p2d1 = new dwv.math.Point2D(
group.x() + bottomRight.x(),
group.y() + bottomRight.y()
);
// new rect
var rect = new dwv.math.Rectangle(p2d0, p2d1);
// debug shadow based on round (used in quantification)
if (kshadow) {
var round = rect.getRound();
var rWidth = round.max.getX() - round.min.getX();
var rHeight = round.max.getY() - round.min.getY();
kshadow.position({
x: round.min.getX() - group.x(),
y: round.min.getY() - group.y()
});
kshadow.size({width: rWidth, height: rHeight});
}
// update label position
var textPos = {
x: rect.getBegin().getX() - group.x(),
y: rect.getEnd().getY() - group.y()
};
klabel.position(textPos);
// update quantification
dwv.tool.draw.updateRectangleQuantification(group, viewController);
};
/**
* Update the quantification of a Rectangle.
*
* @param {object} group The group with the shape.
* @param {object} viewController The associated view controller.
*/
dwv.tool.draw.RectangleFactory.prototype.updateQuantification = function (
group, viewController) {
dwv.tool.draw.updateRectangleQuantification(group, viewController);
};
/**
* Update the quantification of a Rectangle (as a static
* function to be used in update).
*
* @param {object} group The group with the shape.
* @param {object} viewController The associated view controller.
*/
dwv.tool.draw.updateRectangleQuantification = function (
group, viewController) {
// associated shape
var krect = group.getChildren(function (node) {
return node.name() === 'shape';
})[0];
// associated label
var klabel = group.getChildren(function (node) {
return node.name() === 'label';
})[0];
// positions: add possible group offset
var p2d0 = new dwv.math.Point2D(
group.x() + krect.x(),
group.y() + krect.y()
);
var p2d1 = new dwv.math.Point2D(
p2d0.getX() + krect.width(),
p2d0.getY() + krect.height()
);
// rectangle
var rect = new dwv.math.Rectangle(p2d0, p2d1);
// update text
var ktext = klabel.getText();
var quantification = rect.quantify(
viewController,
dwv.utils.getFlags(ktext.meta.textExpr));
ktext.setText(dwv.utils.replaceFlags(ktext.meta.textExpr, quantification));
// update meta
ktext.meta.quantification = quantification;
};
/**
* Get the debug shadow.
*
* @param {object} rectangle The rectangle to shadow.
* @returns {object} The shadow konva shape.
*/
dwv.tool.draw.getShadowRectangle = function (rectangle) {
var round = rectangle.getRound();
var rWidth = round.max.getX() - round.min.getX();
var rHeight = round.max.getY() - round.min.getY();
return new Konva.Rect({
x: round.min.getX(),
y: round.min.getY(),
width: rWidth,
height: rHeight,
fill: 'grey',
strokeWidth: 0,
strokeScaleEnabled: false,
opacity: 0.3,
name: 'shadow'
});
};