AnimateMotionpublic class AnimateMotion extends AbstractAnimate AnimateMotion represents an SVG Tiny
<animateMotion> element. |
Fields Summary |
---|
static final int | ROTATE_ANGLERotate type when an angle is specified in the rotate attribute. | static final int | ROTATE_AUTORotate type when the rotate attribute is set to auto. | static final int | ROTATE_AUTO_REVERSERotate type when the rotate attribute is set to auto-reverse | String | pathThe path attribute value. | float[] | keyPointsThe keyPoints attribute value | float | rotateThe rotate angle. Used if rotateType is ROTATE_ANGLE | float | cosRotateThe rotation's cos value | float | sinRotateThe rotation angle's sin value. | int | rotateTypeThe rotate type. One of ROTATE_ANGLE (an angle was specified) or
ROTATE_AUTO, ROTATE_AUTO_REVERSE | RefValues | pathRefValuesUsed, temporarily, to hold the refValues for the path attribute. | RefValues | mpathRefValuesUsed, temporarily, to hold the refValues for mpath child. |
Constructors Summary |
---|
public AnimateMotion(DocumentNode ownerDocument)Builds a new AnimateMotion element that belongs to the given
document. This AnimateMotion will belong
to the DocumentNode 's time container.
super(ownerDocument, SVGConstants.SVG_ANIMATE_MOTION_TAG);
// Default calcMode for animateMotion is paced.
calcMode = CALC_MODE_PACED;
// AnimateMotion operates on a fixed trait name
traitName = SVGConstants.SVG_MOTION_PSEUDO_ATTRIBUTE;
|
Methods Summary |
---|
protected void | computeRefTimes()Computes refTimes from the calcMode and keyTimes attributes. Validates
that the keyTimes attribute is compatible with the animate set up. This
may be overridden by subclasses (e.g., animateMotion), when there are
special rules for checking keyTimes compatiblity.
// if there is no keyPoints defined or if the calcMode is
// paced, we use the default behavior.
if (keyPoints == null || actualCalcMode == CALC_MODE_PACED) {
super.computeRefTimes();
return;
}
// Check keyTimes is compatible with the animation specification.
//
// a) keyTimes should be specified (i.e., not null)
//
// b) In all cases, the first keyTime must be zero.
//
// c) For non-discrete animations, the last keyTime must be one.
//
// d) There should be as many keyTimes as there are keyPoints
//
if (/* a) */ keyTimes == null
||
/* b) */ keyTimes.length < 1 || keyTimes[0] != 0
||
/* c) */ (actualCalcMode != CALC_MODE_DISCRETE
&&
keyTimes[keyTimes.length - 1] != 1)
||
/* d) */ keyTimes.length != keyPoints.length) {
throw animationError(
idRef,
traitNamespace,
traitName,
targetElement.getNamespaceURI(),
targetElement.getLocalName(),
getId(),
getNamespaceURI(),
getLocalName(),
Messages.formatMessage(
Messages.ERROR_INVALID_ANIMATION_KEY_TIMES,
new Object[] {
getTrait(SVGConstants.SVG_KEY_TIMES_ATTRIBUTE)
}));
}
// If the calcMode is _not_ discrete, we trim the last '1'
// value.
if (actualCalcMode != CALC_MODE_DISCRETE) {
refTimes = new float[keyTimes.length - 1];
System.arraycopy(keyTimes, 0, refTimes, 0, refTimes.length);
} else {
refTimes = keyTimes;
}
| public java.lang.String | getTraitImpl(java.lang.String name)
if (SVGConstants.SVG_PATH_ATTRIBUTE == name) {
return path;
} else if (SVGConstants.SVG_KEY_POINTS_ATTRIBUTE == name) {
return toStringTrait(keyPoints);
} else if (SVGConstants.SVG_ROTATE_ATTRIBUTE == name) {
switch (rotateType) {
case ROTATE_ANGLE:
return Float.toString(rotate);
case ROTATE_AUTO:
return SVGConstants.SVG_AUTO_VALUE;
case ROTATE_AUTO_REVERSE:
default:
return SVGConstants.SVG_AUTO_REVERSE_VALUE;
}
} else {
return super.getTraitImpl(name);
}
| protected void | mapToSegmentProgress(int si, float sp, float[] sisp)The following call lets the animate implementation map
the time segment indices and the time segment penetration
into refValues indices and penetration, in case these are
different. Typically, these are the same, but they may be
different, for example in the case of animateMotion with
keyPoints.
// animateMotion also maps to segments directly unless there
// is a keyPoints attribute specified, in which case it
// overrides the default behavior.
if (keyPoints == null || actualCalcMode == CALC_MODE_PACED) {
super.mapToSegmentProgress(si, sp, sisp);
return;
}
// We are dealing with a keyPoints animateMotion.
// We only do the computation on the first component, because
// the input and output indices for animateMotion with keyTimes
// should be the same on all components (by definition).
float startDist = keyPoints[si];
float endDist = keyPoints[si + 1];
float dist = sp * endDist + (1 - sp) * startDist;
// Now that we know how far along we should be on the path,
// find the corresponding segment.
((MotionRefValues) refValues).getSegmentAtDist(sisp, dist);
| public ElementNode | newInstance(DocumentNode doc)Used by DocumentNode to create a new instance from
a prototype TimedElementNode .
return new AnimateMotion(doc);
| final void | selectRefValuesExtra()Computes the 'right' source for reference values, depending on the
precedence rules for the different values sources.
if (mpathRefValues != null) {
refValues = mpathRefValues;
} else if (pathRefValues != null) {
refValues = pathRefValues;
}
| public void | setTraitImpl(java.lang.String name, java.lang.String value)
if (SVGConstants.SVG_PATH_ATTRIBUTE == name) {
checkWriteLoading(name);
// path values are validated in the validate() method,
// just like to/from/by and values are
path = value;
} else if (SVGConstants.SVG_KEY_POINTS_ATTRIBUTE == name) {
checkWriteLoading(name);
keyPoints = parseFloatArrayTrait(name, value, ';");
} else if (SVGConstants.SVG_ROTATE_ATTRIBUTE == name) {
checkWriteLoading(name);
if (SVGConstants.SVG_AUTO_VALUE.equals(value)) {
rotate = 0;
rotateType = ROTATE_AUTO;
} else if (SVGConstants.SVG_AUTO_REVERSE_VALUE.equals(value)) {
rotate = 0;
rotateType = ROTATE_AUTO_REVERSE;
} else {
// The value is neither 'auto' nor 'auto-reverse'. It
// must be an angle value.
rotate = parseFloatTrait(name, value);
cosRotate = MathSupport.cos(MathSupport.toRadians(rotate));
sinRotate = MathSupport.sin(MathSupport.toRadians(rotate));
rotateType = ROTATE_ANGLE;
}
} else {
super.setTraitImpl(name, value);
}
| boolean | supportsTrait(java.lang.String traitName)
if (SVGConstants.SVG_PATH_ATTRIBUTE == traitName
||
SVGConstants.SVG_KEY_POINTS_ATTRIBUTE == traitName
||
SVGConstants.SVG_ROTATE_ATTRIBUTE == traitName) {
return true;
} else {
return super.supportsTrait(traitName);
}
| final void | validateValuesExtra()Validates the path and mpath values sources.
// Validate the path attribute value
pathRefValues = null;
if (path != null) {
pathRefValues = traitAnim.toRefValues(
this,
new String[] {path},
null,
SVGConstants.SVG_PATH_ATTRIBUTE);
}
// Now, validate the mpath child, if any.
mpathRefValues = null;
SVGElement c = (SVGElement) getFirstElementChild();
SVGElement mpath = null;
while (c != null) {
if (SVGConstants.SVG_MPATH_TAG.equals(c.getLocalName())
&&
SVGConstants.SVG_NAMESPACE_URI.equals(c.getNamespaceURI())) {
mpath = c;
break;
}
c = (SVGElement) c.getNextElementSibling();
}
if (mpath != null) {
String pathHref = ((ElementNode) mpath).getTraitNSImpl(
SVGConstants.XLINK_NAMESPACE_URI,
SVGConstants.SVG_HREF_ATTRIBUTE);
if (pathHref != null) {
boolean pathHrefError = false;
if (pathHref.startsWith("#")) {
String pathId = pathHref.substring(1);
ElementNode path =
(ElementNode) ownerDocument.getElementById(pathId);
if (path != null) {
mpathRefValues = traitAnim.toRefValues(
this,
new String[] {
path.getTraitImpl(
SVGConstants.SVG_D_ATTRIBUTE)
},
null,
SVGConstants.SVG_D_ATTRIBUTE);
} else {
pathHrefError = true;
}
} else {
pathHrefError = true;
}
if (pathHrefError) {
throw animationError(idRef,
traitNamespace,
traitName,
targetElement.getNamespaceURI(),
targetElement.getLocalName(),
getId(),
getNamespaceURI(),
getLocalName(),
Messages.formatMessage
(Messages.ERROR_INVALID_MPATH_HREF,
new Object[] {pathHref}));
}
} else {
throw animationError(idRef,
traitNamespace,
traitName,
targetElement.getNamespaceURI(),
targetElement.getLocalName(),
getId(),
getNamespaceURI(),
getLocalName(),
Messages.formatMessage
(Messages.ERROR_MISSING_MPATH_HREF, null));
}
}
|
|