#------------------------------------------------------------------------------- # canvas.Element #------------------------------------------------------------------------------- # Baseclass for all elements on a canvas # var Element = { # Reference frames (for "clip" coordinates) GLOBAL: 0, PARENT: 1, LOCAL: 2, # Constructor # # @param ghost Element ghost as retrieved from core methods new: func(ghost) { return { parents: [PropertyElement, Element, ghost], _node: props.wrapNode(ghost._node_ghost) }; }, # Get parent group/element getParent: func() { var parent_ghost = me._getParent(); if (parent_ghost == nil) return nil; var type = props.wrapNode(parent_ghost._node_ghost).getName(); var factory = me._getFactory(type); if (factory == nil) return parent_ghost; return factory(parent_ghost); }, # Get the canvas this element is placed on getCanvas: func() { wrapCanvas(me._getCanvas()); }, # Check if elements represent same instance # # @param el Other Element or element ghost equals: func(el) { return me._node.equals(el._node_ghost); }, # Hide/Show element # # @param visible Whether the element should be visible setVisible: func(visible = 1) { me.setBool("visible", visible); }, getVisible: func { me.getBool("visible") }, # Hide element (Shortcut for setVisible(0)) hide: func { me.setVisible(0); }, # Show element (Shortcut for setVisible(1)) show: func { me.setVisible(1); }, # Toggle element visibility toggleVisibility: func { me.setVisible(!me.getVisible()); }, setGeoPosition: func(lat, lon) { me._getTf()._node.getNode("m-geo[4]", 1).setValue("N"~lat); me._getTf()._node.getNode("m-geo[5]", 1).setValue("E"~lon); return me; }, # Create a new transformation matrix # # @param vals Default values (Vector of 6 elements) createTransform: func(vals = nil) { # tf[0] is reserved for setRotation, so min. index 1 is used here var node = me._node.addChild("tf", 1); return Transform.new(node, vals); }, # Shortcut for setting translation setTranslation: func { me._getTf().setTranslation(arg); return me; }, # Get translation set with #setTranslation getTranslation: func() { if (me["_tf"] == nil) return [0, 0]; return [me._tf.e.getValue(), me._tf.f.getValue()]; }, # Set rotation around transformation center (see #setCenter). # # @note This replaces the the existing transformation. For additional scale # or translation use additional transforms (see #createTransform). setRotation: func(rot) { if (me["_tf_rot"] == nil) { # always use the first matrix slot to ensure correct rotation # around transformation center. # tf-rot-index can be set to change the slot to be used. This is used for # example by the SVG parser to apply the rotation after all # transformations defined in the SVG file. me["_tf_rot"] = Transform.new( me._node.getNode("tf["~me.get("tf-rot-index", 0)~"]", 1) ); } me._tf_rot.setRotation(rot, me.getCenter()); return me; }, # Shortcut for setting scale setScale: func { me._getTf().setScale(arg); return me; }, # Shortcut for getting scale getScale: func { me._getTf().getScale(); }, # Set the fill/background/boundingbox color # # @param color Vector of 3 or 4 values in [0, 1] setColorFill: func { me.set("fill", _getColor(arg)); }, getColorFill: func { me.get("fill"); }, getTransformedBounds: func { me.getTightBoundingBox(); }, # Calculate the transformation center based on bounding box and center-offset updateCenter: func { me.update(); var bb = me.getTightBoundingBox(); if (bb[0] > bb[2] or bb[1] > bb[3]) { return; } me._setupCenterNodes( (bb[0] + bb[2]) / 2 + (me.get("center-offset-x") or 0), (bb[1] + bb[3]) / 2 + (me.get("center-offset-y") or 0)); return me; }, # Set transformation center (currently only used for rotation) setCenter: func() { var center = _arg2valarray(arg); if (size(center) != 2){ return debug.warn("invalid arg"); } me._setupCenterNodes(center[0], center[1]); return me; }, # Get transformation center getCenter: func() { var center = [0, 0]; me._setupCenterNodes(); if (me._center[0] != nil) { center[0] = me._center[0].getValue() or 0; } if (me._center[1] != nil) { center[1] = me._center[1].getValue() or 0; } return center; }, getSize: func { var bb = me.getTightBoundingBox(); return [bb[2] - bb[0], bb[3] - bb[1]]; }, # convert bounding box vector into clip string (yes, different order) boundingbox2clip: func(bb) { return sprintf("rect(%d,%d,%d,%d)", bb[1], bb[2], bb[3], bb[0]) }, # set clip by bounding box # bounding_box: [xmin, ymin, xmax, ymax] setClipByBoundingBox: func(bounding_box, clip_frame = nil) { if (clip_frame == nil) { clip_frame = Element.PARENT; } me.set("clip", me.boundingbox2clip(bounding_box)); me.set("clip-frame", clip_frame); return me; }, # set clipping by bounding box of another element setClipByElement: func(clip_elem) { clip_elem.update(); var bounds = clip_elem.getTightBoundingBox(); me.setClipByBoundingBox(bounds, canvas.Element.PARENT); }, # Internal Transform for convenience transform functions _getTf: func { if (me["_tf"] == nil) { me["_tf"] = me.createTransform(); } return me._tf; }, _setupCenterNodes: func(cx = nil, cy = nil) { if (me["_center"] == nil) { me["_center"] = [me._node.getNode("center[0]", cx != nil), me._node.getNode("center[1]", cy != nil)]; } if (cx != nil) { me._center[0].setDoubleValue(cx); } if (cy != nil) { me._center[1].setDoubleValue(cy); } }, };