<@doc hierarchy="GMLDOM"> Aspect for drawing zoomable connection pins (c) SAP AG 2003-2006. All rights reserved. #INCLUDE[gml:defs.inc] Aspect ZPin for ZDrawing; constructor(shape) this.id = base.id; this.shapeID = shape.id; this.board = shape.board; this.canvas= this.board.canvas; this.lines = {}; this.canvas.setWidget(this); this.isInout = ((base.@dir & #[SVG_INOUT]) != 0); this.isInward = ((base.@dir & #[SVG_INWARD]) != 0); this.isOutward = ((base.@dir & #[SVG_OUTWARD]) != 0); this.isDynamic = ((base.@symbol & #[SVG_DYNAMIC_PIN]) != 0); this.isAutohide = ((base.@anchor & #[SVG_AUTOHIDE]) != 0); this.isFilled = (!(base.@symbol & (#[SVG_HOLLOW|SVG_FILLED]))) ? this.isOutward : !(base.@symbol & #[SVG_HOLLOW]); // TODO: make inout pin half-hollow, half-filled this.pinColor = base.@strokeColor || shape.base.@strokeColor; this.fillColor = this.isFilled ? this.pinColor : 'white'; this.hilightColor = shape.getDiagram().base.@hilightColor this.paint(); end destructor if (this.isAnimated) SVG.clearElement(this.pinNode); SVG.removeElement(this.pinNode); this.pinNode = null; if (this.pinText) { SVG.removeElement(this.pinText); this.pinText = null; this.pinTextClip = null; } this.canvas.removeWidget(this.id); //TODO: delete this['base']; end virtual method getShape() return this.canvas.getWidget(this.shapeID); end ////////////////////////////////////////////////////////////////////////////////////// // BASE PROPERTIES <@doc type="ENUM" group="Instance Properties">Gets or sets the pin's anchor point The ~anchor property is a bitwise combination of the following groups of flags: Name | Description SVG_LEFT | Anchor to left edge SVG_RIGHT | Anchor to right edge SVG_TOP | Anchor to top edge SVG_BOTTOM | Anchor to bottom edge | SVG_START | Anchor to edge's start point SVG_MIDDLE | Anchor to edge's middle point SVG_END | Anchor to edge's end point | SVG_AUTO | Anchor point is calculated automatically | SVG_AUTOHIDE | The pin is hiden by default, but is displayed when selected When SVG_AUTO flag is specified, the actual anchor point is calculated basing on SVG_START/SVG_MIDDLE/SVG_END flags and the index of this pin among other pins with the same anchor settings. Typicially, pins created earlier will be positioned before pins created later. property anchor = 0; <@doc type="n">Defines the pin's vertical offset from the anchor point // TODO: We'd better create a way to define vertical and horizontal offset, if needed property offset = 0; <@doc type="Object">Defines the pin's direction The ~dir property can be one of the following flags: Name | Description SVG_INOUT | In/out pin SVG_INWARD | Inward pin SVG_OUTWARD | Outward pin readonly property dir = 0; <@doc type="n">Defines the pin's connection radius The connection ~radius is the distance between the exact point where lines connect to the pin and the pin's origin. Use this property to override the default connection radius defined on the pin's symbol, in order to accomodate for the geometry of the containing shape aspect. readonly property radius = 0; <@doc type="RGB">Defines the pin's stroke color If the pin color is not specified, the stroke color of the containing shape will be used. readonly property strokeColor = ''; <@doc> Defines the behavior of the pin text when it becomes larger than approximatelly half of the parent shape. This property is only used when the pin has text defined for it. This property can have one of the following possible values: Name | Description SVG_OVERFLOW_VISIBLE | Entire text is visible (default) SVG_OVERFLOW_FADEOUT | The overflowed part of the text is shown faded out readonly property textOverflow = #[SVG_OVERFLOW_VISIBLE]; <@doc type="@PIN_SYMBOL">Defines the pin's graphical symbol property symbol = 0; <@struct name="PIN_SYMBOL" group="Structures"> A bitwise structure for defining pin symbols A pin symbol can be any bitwise combination of the following groups of flags: Name | Description SVG_CLASSIC_PIN | Classic pin symbol (default) SVG_DIAMOND_PIN | Diamond symbol SVG_CIRCLE_PIN | Circle symbol SVG_SQUARE_PIN | Square symbol SVG_TRIANGLE_PIN | Triangle symbol SVG_CUSTOM_PIN | Custom symbol defined by the @ZShape!pinSymbols property on the containing shape (using the first 8 bits as index) SVG_DYNAMIC_PIN | Pin symbol is calculated dynamically, basing on @dynsymbol property | SVG_HOLLOW | The symbol is hollow, i.e. filled with white color (default for input pins). SVG_FILLED | The symbol is filled with the primary color (default for output pins). | SVG_NOTEXT | The pin text label is hidden SVG_NOSYMBOL | The pin has no symbol SVG_HIDDEN | The pin has no text and no symbol, making it invisible (combines SVG_NOTEXT|SVG_NOSYMBOL) <@doc> Defines the dynamic formula that evaluates to pin symbol. This property is evaluated only if @symbol property has SVG_DYNAMIC_PIN flag set. A dynamic formula is a string containing a valid JavaScript expression that involves one or more GML property references. A GML property reference is written by adding the \@ prefix (e.g., \@pinSymbol or \@Class.metadata.pinSymbol). static readonly property dynsymbol = ''; ////////////////////////////////////////////////////////////////////////////////////// // ASPECT PROPERTIES <@doc scope="private">Gets the pin's Id virtual property id = ''; // Pin colors <@doc type="RGB" scope="private">Gets the pin's color (inerited from the stroke color) virtual property pinColor = ''; <@doc type="RGB" scope="private">Gets the pin's fill color (derived from the pin color and symbol type) virtual property fillColor = ''; <@doc type="RGB" scope="private">Gets the pin's hilight color (inherited from the diagram hilight color) virtual property hilightColor = ''; // Associated objects <@doc type="bool[id]" scope="private">Gets the collection of lines connected to this pin virtual property lines = null; <@doc type="@ZShape!" scope="private">Gets the owner shape object virtual property shape = null; // Status Flags <@doc type="b" scope="private">Indicates that this graphic is a connection pin (for quick tests) virtual property isPin = true; <@doc scope="private">Indicates whether the pin is animated virtual property isAnimated = false; <@doc scope="private">Indicates whether the pin is filled (otherwise, hollow) virtual property isFilled = false; <@doc type="b" scope="private">Indicates that the pin is hidden by default, and shown when selected virtual property isAutohide = false; <@doc type="b" scope="private">Indicates that the pin is facing inward and outward virtual property isInout = false; <@doc type="b" scope="private">Indicates that the pin is facing inward virtual property isInward = false; <@doc type="b" scope="private">Indicates that the pin is facing outward virtual property isOutward = false; <@doc scope="private">Indicates whether the pin is currently selected virtual property isSelected = false; <@doc type="b" scope="private">Indicates that this pin is candidate for wiring virtual property isWireTarget = false; <@doc scope="private">Indicates whether the pin symbol is dynamic virtual property isDynamic = false; // SVG painting objects <@doc type="SVGNode" scope="private">Gets the pin's symbol svg node virtual property pinNode = null; <@doc type="SVGNode" scope="private">Gets the pin's text svg node virtual property pinText = null; <@doc type="SVGNode" scope="private">Gets the pin's text clipping svg node virtual property pinTextClip = null; // Geometry properties <@doc scope="private">Gets the pin's effective radius (as defined on the symbol or overridden by the base object) virtual property rad = 0; <@doc scope="private">Gets the pin's rotation angle (in multiples of 90 degrees counterclockwise) The pin's rotation angle is defined as the rotation angle of the imaginary line that emanates from the pin's connection point outward, and is perpendicular to the side of the shape on which the pin is placed (after accounting for the rotation angle and flip state of the containing shape). The resulting value of this property is: 0=right(0 degrees), 1=top(90 degrees), 2=left(180 degrees), 3=bottom(270 degrees) virtual property rot = 0; <@doc scope="private">Gets the x-coordinate of the pin's connection point The pin's connection point is the precise point to which the pin's lines should be connected. The coordinate of the connection point is relative to the containing shape's center point. virtual property x = 0; <@doc scope="private">Gets the y-coordinate of the pin's connection point The pin's connection point is the precise point to which the pin's lines should be connected. The coordinate of the connection point is relative to the containing shape's center point. virtual property y = 0; ////////////////////////////////////////////////////////////////////////////////////// // MODEL EVENTS override virtual method onModelUpdate(evt) this.repaint(evt.name); //TODO: repaint also: strokeColor, symbol end override virtual method onModelInsert(evt) // nothing to do (pin has no child graphics) end override virtual method onModelRemove(evt) // nothing to do (pin has no child graphics) end ////////////////////////////////////////////////////////////////////////////////////// // PAINTING METHODS <@doc scope="private"> Paints the pin virtual method paint() this.repaint(); end <@doc scope="private"> Repaints the pin after a property has changed virtual method repaint(prop) var shape = this.getShape(); if (!prop || prop == '@symbol') this.updateSymbol(); if (!prop || prop == 'name') { if (this.pinText) SVG.setText(this.pinText, base.name); } if (!prop || prop == '@anchor' || prop == '@offset' || prop == '@symbol') { var edge = base.@anchor & ~(#[SVG_AUTOHIDE|SVG_AUTO]); var offset = base.@offset, count = 0, total = 0, sa=0; if (base.@anchor & #[SVG_AUTO]) { // count all pins with same anchor, save index of this pin in the counting var shapeBase = shape.base, pins = shapeBase[shapeBase.@pinsKey], found = false; for (var pid in pins) { if (!found && (pid == this.id)) found = true; if (base.@anchor == pins[pid].@anchor) { total++; if (!found) count++; } } total--; // make total zero based } var aoffset = 0, doff = (edge & (#[SVG_TOP|SVG_BOTTOM])) ? 30 : 10; // distance between same-anchor pins switch (edge & 0xF0) { case #[SVG_START]: sa=-1; aoffset += count*doff; break; case #[SVG_MIDDLE]: sa=0; aoffset += (count - total/2)*doff; break; case #[SVG_END]: sa=+1; aoffset += -(count*doff); break; } var px=0, py=0, pa=0, sx=0, sy=0, rot=0, dw=shape.w/2, dh=shape.h/2; switch (edge & 0x0F) { case #[SVG_LEFT]: rot=0; pa=0; px=-dw; py=sa*dh+aoffset+offset; sx=-1; break; case #[SVG_RIGHT]: rot=2; pa=180; px=+dw; py=sa*dh+aoffset+offset; sx=+1; break; case #[SVG_TOP]: rot=3; pa=90; px=sa*dw+aoffset; py=-dh+offset; sy=-1; break; case #[SVG_BOTTOM]: rot=1; pa=270; px=sa*dw+aoffset; py=+dh+offset; sy=+1; break; case 0: rot=0; pa=270; sy=+1; break; } this.rot = Math.round(rot + (2-shape.rot)) % 4; if (this.isOutward) pa=180-pa; if (this.pinNode) { this.pinNode.setAttribute('transform', 'translate('+px+' '+py+')'+(pa ? ' rotate('+pa+') ' : '')); } if (this.pinText) { var tx = (edge & (#[SVG_TOP|SVG_BOTTOM])) ? px : px-(sx*6||+3); var ty = (edge & (#[SVG_TOP|SVG_BOTTOM])) ? py-(sy*12) : py-(sy*6||-3); this.pinText.setAttribute('transform', 'translate('+tx+' '+ty+')'); this.pinText.setAttribute('text-anchor', (edge & #[SVG_RIGHT]) ? 'end' : (edge & #[SVG_LEFT]) ? 'start' : 'middle'); if (this.pinTextClip) { // text clipping values - used for fadeout text before it reaches the icon in the center of the shape // TODO: Fix clipping for top/bottom plugs because they now render text horizontally (without the rotation) // TODO: Find why cx/cy of +16/-16 doesn't end at the center, and -32/+21 are necessary // TODO: The heuristics surronding the icon (ABS..etc.) is not generic (only look good if there's an icon in the middle). Think if this is OK var cx=0, cy=0, cstart=0, cend=0; switch (edge & 0x0F) { case #[SVG_LEFT]: cx=dw-32+((ABS(py)>16)?14:0); cy=0; cstart=0; cend=10; break; case #[SVG_RIGHT]: cx=-(dw-21+((ABS(py)>16)?14:0)); cy=0; cstart=10; cend=0; break; case #[SVG_TOP]: cx=0; cy=dh-32+((ABS(py)>16)?14:0); cstart=0; cend=10; break; case #[SVG_BOTTOM]: cx=0; cy=-(dh-21+((ABS(py)>16)?14:0)); cstart=10; cend=0; break; } this.pinTextClip.setAttribute('x1', cstart); this.pinTextClip.setAttribute('x2', cend); this.pinTextClip.setAttribute('gradientTransform', 'translate('+cx+' '+cy+')'); } } px+=sx*this.rad, py+=sy*this.rad; switch (shape.rot) { case 0: this.x=+px; this.y=+py; break; case 1: this.x=-py; this.y=+px; break; case 2: this.x=-px; this.y=-py; break; case 3: this.x=+py; this.y=-px; break; } if (this.rot < 0) this.rot += 4; // Rerouting lines var lines = this.lines, canvas = this.canvas; if (!lines || ISEMPTY(lines)) return; for (var m in lines) { var line = canvas.getWidget(m); if (line) line.reroute(); } } end ////////////////////////////////////////////////////////////////////////////////////// // INTERACTIVE EFFECTS <@doc scope="private"> Shows indication that the mouse is over the pin virtual method showHoverEffect() if (!this.pinNode || this.marked) return; var shape = this.getShape(), diag=shape.getDiagram(); var color = (this.isSelected && !shape.isSelected ? diag.base.@hilightText : this.hilightColor); SVG.setProperty(this.pinNode, 'color', color); end <@doc scope="private"> Hides indication that the mouse is over the pin virtual method hideHoverEffect() if (!this.pinNode || this.marked) return; var shape=this.getShape(), diag=shape.getDiagram(); var color = (this.isSelected && !shape.isSelected ? this.hilightColor : shape.isSelected ? diag.base.@hilightText : base.@strokeColor); SVG.setProperty(this.pinNode, 'color', this.isFilled ? color : 'white'); end <@doc scope="private"> Shows indication that the pin is selected virtual method showSelectionEffect(showAutohidden) if (this.marked) return; var shape = this.getShape(), diag=shape.getDiagram(); this.isSelected = true; if (showAutohidden && this.isAutohide) SVG.visible(this.pinNode, true); var color = shape.isSelected ? diag.base.@hilightText : this.hilightColor; SVG.setProperty(this.pinNode, 'stroke', color); SVG.setProperty(this.pinNode, 'color', this.isFilled ? color : 'white'); var color = shape.isSelected ? diag.base.@hilightText : base.@strokeColor; SVG.setProperty(this.pinTextClip, 'color', color); SVG.setProperty(this.pinText, 'color', color); end <@doc scope="private"> Hides the pin selection indication virtual method hideSelectionEffect(hideAutohidden) if (this.marked) return; var shape=this.getShape(), diag=shape.getDiagram(); this.isSelected = false; if (hideAutohidden && this.isAutohide) SVG.visible(this.pinNode, false); var color = base.@strokeColor; SVG.setProperty(this.pinNode, 'stroke', color); SVG.setProperty(this.pinNode, 'color', this.isFilled ? color : 'white'); SVG.setProperty(this.pinTextClip, 'color', color); SVG.setProperty(this.pinText, 'color', color); end <@doc scope="private"> Shows indication that the pin is in focus virtual method showFocusEffect() if (this.isAutohide) SVG.visible(this.pinNode, true); end <@doc scope="private"> Hides the pin focus indication virtual method hideFocusEffect() if (this.isAutohide) SVG.visible(this.pinNode, false); end <@doc scope="private"> Shows indication that the pin is a valid target for wiring operation virtual method showWiringEffect(animate) if (!this.pinNode) return; this.isWireTarget = true; if (this.isAutohide) SVG.visible(this.pinNode, true); this.showHoverEffect(); if (this.isAnimated) { SVG.clearElement(this.pinNode); this.isAnimated = false; } if (animate) { SVG.createFragment(this.pinNode, ''); this.isAnimated = true; } end <@doc scope="private"> Hides the pin's wiring indication virtual method hideWiringEffect() if (!this.pinNode) return; this.isWireTarget = false; if (this.isAutohide) SVG.visible(this.pinNode, false); this.hideHoverEffect(); if (this.isAnimated) { SVG.clearElement(this.pinNode); this.isAnimated = false; } end ////////////////////////////////////////////////////////////////////////////////////// // GEOMETRIC CALCULATIONS <@doc scope="private"> Gets the absolute position of the pin's connection point (relative to the canvas) virtual method getCP() var s=this.getShape(); return { x: s.ox+(s.cx+this.x)*s.os, y: s.oy+(s.cy+this.y)*s.os, rot: this.rot, scale: s.os, shapeID: s.id }; end <@doc scope="private"> Gets the position of the pin's connection point relative to the given line's parent coordinates system virtual method getLineCP(line, otherPin) var s=this.getShape(), p=line.getParent(), newRot=this.rot; var edge = base.@anchor & ~(#[SVG_AUTOHIDE|SVG_AUTO]); var sx = 0; if (edge == #[SVG_RIGHT|SVG_MIDDLE]) { if (line.srcpinID == this.id) newRot = 0; else if (line.trgpinID == this.id) { newRot = 2; sx = -2; } } return { x: s.ox+(s.cx+this.x)*s.os-p.qx + sx*this.rad, y: s.oy+(s.cy+this.y)*s.os-p.qy, rot: newRot, scale: s.os/p.qs, shapeID: s.id }; end <@doc scope="private"> Gets the pin's tooltip positioning data virtual method getTooltipPos() var side=0; switch (base.@anchor & 0x0F) { case #[SVG_TOP]: side=0; break; case #[SVG_RIGHT]: side=1; break; case #[SVG_BOTTOM]: side=2; break; case #[SVG_LEFT]: side=3; break; } var data=this.getCP(); switch ((side+this.getShape().rot)%4) { case 0: data.dy = -1; break; // top case 1: data.x -= 8; data.y += 4; data.dx = -1; break; // right case 2: data.y -= 5; data.dy = -1; break; // bottom case 3: data.x += 8; data.y += 4; data.dx = 1; break; // left } data.color = this.pinColor; return data; end <@doc scope="private"> Tests whether this pin is connected to a given other pin virtual method isConnectedTo(other) var canvas = this.canvas, lines = this.lines; for (var k in lines) { var ln = canvas.getWidget(k); if (!ln) continue; if (ln.srcpinID == this.id && other && ln.trgpinID == other.id) return true; if (other && ln.srcpinID == other.id && ln.trgpinID == this.id) return true; } return false; end ////////////////////////////////////////////////////////////////////////////////////// // EVENT HANDLERS virtual method setupPointer(evt) var shape=this.getShape(), diag=shape.getDiagram(); if (evt.detail>1) { RULE('drillIntoShape', diag.base, shape.base); } else if (diag.isEditable) { if (RULE('canConnectFrom', diag.base, diag.boardAspect, base)) { return new SvgPointer('wiringHandler', evt, this.id, this.canvas); } } return null; end virtual method mouseover(evt, ptr) var shape=this.getShape(), diag=shape.getDiagram(); if (!diag.isEditable) return; if (ptr) { if (ptr.method == 'wiringHandler' && this.isWireTarget) { ptr.currpinID = this.id; diag.showTooltip(this); } if (ptr.method == 'moveHandler') { shape.mouseover(evt, ptr); } return; } diag.showTooltip(this); if (!diag.hilightMode) return; if (!RULE('canConnectFrom', diag.base, diag.boardAspect, base)) return; this.showHoverEffect(); end virtual method mouseout(evt, ptr) var shape=this.getShape(), diag=shape.getDiagram(); if (!diag.isEditable) return; if (ptr) { if (ptr.method == 'wiringHandler' && this.isWireTarget) { ptr.currpinID = ''; diag.hideTooltip(); } if (ptr.method == 'moveHandler') { shape.mouseout(evt, ptr); } return; } diag.hideTooltip(); this.hideHoverEffect(); end virtual method wiringHandler(ptr) var canvas = this.canvas; var shape=this.getShape(), diag=shape.getDiagram(), lwidth=2/canvas.scale; switch (ptr.phase) { case #[PTR_START]: diag.selectById(shape.id); diag.activateBackground(true); if (diag.isZoomable) diag.startZoomableAction(); // TODO; BlockZoom work ptr.scrollMode = #[PTR_AUTOSCROLL]; ptr.visualCues = GETVAR('SVG_VISUAL_CUES'); ptr.wireTargetID = ''; ptr.visitedBlocks = {}; ptr.srcpinID = this.id; ptr.trgpinID = ''; ptr.currpinID = ''; var x=shape.ox+(shape.cx+this.x)*shape.os; var y=shape.oy+(shape.cy+this.y)*shape.os; ptr.wire = SVG.createElement(diag.wiresLayer, 'line', { x1:x, y1:y, x2:x, y2:y, fill:'none', 'stroke':this.hilightColor, 'stroke-width':lwidth, 'stroke-dasharray':lwidth+' '+lwidth, 'pointer-events':'none' }); if (this.id != ptr.srcpinID) this.showWiringEffect(ptr.visualCues); if (diag.rubberwireObj) { SVG.removeElement(diag.rubberwireObj); diag.rubberwireObj = null; } diag.hideTooltip(); // Hides the toolTip when a line created (phase 1) break; case #[PTR_MOVE]: if (ptr.currpinID !== ptr.trgpinID) { if (!ptr.currpinID) { ptr.trgpinID = ''; ptr.wire.setAttribute('stroke-dasharray', lwidth+' '+lwidth); } else { ptr.trgpinID = ptr.currpinID; //TODO: route the wire according to candidate link type var P2=canvas.getWidget(ptr.trgpinID), S2=P2.getShape(); ptr.wire.setAttribute('x2', S2.ox+(S2.cx+P2.x)*S2.os); ptr.wire.setAttribute('y2', S2.oy+(S2.cy+P2.y)*S2.os); ptr.wire.setAttribute('stroke-dasharray', 'none'); } } if (!ptr.trgpinID) { ptr.wire.setAttribute('x2', ptr.pos.x); ptr.wire.setAttribute('y2', ptr.pos.y); } break; case #[PTR_FINISH]: diag.activateBackground(false); var wireTarget = canvas.getWidget(ptr.wireTargetID); if (wireTarget) wireTarget.hideWiringEffect(ptr); this.hideWiringEffect(); var shapeBase = shape.base, pins = shapeBase[shapeBase.@pinsKey]; for (var k in pins) { var pin = canvas.getWidget(pins[k].id); if (pin) pin.showSelectionEffect(true); } if (!ptr.moved || ptr.srcpinID == ptr.trgpinID) { SVG.removeElement(ptr.wire); if (diag.isZoomable) diag.finishZoomableAction(); break; } // in case of dangling connection, open quick-connect menu (if defined) // TODO: why calculating block if ptr.wireTarget seems to be the block we're looking for? var pos = ptr.pos; if (!ptr.trgpinID) { var block = diag.findBlockAt(pos) || diag.getRoot(); var relpos = {x:pos.x-block.qx, y:pos.y-block.qy}; var menu = RULE('defineDanglingMenu', diag.base, diag.boardAspect, base, relpos ,(block && block.base || null)); if (menu) { diag.rubberwireObj = ptr.wire; diag.zoomTargetID = ptr.wireTargetID; // TODO: BlockZoom work diag.openMenu(menu, pos, menu.callback); } else { SVG.removeElement(ptr.wire); if (diag.isZoomable) diag.finishZoomableAction(); } break; } // otherwise, open the connect menu (if defined). Figure direction first. var ptrTrgpin = canvas.getWidget(ptr.trgpinID); var srcpin = this.isInward ? ptrTrgpin : this; var trgpin = this.isOutward ? ptrTrgpin : this; if (this.isInout) { if (ptrTrgpin.isInward) trgpin = ptrTrgpin; else srcpin = ptrTrgpin; } var srcplug=srcpin.base, trgplug=trgpin.base; var menu = RULE('defineConnectMenu', diag.base, diag.boardAspect, srcplug, trgplug, pos); if (menu) { diag.rubberwireObj = ptr.wire; diag.zoomTargetID = ptr.wireTargetID; // TODO: BlockZoom work diag.openMenu(menu, pos, menu.callback); break; } // otherwise, create new link based on candidate link type(s) var linktypes = RULE('defineConnectionTypes', diag.base, diag.boardAspect, srcplug, trgplug); // no valid link type if (!linktypes || linktypes.length==0) { if (diag.isZoomable) diag.finishZoomableAction(); // TODO: BlockZoom work SVG.removeElement(ptr.wire); break; } // exactly one valid link type, so create it immediately if (linktypes.length==1) { diag.rubberwireObj = ptr.wire; var linkclass = CLASS(linktypes[0]); if (linkclass) createLink(linkclass.fullname); if (diag.isZoomable) diag.finishZoomableAction(wireTarget); // TODO: BlockZoom work break; } // more than one valid link type, so open a selection menu var menu = $ENV.defineMenubar(); diag.rubberwireObj = ptr.wire; diag.zoomTargetID = ptr.wireTargetID; for (var i=0, len=linktypes.length; i' ); this.pinNode.peerID = this.id; } } // delete old text, if any if (this.pinText) { SVG.removeElement(this.pinText); this.pinText = null; this.pinTextClip = null; } // create new text, if defined if (!(base.@symbol & #[SVG_NOTEXT])) { this.pinText = SVG.createElement(shape.pinsLabels, 'text', {'class':'pinText', fill: 'currentColor'}); if ((base.@textOverflow == #[SVG_OVERFLOW_FADEOUT]) && shape.getDiagram().handleTextOverflow) { var id = 'gradient' + this.id; this.pinTextClip = SVG.createFragment(this.pinText, ''); this.pinText.setAttribute('fill', 'url(#' + id + ')'); } SVG.setText(this.pinText, base.name); } end